summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--RELEASE_NOTES4
-rw-r--r--doc/TODO.txt1
-rw-r--r--src/CSGTermEvaluator.h1
-rw-r--r--src/MainWindow.h1
-rw-r--r--src/MainWindow.ui6
-rw-r--r--src/expr.cc4
-rw-r--r--src/mainwin.cc33
-rw-r--r--src/openscad.cc156
-rw-r--r--src/value.cc6
-rw-r--r--testdata/scad/features/echo-tests.scad12
-rw-r--r--tests/CMakeLists.txt25
-rw-r--r--tests/echotest.cc148
-rw-r--r--tests/regression/echotest/echo-expected.txt1
-rw-r--r--tests/regression/echotest/echo-tests-expected.txt8
14 files changed, 323 insertions, 83 deletions
diff --git a/RELEASE_NOTES b/RELEASE_NOTES
index a6a0855..3af3c1a 100644
--- a/RELEASE_NOTES
+++ b/RELEASE_NOTES
@@ -8,10 +8,11 @@ o New import() statement reads the correct file format based on the filename ext
(.stl, .dxf and .off is supported)
o The color() statement now supports an alpha parameter, e.g. color(c=[1,0,0], alpha=0.4)
o The color() statement now supports specifying colors as strings, e.g. color("Red")
-o if() and else() can now take any value type as parameter. false, 0, empty string and empty vector or illegal value type will evaluate as false, everything else as true.
+o if()/else() and the ternary operator can now take any value type as parameter. false, 0, empty string and empty vector or illegal value type will evaluate as false, everything else as true.
o Strings can now be lexographically compared using the <, <=, >, >= operators
o The version() function will return the OpenSCAD version as a vector, e.g. [2011, 09]
o The version_num() function will return the OpenSCAD version as a number, e.g. 20110923
+o Added PI constant.
Bugfixes:
o square() crashed if any of the dimensions were zero
@@ -26,6 +27,7 @@ o dxf_linear_extrude() and dxf_rotate_extrude() are now deprecated.
o The file, layer, origin and scale parameters to linear_extrude() and rotate_extrude()
are now deprecated. Use an import() child instead.
o import_dxf(), import_stl() and import_off() are now deprecated. Use import() instead.
+o When exporting geometry from the cmd-line, use the universal -o option. It will export to the correct file format based on the given suffix (dxf, stl, off).
OpenSCAD 2011.06
================
diff --git a/doc/TODO.txt b/doc/TODO.txt
index 65534b8..2202792 100644
--- a/doc/TODO.txt
+++ b/doc/TODO.txt
@@ -116,6 +116,7 @@ o Misc
(e.g Preview, Render)
- If trying to export STL/DXF but source is newer than the CGAL rendering, ask
for confirmation.
+ - Go through keyboard shortcuts and make them more conformant to platform standards
o Cmd-line
- Add verbose option (PRINT command from mainwin.cc and progress output)
diff --git a/src/CSGTermEvaluator.h b/src/CSGTermEvaluator.h
index b359f5b..9d1fabe 100644
--- a/src/CSGTermEvaluator.h
+++ b/src/CSGTermEvaluator.h
@@ -4,6 +4,7 @@
#include <map>
#include <list>
#include <vector>
+#include <cstddef>
#include "visitor.h"
#if defined __WIN32__ && ! defined _MSC_VER
diff --git a/src/MainWindow.h b/src/MainWindow.h
index 37a6a4c..a3c812b 100644
--- a/src/MainWindow.h
+++ b/src/MainWindow.h
@@ -115,6 +115,7 @@ private slots:
void actionExportSTL();
void actionExportOFF();
void actionExportDXF();
+ void actionExportCSG();
void actionExportImage();
void actionFlushCaches();
diff --git a/src/MainWindow.ui b/src/MainWindow.ui
index 1741557..4d5ff22 100644
--- a/src/MainWindow.ui
+++ b/src/MainWindow.ui
@@ -178,6 +178,7 @@
<addaction name="designActionExportSTL"/>
<addaction name="designActionExportOFF"/>
<addaction name="designActionExportDXF"/>
+ <addaction name="designActionExportCSG"/>
<addaction name="designActionExportImage"/>
<addaction name="designActionFlushCaches"/>
</widget>
@@ -657,6 +658,11 @@
<string>Export as Image...</string>
</property>
</action>
+ <action name="designActionExportCSG">
+ <property name="text">
+ <string>Export as CSG...</string>
+ </property>
+ </action>
</widget>
<customwidgets>
<customwidget>
diff --git a/src/expr.cc b/src/expr.cc
index c9eda4e..fc1fbf0 100644
--- a/src/expr.cc
+++ b/src/expr.cc
@@ -75,9 +75,7 @@ Value Expression::evaluate(const Context *context) const
return this->children[0]->evaluate(context) > this->children[1]->evaluate(context);
if (this->type == "?:") {
Value v = this->children[0]->evaluate(context);
- if (v.type == Value::BOOL)
- return this->children[v.b ? 1 : 2]->evaluate(context);
- return Value();
+ return this->children[v.toBool() ? 1 : 2]->evaluate(context);
}
if (this->type == "[]") {
Value v1 = this->children[0]->evaluate(context);
diff --git a/src/mainwin.cc b/src/mainwin.cc
index 238bd10..be82d26 100644
--- a/src/mainwin.cc
+++ b/src/mainwin.cc
@@ -283,6 +283,7 @@ MainWindow::MainWindow(const QString &filename)
connect(this->designActionExportSTL, SIGNAL(triggered()), this, SLOT(actionExportSTL()));
connect(this->designActionExportOFF, SIGNAL(triggered()), this, SLOT(actionExportOFF()));
connect(this->designActionExportDXF, SIGNAL(triggered()), this, SLOT(actionExportDXF()));
+ connect(this->designActionExportCSG, SIGNAL(triggered()), this, SLOT(actionExportCSG()));
connect(this->designActionExportImage, SIGNAL(triggered()), this, SLOT(actionExportImage()));
connect(this->designActionFlushCaches, SIGNAL(triggered()), this, SLOT(actionFlushCaches()));
@@ -1474,6 +1475,38 @@ void MainWindow::actionExportDXF()
#endif /* ENABLE_CGAL */
}
+void MainWindow::actionExportCSG()
+{
+ setCurrentOutput();
+
+ if (!this->root_node) {
+ PRINT("Nothing to export. Please try compiling first...");
+ clearCurrentOutput();
+ return;
+ }
+
+ QString csg_filename = QFileDialog::getSaveFileName(this, "Export CSG File",
+ this->fileName.isEmpty() ? "Untitled.csg" : QFileInfo(this->fileName).baseName()+".csg",
+ "CSG Files (*.csg)");
+ if (csg_filename.isEmpty()) {
+ PRINTF("No filename specified. CSG export aborted.");
+ clearCurrentOutput();
+ return;
+ }
+
+ std::ofstream fstream(csg_filename.toUtf8());
+ if (!fstream.is_open()) {
+ PRINTA("Can't open file \"%s\" for export", csg_filename);
+ }
+ else {
+ fstream << this->tree.getString(*this->root_node) << "\n";
+ fstream.close();
+ PRINTF("CSG export finished.");
+ }
+
+ clearCurrentOutput();
+}
+
void MainWindow::actionExportImage()
{
QImage img = this->glview->grabFrameBuffer();
diff --git a/src/openscad.cc b/src/openscad.cc
index 878cb22..f3d28a6 100644
--- a/src/openscad.cc
+++ b/src/openscad.cc
@@ -70,7 +70,7 @@ namespace po = boost::program_options;
static void help(const char *progname)
{
- fprintf(stderr, "Usage: %s [ { -s stl_file | -o off_file | -x dxf_file } [ -d deps_file ] ]\\\n"
+ fprintf(stderr, "Usage: %s [ { -o output_file } [ -d deps_file ] ]\\\n"
"%*s[ -m make_command ] [ -D var=val [..] ] filename\n",
progname, int(strlen(progname))+8, "");
exit(1);
@@ -126,18 +126,14 @@ int main(int argc, char **argv)
QCoreApplication::setApplicationName("OpenSCAD");
const char *filename = NULL;
- const char *stl_output_file = NULL;
- const char *off_output_file = NULL;
- const char *dxf_output_file = NULL;
+ const char *output_file = NULL;
const char *deps_output_file = NULL;
po::options_description desc("Allowed options");
desc.add_options()
("help,h", "help message")
("version,v", "print the version")
- ("s,s", po::value<string>(), "stl-file")
- ("o,o", po::value<string>(), "off-file")
- ("x,x", po::value<string>(), "dxf-file")
+ ("o,o", po::value<string>(), "out-file")
("d,d", po::value<string>(), "deps-file")
("m,m", po::value<string>(), "makefile")
("D,D", po::value<vector<string> >(), "var=val");
@@ -159,20 +155,10 @@ int main(int argc, char **argv)
if (vm.count("help")) help(argv[0]);
if (vm.count("version")) version();
- if (vm.count("s")) {
- if (stl_output_file || off_output_file || dxf_output_file)
- help(argv[0]);
- stl_output_file = vm["s"].as<string>().c_str();
- }
if (vm.count("o")) {
- if (stl_output_file || off_output_file || dxf_output_file)
- help(argv[0]);
- off_output_file = vm["o"].as<string>().c_str();
- }
- if (vm.count("x")) {
- if (stl_output_file || off_output_file || dxf_output_file)
- help(argv[0]);
- dxf_output_file = vm["x"].as<string>().c_str();
+ // FIXME: Allow for multiple output files?
+ if (output_file) help(argv[0]);
+ output_file = vm["o"].as<string>().c_str();
}
if (vm.count("d")) {
if (deps_output_file)
@@ -253,10 +239,24 @@ int main(int argc, char **argv)
PolySetCGALEvaluator psevaluator(cgalevaluator);
#endif
- if (stl_output_file || off_output_file || dxf_output_file)
+ if (output_file)
{
- if (!filename)
- help(argv[0]);
+ const char *stl_output_file = NULL;
+ const char *off_output_file = NULL;
+ const char *dxf_output_file = NULL;
+ const char *csg_output_file = NULL;
+
+ QString suffix = QFileInfo(output_file).suffix().toLower();
+ if (suffix == "stl") stl_output_file = output_file;
+ else if (suffix == "off") off_output_file = output_file;
+ else if (suffix == "dxf") dxf_output_file = output_file;
+ else if (suffix == "csg") csg_output_file = output_file;
+ else {
+ fprintf(stderr, "Unknown suffix for output file %s\n", output_file);
+ exit(1);
+ }
+
+ if (!filename) help(argv[0]);
#ifdef ENABLE_CGAL
Context root_ctx;
@@ -304,68 +304,80 @@ int main(int argc, char **argv)
AbstractNode::resetIndexCounter();
root_node = root_module->evaluate(&root_ctx, &root_inst);
-
tree.setRoot(root_node);
- CGAL_Nef_polyhedron root_N = cgalevaluator.evaluateCGALMesh(*tree.root());
- QDir::setCurrent(original_path.absolutePath());
-
- if (deps_output_file) {
- if (!write_deps(deps_output_file,
- stl_output_file ? stl_output_file : off_output_file)) {
- exit(1);
- }
- }
-
- if (stl_output_file) {
- if (root_N.dim != 3) {
- fprintf(stderr, "Current top level object is not a 3D object.\n");
- exit(1);
- }
- if (!root_N.p3->is_simple()) {
- fprintf(stderr, "Object isn't a valid 2-manifold! Modify your design.\n");
- exit(1);
- }
- std::ofstream fstream(stl_output_file);
+ if (csg_output_file) {
+ QDir::setCurrent(original_path.absolutePath());
+ std::ofstream fstream(csg_output_file);
if (!fstream.is_open()) {
- PRINTF("Can't open file \"%s\" for export", stl_output_file);
+ PRINTF("Can't open file \"%s\" for export", csg_output_file);
}
else {
- export_stl(&root_N, fstream, NULL);
+ fstream << tree.getString(*root_node) << "\n";
fstream.close();
}
}
-
- if (off_output_file) {
- if (root_N.dim != 3) {
- fprintf(stderr, "Current top level object is not a 3D object.\n");
- exit(1);
- }
- if (!root_N.p3->is_simple()) {
- fprintf(stderr, "Object isn't a valid 2-manifold! Modify your design.\n");
- exit(1);
- }
- std::ofstream fstream(off_output_file);
- if (!fstream.is_open()) {
- PRINTF("Can't open file \"%s\" for export", off_output_file);
- }
- else {
- export_off(&root_N, fstream, NULL);
- fstream.close();
+ else {
+ CGAL_Nef_polyhedron root_N = cgalevaluator.evaluateCGALMesh(*tree.root());
+
+ QDir::setCurrent(original_path.absolutePath());
+
+ if (deps_output_file) {
+ if (!write_deps(deps_output_file,
+ stl_output_file ? stl_output_file : off_output_file)) {
+ exit(1);
+ }
}
- }
- if (dxf_output_file) {
- std::ofstream fstream(dxf_output_file);
- if (!fstream.is_open()) {
- PRINTF("Can't open file \"%s\" for export", dxf_output_file);
+ if (stl_output_file) {
+ if (root_N.dim != 3) {
+ fprintf(stderr, "Current top level object is not a 3D object.\n");
+ exit(1);
+ }
+ if (!root_N.p3->is_simple()) {
+ fprintf(stderr, "Object isn't a valid 2-manifold! Modify your design.\n");
+ exit(1);
+ }
+ std::ofstream fstream(stl_output_file);
+ if (!fstream.is_open()) {
+ PRINTF("Can't open file \"%s\" for export", stl_output_file);
+ }
+ else {
+ export_stl(&root_N, fstream, NULL);
+ fstream.close();
+ }
}
- else {
- export_dxf(&root_N, fstream, NULL);
- fstream.close();
+
+ if (off_output_file) {
+ if (root_N.dim != 3) {
+ fprintf(stderr, "Current top level object is not a 3D object.\n");
+ exit(1);
+ }
+ if (!root_N.p3->is_simple()) {
+ fprintf(stderr, "Object isn't a valid 2-manifold! Modify your design.\n");
+ exit(1);
+ }
+ std::ofstream fstream(off_output_file);
+ if (!fstream.is_open()) {
+ PRINTF("Can't open file \"%s\" for export", off_output_file);
+ }
+ else {
+ export_off(&root_N, fstream, NULL);
+ fstream.close();
+ }
+ }
+
+ if (dxf_output_file) {
+ std::ofstream fstream(dxf_output_file);
+ if (!fstream.is_open()) {
+ PRINTF("Can't open file \"%s\" for export", dxf_output_file);
+ }
+ else {
+ export_dxf(&root_N, fstream, NULL);
+ fstream.close();
+ }
}
}
-
delete root_node;
#else
fprintf(stderr, "OpenSCAD has been compiled without CGAL support!\n");
diff --git a/src/value.cc b/src/value.cc
index 685bf81..6685594 100644
--- a/src/value.cc
+++ b/src/value.cc
@@ -352,19 +352,19 @@ std::string Value::toString() const
stream << ']';
break;
case RANGE:
- stream << "[ "
+ stream << '['
<< this->range_begin
<< " : "
<< this->range_step
<< " : "
<< this->range_end
- << " ]";
+ << ']';
break;
case NUMBER:
stream << this->num;
break;
case BOOL:
- stream << this->b;
+ stream << (this->b ? "true" : "false");
break;
default:
stream << "undef";
diff --git a/testdata/scad/features/echo-tests.scad b/testdata/scad/features/echo-tests.scad
new file mode 100644
index 0000000..b07d444
--- /dev/null
+++ b/testdata/scad/features/echo-tests.scad
@@ -0,0 +1,12 @@
+echo(undef);
+echo("string");
+s = "stringvar";
+echo(s);
+echo(a = 1, b = 2.0, true, c = false);
+v = [1, "vecstr", 2.34, false];
+echo(v);
+r = [1:2:10];
+echo(r);
+
+echo(vec = [1,2,3]);
+echo(range = [0:2]);
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 00a9238..3fd283e 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -78,10 +78,10 @@ include_directories(../src)
add_definitions(-DOPENSCAD_VERSION=test -DOPENSCAD_YEAR=2011 -DOPENSCAD_MONTH=10)
-set(COMMON_SOURCES
+
+set(CORE_SOURCES
../src/handle_dep.cc
../src/qhash.cc
- ../src/export.cc
../src/value.cc
../src/expr.cc
../src/func.cc
@@ -107,13 +107,24 @@ set(COMMON_SOURCES
../src/rotateextrude.cc
../src/printutils.cc
../src/progress.cc
+ ${FLEX_OpenSCADlexer_OUTPUTS}
+ ${BISON_OpenSCADparser_OUTPUTS})
+
+set(COMMON_SOURCES
+ ${CORE_SOURCES}
+ ../src/export.cc
../src/nodedumper.cc
../src/traverser.cc
../src/PolySetEvaluator.cc
../src/PolySetCache.cc
../src/Tree.cc
- ${FLEX_OpenSCADlexer_OUTPUTS}
- ${BISON_OpenSCADparser_OUTPUTS})
+)
+
+#
+# echotest
+#
+add_executable(echotest echotest.cc ${CORE_SOURCES})
+target_link_libraries(echotest ${QT_LIBRARIES} ${OPENGL_LIBRARY})
#
# dumptest
@@ -195,6 +206,12 @@ file(GLOB FEATURES_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/features/*.scad)
file(GLOB BUGS_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/*.scad)
file(GLOB SCAD_DXF_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/dxf/*.scad)
+list(APPEND ECHO_FILES
+ ${CMAKE_SOURCE_DIR}/../testdata/scad/minimal/echo.scad
+ ${CMAKE_SOURCE_DIR}/../testdata/scad/features/echo-tests.scad)
+
+# Add echotest tests to CTest
+add_cmdline_test(echotest txt ${ECHO_FILES})
# Add dumptest tests to CTest
add_cmdline_test(dumptest txt ${MINIMAL_FILES})
# Add csgtexttest tests to CTest
diff --git a/tests/echotest.cc b/tests/echotest.cc
new file mode 100644
index 0000000..4811c7c
--- /dev/null
+++ b/tests/echotest.cc
@@ -0,0 +1,148 @@
+/*
+ * OpenSCAD (www.openscad.org)
+ * Copyright (C) 2009-2011 Clifford Wolf <clifford@clifford.at> and
+ * Marius Kintel <marius@kintel.net>
+ *
+ * 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.
+ *
+ * As a special exception, you have permission to link this program
+ * with the CGAL library and distribute executables, as long as you
+ * follow the requirements of the GNU GPL in regard to all of the
+ * software in the executable aside from CGAL.
+ *
+ * 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
+ *
+ */
+
+#include "openscad.h"
+#include "handle_dep.h"
+#include "node.h"
+#include "module.h"
+#include "context.h"
+#include "value.h"
+#include "builtin.h"
+#include "printutils.h"
+
+#include <QApplication>
+#include <QFile>
+#include <QDir>
+#include <QSet>
+#include <getopt.h>
+#include <assert.h>
+#include <iostream>
+#include <sstream>
+
+using std::string;
+
+std::string commandline_commands;
+QString currentdir;
+QString examplesdir;
+QString librarydir;
+
+static void stdout_handler(const QString &msg, void *userdata) {
+ std::cout << msg.toUtf8().data() << std::endl;
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s <file.scad>\n", argv[0]);
+ exit(1);
+ }
+
+ const char *filename = argv[1];
+
+ int rc = 0;
+
+ set_output_handler(&stdout_handler, NULL);
+
+ initialize_builtin_functions();
+ initialize_builtin_modules();
+
+ QApplication app(argc, argv, false);
+ QDir original_path = QDir::current();
+
+ currentdir = QDir::currentPath();
+
+ QDir libdir(QApplication::instance()->applicationDirPath());
+#ifdef Q_WS_MAC
+ libdir.cd("../Resources"); // Libraries can be bundled
+ if (!libdir.exists("libraries")) libdir.cd("../../..");
+#elif defined(Q_OS_UNIX)
+ if (libdir.cd("../share/openscad/libraries")) {
+ librarydir = libdir.path();
+ } else
+ if (libdir.cd("../../share/openscad/libraries")) {
+ librarydir = libdir.path();
+ } else
+ if (libdir.cd("../../libraries")) {
+ librarydir = libdir.path();
+ } else
+#endif
+ if (libdir.cd("libraries")) {
+ librarydir = libdir.path();
+ }
+
+ 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));
+
+ Value zero3;
+ zero3.type = Value::VECTOR;
+ zero3.append(new Value(0.0));
+ zero3.append(new Value(0.0));
+ zero3.append(new Value(0.0));
+ root_ctx.set_variable("$vpt", zero3);
+ root_ctx.set_variable("$vpr", zero3);
+
+
+ AbstractModule *root_module;
+ ModuleInstantiation root_inst;
+ AbstractNode *root_node;
+
+ QFileInfo fileInfo(filename);
+ handle_dep(filename);
+ FILE *fp = fopen(filename, "rt");
+ if (!fp) {
+ fprintf(stderr, "Can't open input file `%s'!\n", filename);
+ exit(1);
+ } else {
+ std::stringstream text;
+ char buffer[513];
+ int ret;
+ while ((ret = fread(buffer, 1, 512, fp)) > 0) {
+ buffer[ret] = 0;
+ text << buffer;
+ }
+ fclose(fp);
+ text << commandline_commands;
+ root_module = parse(text.str().c_str(), fileInfo.absolutePath().toLocal8Bit(), false);
+ if (!root_module) {
+ exit(1);
+ }
+ }
+
+ QDir::setCurrent(fileInfo.absolutePath());
+
+ AbstractNode::resetIndexCounter();
+ root_node = root_module->evaluate(&root_ctx, &root_inst);
+
+ destroy_builtin_functions();
+ destroy_builtin_modules();
+
+ return rc;
+}
diff --git a/tests/regression/echotest/echo-expected.txt b/tests/regression/echotest/echo-expected.txt
new file mode 100644
index 0000000..8fc094e
--- /dev/null
+++ b/tests/regression/echotest/echo-expected.txt
@@ -0,0 +1 @@
+ECHO:
diff --git a/tests/regression/echotest/echo-tests-expected.txt b/tests/regression/echotest/echo-tests-expected.txt
new file mode 100644
index 0000000..cc548f6
--- /dev/null
+++ b/tests/regression/echotest/echo-tests-expected.txt
@@ -0,0 +1,8 @@
+ECHO: undef
+ECHO: "string"
+ECHO: "stringvar"
+ECHO: a = 1, b = 2, true, c = false
+ECHO: [1, "vecstr", 2.34, false]
+ECHO: [1 : 2 : 10]
+ECHO: vec = [1, 2, 3]
+ECHO: range = [0 : 1 : 2]
contact: Jan Huwald // Impressum