File indexing completed on 2024-04-21 03:40:38

0001 /*************************************************************************************
0002  *  Copyright (C) 2016 Aleix Pol Gonzalez <aleixpol@kde.org>                         *
0003  *                                                                                   *
0004  *  This program is free software; you can redistribute it and/or                    *
0005  *  modify it under the terms of the GNU General Public License                      *
0006  *  as published by the Free Software Foundation; either version 2                   *
0007  *  of the License, or (at your option) any later version.                           *
0008  *                                                                                   *
0009  *  This program is distributed in the hope that it will be useful,                  *
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of                   *
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                    *
0012  *  GNU General Public License for more details.                                     *
0013  *                                                                                   *
0014  *  You should have received a copy of the GNU General Public License                *
0015  *  along with this program; if not, write to the Free Software                      *
0016  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA   *
0017  *************************************************************************************/
0018 
0019 #include "export3d.h"
0020 
0021 #include <QFile>
0022 #include <QDebug>
0023 #include <QVector3D>
0024 #include <cmath>
0025 
0026 #include "surface.h"
0027 #include "plotitem.h"
0028 #include "plotsmodel.h"
0029 
0030 using namespace Analitza;
0031 
0032 template <typename T>
0033 static QByteArray fromNumbers(const QVector<T>& input)
0034 {
0035     QByteArray ret;
0036     foreach(qreal r, input) {
0037         ret += QByteArray::number(r)+' ';
0038     }
0039     ret.chop(1);
0040     return ret;
0041 }
0042 
0043 static QByteArray fromVector3D(const QVector3D &r)
0044 {
0045     return QByteArray::number(r.x())+' '
0046          + QByteArray::number(r.y())+' '
0047          + QByteArray::number(r.z());
0048 }
0049 
0050 static QByteArray fromNumbers(const QVector<QVector3D>& input)
0051 {
0052     QByteArray ret;
0053     foreach(const QVector3D &r, input) {
0054         ret += fromVector3D(r);
0055     }
0056     ret.chop(1);
0057     return ret;
0058 }
0059 
0060 static QVector<int> makeTriangles(const QVector<uint>& input)
0061 {
0062     QVector<int> ret;
0063     int i = 0;
0064     foreach(uint val, input) {
0065         ret += val;
0066         if(i==2) {
0067             ret += -1;
0068             i = 0;
0069         } else
0070             ++i;
0071     }
0072     ret += -1;
0073     return ret;
0074 }
0075 
0076 void Export3D::exportX3D(const QString& path, QAbstractItemModel* model)
0077 {
0078     QFile f(path);
0079     if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
0080         qWarning() << "couldn't open" << path;
0081         return;
0082     }
0083 
0084     f.write(QByteArrayLiteral("<?xml version='1.0' encoding='UTF-8'?>\n"
0085     "<!DOCTYPE X3D PUBLIC 'ISO//Web3D//DTD X3D 3.2//EN' 'http://www.web3d.org/specifications/x3d-3.2.dtd'>\n"
0086     "<X3D profile='Interchange' version='3.2' xmlns:xsd='http://www.w3.org/2001/XMLSchema-instance' "
0087         "xsd:noNamespaceSchemaLocation='http://www.web3d.org/specifications/x3d-3.2.xsd'>\n"
0088         "<Scene>\n"));
0089     for (int i = 0; i < model->rowCount(); ++i)
0090     {
0091         const QModelIndex pi = model->index(i, 0);
0092 
0093         if (!pi.isValid())
0094             continue;
0095 
0096         PlotItem* item = pi.data(PlotsModel::PlotRole).value<PlotItem*>();
0097 
0098         Surface *surf = dynamic_cast<Surface*>(item);
0099         if (!surf || !surf->isVisible())
0100             continue;
0101 
0102         f.write(QByteArrayLiteral(
0103             "<Shape>\n"
0104                 "<Appearance><Material diffuseColor='1 0 0' specularColor='0.8 0.7 0.5'/></Appearance>\n"
0105                 "<IndexedFaceSet solid='false' normalPerVertex='false' coordIndex='"));
0106         f.write(fromNumbers(makeTriangles(surf->indexes())));
0107         f.write(QByteArrayLiteral("'>\n"
0108                     "<Coordinate point='"));
0109         f.write(fromNumbers(surf->vertices()));
0110         f.write(QByteArrayLiteral("'/>\n"
0111         "<Normal vector='"));
0112         f.write(fromNumbers(surf->normals()));
0113         f.write(QByteArrayLiteral(
0114                 "'/>\n"
0115                 "</IndexedFaceSet>\n"
0116             "</Shape>\n"));
0117     }
0118     f.write(QByteArrayLiteral(
0119         "</Scene>\n"
0120     "</X3D>\n"));
0121 }
0122 
0123 void Export3D::exportSTL(const QString& path, QAbstractItemModel* model)
0124 {
0125     QFile f(path);
0126     if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
0127         qWarning() << "couldn't open" << path;
0128         return;
0129     }
0130 
0131     f.write(QByteArrayLiteral("solid myplot\n"));
0132     for (int i = 0; i < model->rowCount(); ++i)
0133     {
0134         const QModelIndex pi = model->index(i, 0);
0135 
0136         if (!pi.isValid())
0137             continue;
0138 
0139         PlotItem* item = pi.data(PlotsModel::PlotRole).value<PlotItem*>();
0140 
0141         Surface *surf = dynamic_cast<Surface*>(item);
0142         if (!surf || !surf->isVisible())
0143             continue;
0144 
0145         const auto vertices = surf->vertices();
0146         const auto indexes = surf->indexes();
0147 
0148         for (int i = 0, c = indexes.count()/3; i<c; ++i) {
0149 //             f.write("  facet normal " + fromVector3D(normals[i]) + '\n');
0150             const QVector3D v1 = vertices[indexes[i*3 + 0]]
0151                           , v2 = vertices[indexes[i*3 + 1]]
0152                           , v3 = vertices[indexes[i*3 + 2]];
0153 
0154             //TODO: should be using the normals from Surface
0155             f.write("  facet normal " + fromVector3D(QVector3D::normal(v1, v2, v3)) + '\n');
0156             f.write("     outer loop\n");
0157             f.write("       vertex " + fromVector3D(v1) + '\n');
0158             f.write("       vertex " + fromVector3D(v2) + '\n');
0159             f.write("       vertex " + fromVector3D(v3) + '\n');
0160             f.write("     endloop\n");
0161             f.write("  endfacet\n");
0162         }
0163         f.write("\n");
0164     }
0165     f.write("endsolid myplot\n");
0166 }