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 }