summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dxfdata.cc1
-rw-r--r--export.cc101
-rw-r--r--import.cc1
-rw-r--r--lexer.l1
-rw-r--r--mainwin.cc87
-rw-r--r--openscad.cc184
-rw-r--r--openscad.h8
-rw-r--r--openscad.pro2
-rw-r--r--surface.cc1
9 files changed, 304 insertions, 82 deletions
diff --git a/dxfdata.cc b/dxfdata.cc
index 14c9c0e..b08369e 100644
--- a/dxfdata.cc
+++ b/dxfdata.cc
@@ -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
+
diff --git a/import.cc b/import.cc
index 3ec7056..3d8b8dc 100644
--- a/import.cc
+++ b/import.cc
@@ -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());
diff --git a/lexer.l b/lexer.l
index 7c5f5e7..b0975fb 100644
--- a/lexer.l
+++ b/lexer.l
@@ -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);
diff --git a/mainwin.cc b/mainwin.cc
index 98e82f7..6dba9c8 100644
--- a/mainwin.cc
+++ b/mainwin.cc
@@ -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();
diff --git a/openscad.h b/openscad.h
index 0f565c9..5345e7c 100644
--- a/openscad.h
+++ b/openscad.h
@@ -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
diff --git a/surface.cc b/surface.cc
index 5083c74..e8e59e1 100644
--- a/surface.cc
+++ b/surface.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)) {
contact: Jan Huwald // Impressum