mirror of https://github.com/vitalif/openscad
Clifford Wolf:
Added command line mode (stl export only) git-svn-id: http://svn.clifford.at/openscad/trunk@106 b57f626f-c46c-0410-a088-ec61d464b74cstl_dim
parent
a6b4efc78f
commit
0b61257ca8
|
@ -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)) {
|
||||
|
|
|
@ -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());
|
||||
|
|
1
lexer.l
1
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);
|
||||
|
|
87
mainwin.cc
87
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();
|
||||
}
|
||||
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()
|
||||
|
|
186
openscad.cc
186
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]);
|
||||
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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)) {
|
||||
|
|
Loading…
Reference in New Issue