diff options
author | clifford <clifford@b57f626f-c46c-0410-a088-ec61d464b74c> | 2009-10-18 08:50:01 (GMT) |
---|---|---|
committer | clifford <clifford@b57f626f-c46c-0410-a088-ec61d464b74c> | 2009-10-18 08:50:01 (GMT) |
commit | 0b61257ca8367f2b0957982b16c333bc3bbbe1ba (patch) | |
tree | a2992f4961de546f217a75cd290e6ffe08c9d629 | |
parent | a6b4efc78fed90714ed41cc4a589c67ae995693a (diff) |
Clifford Wolf:
Added command line mode (stl export only)
git-svn-id: http://svn.clifford.at/openscad/trunk@106 b57f626f-c46c-0410-a088-ec61d464b74c
-rw-r--r-- | dxfdata.cc | 1 | ||||
-rw-r--r-- | export.cc | 101 | ||||
-rw-r--r-- | import.cc | 1 | ||||
-rw-r--r-- | lexer.l | 1 | ||||
-rw-r--r-- | mainwin.cc | 87 | ||||
-rw-r--r-- | openscad.cc | 184 | ||||
-rw-r--r-- | openscad.h | 8 | ||||
-rw-r--r-- | openscad.pro | 2 | ||||
-rw-r--r-- | surface.cc | 1 |
9 files changed, 304 insertions, 82 deletions
@@ -24,6 +24,7 @@ DxfData::DxfData(double fn, double fs, double fa, QString filename, QString layername, double xorigin, double yorigin, double scale) { + handle_dep(filename); QFile f(filename); if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) { diff --git a/export.cc b/export.cc new file mode 100644 index 0000000..017c8e3 --- /dev/null +++ b/export.cc @@ -0,0 +1,101 @@ +/* + * OpenSCAD (www.openscad.at) + * Copyright (C) 2009 Clifford Wolf <clifford@clifford.at> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define INCLUDE_ABSTRACT_NODE_DETAILS + +#include "openscad.h" + +#include <QApplication> + +#ifdef ENABLE_CGAL + +void export_stl(CGAL_Nef_polyhedron *root_N, QString filename, QProgressDialog *pd) +{ + CGAL_Polyhedron P; + root_N->convert_to_Polyhedron(P); + + typedef CGAL_Polyhedron::Vertex Vertex; + typedef CGAL_Polyhedron::Vertex_const_iterator VCI; + typedef CGAL_Polyhedron::Facet_const_iterator FCI; + typedef CGAL_Polyhedron::Halfedge_around_facet_const_circulator HFCC; + + FILE *f = fopen(filename.toAscii().data(), "w"); + if (!f) { + PRINT("Can't open STL file for STL export."); + current_win = NULL; + return; + } + fprintf(f, "solid\n"); + + int facet_count = 0; + for (FCI fi = P.facets_begin(); fi != P.facets_end(); ++fi) { + HFCC hc = fi->facet_begin(); + HFCC hc_end = hc; + Vertex v1, v2, v3; + v1 = *VCI((hc++)->vertex()); + v3 = *VCI((hc++)->vertex()); + do { + v2 = v3; + v3 = *VCI((hc++)->vertex()); + double x1 = CGAL::to_double(v1.point().x()); + double y1 = CGAL::to_double(v1.point().y()); + double z1 = CGAL::to_double(v1.point().z()); + double x2 = CGAL::to_double(v2.point().x()); + double y2 = CGAL::to_double(v2.point().y()); + double z2 = CGAL::to_double(v2.point().z()); + double x3 = CGAL::to_double(v3.point().x()); + double y3 = CGAL::to_double(v3.point().y()); + double z3 = CGAL::to_double(v3.point().z()); + QString vs1, vs2, vs3; + vs1.sprintf("%f %f %f", x1, y1, z1); + vs2.sprintf("%f %f %f", x2, y2, z2); + vs3.sprintf("%f %f %f", x3, y3, z3); + if (vs1 != vs2 && vs1 != vs3 && vs2 != vs3) { + + double nx = (y1-y2)*(z1-z3) - (z1-z2)*(y1-y3); + double ny = (z1-z2)*(x1-x3) - (x1-x2)*(z1-z3); + double nz = (x1-x2)*(y1-y3) - (y1-y2)*(x1-x3); + double n_scale = 1 / sqrt(nx*nx + ny*ny + nz*nz); + fprintf(f, " facet normal %f %f %f\n", + nx * n_scale, ny * n_scale, nz * n_scale); + fprintf(f, " outer loop\n"); + fprintf(f, " vertex %s\n", vs1.toAscii().data()); + fprintf(f, " vertex %s\n", vs2.toAscii().data()); + fprintf(f, " vertex %s\n", vs3.toAscii().data()); + fprintf(f, " endloop\n"); + fprintf(f, " endfacet\n"); + } + } while (hc != hc_end); + if (pd) { + pd->setValue(facet_count++); + QApplication::processEvents(); + } + } + + fprintf(f, "endsolid\n"); + fclose(f); +} + +void export_off(CGAL_Nef_polyhedron *root_N, QString filename, QProgressDialog *pd) +{ +} + +#endif + @@ -77,6 +77,7 @@ PolySet *ImportNode::render_polyset(render_mode_e) const if (type == TYPE_STL) { + handle_dep(filename); QFile f(filename); if (!f.open(QIODevice::ReadOnly)) { PRINTF("WARNING: Can't open import file `%s'.", filename.toAscii().data()); @@ -60,6 +60,7 @@ extern const char *parser_input_buffer; "<"[^ \t\n>]+">" { char *filename = strdup(yytext+1); filename[strlen(filename)-1] = 0; + handle_dep(filename); yyin = fopen(filename, "r"); if (!yyin) { PRINTF("WARNING: Can't open input file `%s'.", filename); @@ -787,7 +787,7 @@ void MainWindow::actionDisplayCSGProducts() current_win = NULL; } -void MainWindow::actionExportSTL() +void MainWindow::actionExportSTLorOFF(bool stl_mode) { current_win = this; @@ -804,94 +804,43 @@ void MainWindow::actionExportSTL() return; } - QString stl_filename = QFileDialog::getSaveFileName(this, "Export STL File", "", "STL Files (*.stl)"); + QString stl_filename = QFileDialog::getSaveFileName(this, + stl_mode ? "Export STL File" : "Export OFF File", "", + stl_mode ? "STL Files (*.stl)" : "OFF Files (*.off)"); if (stl_filename.isEmpty()) { - PRINT("No filename specified. STL export aborted."); + PRINTF("No filename specified. %s export aborted.", stl_mode ? "STL" : "OFF"); current_win = NULL; return; } - CGAL_Polyhedron P; - root_N->convert_to_Polyhedron(P); - - typedef CGAL_Polyhedron::Vertex Vertex; - typedef CGAL_Polyhedron::Vertex_const_iterator VCI; - typedef CGAL_Polyhedron::Facet_const_iterator FCI; - typedef CGAL_Polyhedron::Halfedge_around_facet_const_circulator HFCC; - - FILE *f = fopen(stl_filename.toAscii().data(), "w"); - if (!f) { - PRINT("Can't open STL file for STL export."); - current_win = NULL; - return; - } - fprintf(f, "solid\n"); - - QProgressDialog *pd = new QProgressDialog("Exporting object to STL file...", + QProgressDialog *pd = new QProgressDialog( + stl_mode ? "Exporting object to STL file..." : "Exporting object to OFF file...", QString(), 0, root_N->number_of_facets() + 1); pd->setValue(0); pd->setAutoClose(false); pd->show(); QApplication::processEvents(); - int facet_count = 0; - for (FCI fi = P.facets_begin(); fi != P.facets_end(); ++fi) { - HFCC hc = fi->facet_begin(); - HFCC hc_end = hc; - Vertex v1, v2, v3; - v1 = *VCI((hc++)->vertex()); - v3 = *VCI((hc++)->vertex()); - do { - v2 = v3; - v3 = *VCI((hc++)->vertex()); - double x1 = CGAL::to_double(v1.point().x()); - double y1 = CGAL::to_double(v1.point().y()); - double z1 = CGAL::to_double(v1.point().z()); - double x2 = CGAL::to_double(v2.point().x()); - double y2 = CGAL::to_double(v2.point().y()); - double z2 = CGAL::to_double(v2.point().z()); - double x3 = CGAL::to_double(v3.point().x()); - double y3 = CGAL::to_double(v3.point().y()); - double z3 = CGAL::to_double(v3.point().z()); - QString vs1, vs2, vs3; - vs1.sprintf("%f %f %f", x1, y1, z1); - vs2.sprintf("%f %f %f", x2, y2, z2); - vs3.sprintf("%f %f %f", x3, y3, z3); - if (vs1 != vs2 && vs1 != vs3 && vs2 != vs3) { - - double nx = (y1-y2)*(z1-z3) - (z1-z2)*(y1-y3); - double ny = (z1-z2)*(x1-x3) - (x1-x2)*(z1-z3); - double nz = (x1-x2)*(y1-y3) - (y1-y2)*(x1-x3); - double n_scale = 1 / sqrt(nx*nx + ny*ny + nz*nz); - fprintf(f, " facet normal %f %f %f\n", - nx * n_scale, ny * n_scale, nz * n_scale); - fprintf(f, " outer loop\n"); - fprintf(f, " vertex %s\n", vs1.toAscii().data()); - fprintf(f, " vertex %s\n", vs2.toAscii().data()); - fprintf(f, " vertex %s\n", vs3.toAscii().data()); - fprintf(f, " endloop\n"); - fprintf(f, " endfacet\n"); - } - } while (hc != hc_end); - pd->setValue(facet_count++); - QApplication::processEvents(); - } - - fprintf(f, "endsolid\n"); - fclose(f); + if (stl_mode) + export_stl(root_N, stl_filename, pd); + else + export_off(root_N, stl_filename, pd); - PRINT("STL export finished."); + PRINTF("%s export finished.", stl_mode ? "STL" : "OFF"); delete pd; #endif /* ENABLE_CGAL */ current_win = NULL; } +void MainWindow::actionExportSTL() +{ + actionExportSTLorOFF(true); +} + void MainWindow::actionExportOFF() { - current_win = this; - PRINTA("Function %1 is not implemented yet!", QString(__PRETTY_FUNCTION__)); - current_win = NULL; + actionExportSTLorOFF(false); } void MainWindow::viewModeActionsUncheck() diff --git a/openscad.cc b/openscad.cc index 31e5e6f..b3366eb 100644 --- a/openscad.cc +++ b/openscad.cc @@ -23,6 +23,32 @@ #include "openscad.h" #include <QApplication> +#include <QFile> +#include <QDir> +#include <QSet> + +static void help(const char *progname) +{ + fprintf(stderr, "Usage: %s [ -m make_command ] [ filename ]\n", progname); + fprintf(stderr, " %s { -s stl_file | -o off_file } [ -d deps_file ] [ -m make_command ] filename\n", progname); + exit(1); +} + +const char *make_command = NULL; +QSet<QString> dependencies; + +void handle_dep(QString filename) +{ + if (filename.startsWith("/")) + dependencies.insert(filename); + else + dependencies.insert(QDir::currentPath() + QString("/") + filename); + if (!QFile(filename).exists() && make_command) { + char buffer[4096]; + snprintf(buffer, 4096, "%s '%s", make_command, filename.replace("'", "'\\''").toUtf8().data()); + system(buffer); + } +} int main(int argc, char **argv) { @@ -31,21 +57,155 @@ int main(int argc, char **argv) initialize_builtin_functions(); initialize_builtin_modules(); - QApplication a(argc, argv); - MainWindow *m; +#ifdef Q_WS_X11 + // see <http://qt.nokia.com/doc/4.5/qapplication.html#QApplication-2>: + // On X11, the window system is initialized if GUIenabled is true. If GUIenabled + // is false, the application does not connect to the X server. On Windows and + // Macintosh, currently the window system is always initialized, regardless of the + // value of GUIenabled. This may change in future versions of Qt. + bool useGUI = getenv("DISPLAY") != 0; +#else + bool useGUI = true; +#endif + QApplication app(argc, argv, useGUI); - if (argc > 1) - m = new MainWindow(argv[1]); - else - m = new MainWindow(); + const char *filename = NULL; + const char *stl_output_file = NULL; + const char *off_output_file = NULL; + const char *deps_output_file = NULL; + + int opt; + + while ((opt = getopt(argc, argv, "s:o:d:m:")) != -1) + { + switch (opt) + { + case 's': + if (stl_output_file || off_output_file) + help(argv[0]); + stl_output_file = optarg; + break; + case 'o': + if (stl_output_file || off_output_file) + help(argv[0]); + off_output_file = optarg; + break; + case 'd': + if (deps_output_file) + help(argv[0]); + deps_output_file = optarg; + break; + case 'm': + if (make_command) + help(argv[0]); + make_command = optarg; + break; + default: + help(argv[0]); + } + } + + if (optind < argc) + filename = argv[optind++]; + + if (optind != argc) + help(argv[0]); - m->show(); - m->resize(800, 600); - m->s1->setSizes(QList<int>() << 400 << 400); - m->s2->setSizes(QList<int>() << 400 << 200); + if (stl_output_file || off_output_file) + { + if (!filename) + help(argv[0]); - a.connect(m, SIGNAL(destroyed()), &a, SLOT(quit())); - rc = a.exec(); +#ifdef ENABLE_CGAL + Context root_ctx; + root_ctx.functions_p = &builtin_functions; + root_ctx.modules_p = &builtin_modules; + root_ctx.set_variable("$fn", Value(0.0)); + root_ctx.set_variable("$fs", Value(1.0)); + root_ctx.set_variable("$fa", Value(12.0)); + root_ctx.set_variable("$t", Value(0.0)); + + AbstractModule *root_module; + ModuleInstanciation root_inst; + AbstractNode *root_node; + + handle_dep(filename); + FILE *fp = fopen(filename, "rt"); + if (!fp) { + fprintf(stderr, "Can't open input file `%s'!\n", filename); + exit(1); + } else { + QString text; + char buffer[513]; + int rc; + while ((rc = fread(buffer, 1, 512, fp)) > 0) { + buffer[rc] = 0; + text += buffer; + } + fclose(fp); + root_module = parse(text.toAscii().data(), false); + } + + QString original_path = QDir::currentPath(); + QFileInfo fileInfo(filename); + QDir::setCurrent(fileInfo.dir().absolutePath()); + + AbstractNode::idx_counter = 1; + root_node = root_module->evaluate(&root_ctx, &root_inst); + + CGAL_Nef_polyhedron *root_N; + root_N = new CGAL_Nef_polyhedron(root_node->render_cgal_nef_polyhedron()); + + QDir::setCurrent(original_path); + + if (deps_output_file) { + fp = fopen(deps_output_file, "wt"); + if (!fp) { + fprintf(stderr, "Can't open dependencies file `%s' for writing!\n", deps_output_file); + exit(1); + } + fprintf(fp, "%s:", stl_output_file ? stl_output_file : off_output_file); + QSetIterator<QString> i(dependencies); + while (i.hasNext()) + fprintf(fp, " \\\n\t%s", i.next().toUtf8().data()); + fprintf(fp, "\n"); + fclose(fp); + } + + if (stl_output_file) + export_stl(root_N, stl_output_file, NULL); + + if (off_output_file) + export_off(root_N, off_output_file, NULL); + + delete root_node; + delete root_N; +#else + fprintf(stderr, "OpenSCAD has been compiled without CGAL support!\n"); + exit(1); +#endif + } + else if (useGUI) + { + MainWindow *m; + if (filename) + m = new MainWindow(filename); + else + m = new MainWindow(); + + m->show(); + m->resize(800, 600); + m->s1->setSizes(QList<int>() << 400 << 400); + m->s2->setSizes(QList<int>() << 400 << 200); + + app.connect(m, SIGNAL(destroyed()), &app, SLOT(quit())); + rc = app.exec(); + } + else + { + fprintf(stderr, "Requested GUI mode but can't open display!\n"); + exit(1); + } destroy_builtin_functions(); destroy_builtin_modules(); @@ -30,6 +30,7 @@ #include <QCache> #include <QVector> #include <QMainWindow> +#include <QProgressDialog> #include <QSplitter> #include <QTextEdit> #include <QLineEdit> @@ -751,6 +752,7 @@ private slots: void actionDisplayAST(); void actionDisplayCSGTree(); void actionDisplayCSGProducts(); + void actionExportSTLorOFF(bool stl_mode); void actionExportSTL(); void actionExportOFF(); @@ -800,6 +802,12 @@ extern int get_fragments_from_r(double r, double fn, double fs, double fa); extern QPointer<MainWindow> current_win; +#ifdef ENABLE_CGAL +void export_stl(CGAL_Nef_polyhedron *root_N, QString filename, QProgressDialog *pd); +void export_off(CGAL_Nef_polyhedron *root_N, QString filename, QProgressDialog *pd); +#endif +extern void handle_dep(QString filename); + #define PRINT(_msg) do { if (current_win.isNull()) fprintf(stderr, "%s\n", QString(_msg).toAscii().data()); else current_win->console->append(_msg); } while (0) #define PRINTF(_fmt, ...) do { QString _m; _m.sprintf(_fmt, ##__VA_ARGS__); PRINT(_m); } while (0) #define PRINTA(_fmt, ...) do { QString _m = QString(_fmt).arg(__VA_ARGS__); PRINT(_m); } while (0) diff --git a/openscad.pro b/openscad.pro index 63a5450..6ccbbfc 100644 --- a/openscad.pro +++ b/openscad.pro @@ -15,7 +15,7 @@ LEXSOURCES += lexer.l YACCSOURCES += parser.y HEADERS += openscad.h -SOURCES += openscad.cc mainwin.cc glview.cc +SOURCES += openscad.cc mainwin.cc glview.cc export.cc SOURCES += value.cc expr.cc func.cc module.cc context.cc SOURCES += csgterm.cc polyset.cc csgops.cc transform.cc SOURCES += primitives.cc surface.cc control.cc render.cc @@ -76,6 +76,7 @@ void register_builtin_surface() PolySet *SurfaceNode::render_polyset(render_mode_e) const { + handle_dep(filename); QFile f(filename); if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) { |