Clifford Wolf:

Added command line mode (stl export only)



git-svn-id: http://svn.clifford.at/openscad/trunk@106 b57f626f-c46c-0410-a088-ec61d464b74c
stl_dim
clifford 2009-10-18 08:50:01 +00:00
parent a6b4efc78f
commit 0b61257ca8
9 changed files with 305 additions and 83 deletions

View File

@ -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)) {

101
export.cc Normal file
View File

@ -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

View File

@ -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());

View File

@ -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);

View File

@ -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();
}
if (stl_mode)
export_stl(root_N, stl_filename, pd);
else
export_off(root_N, stl_filename, pd);
fprintf(f, "endsolid\n");
fclose(f);
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()

View File

@ -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]);
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]);
if (stl_output_file || off_output_file)
{
if (!filename)
help(argv[0]);
#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
m = new MainWindow();
m->show();
m->resize(800, 600);
m->s1->setSizes(QList<int>() << 400 << 400);
m->s2->setSizes(QList<int>() << 400 << 200);
a.connect(m, SIGNAL(destroyed()), &a, SLOT(quit()));
rc = a.exec();
{
fprintf(stderr, "Requested GUI mode but can't open display!\n");
exit(1);
}
destroy_builtin_functions();
destroy_builtin_modules();

View File

@ -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)

View File

@ -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

View File

@ -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)) {