Merge remote branch 'upstream/visitor' into visitortests

Conflicts:
	src/export.cc
	src/openscad.cc
	src/polyset.cc
	src/transform.cc
	tests/CMakeLists.txt
	tests/FindGLEW.cmake
	tests/csgtermtest.cc
stl_dim
Don Bright 2011-09-12 17:40:51 -05:00
commit f5f06c8e97
295 changed files with 5959 additions and 2685 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "libraries/MCAD"]
path = libraries/MCAD
url = git@github.com:openscad/MCAD.git

View File

@ -1,12 +1,26 @@
OpenSCAD 20xx.yy
================
Features:
o The MCAD library is now bundled with OpenSCAD
o Added import and export of the OFF file format
o New import() statement reads the correct file format based on the filename extension
(.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.
Bugfixes:
o square() crashed if any of the dimensions were zero
o Flush Caches didn't flush cached USE'd modules
o STL export should be a bit more robust
Deprecations:
o dxf_linear_extrude() and dxf_rotate_extrude() are now deprecated.
Use linear_extrude() and rotate_extrude() instead.
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.
OpenSCAD 2011.06
================

View File

@ -1,18 +1,18 @@
boost {
isEmpty(DEPLOYDIR) {
# Optionally specify location of boost using the
# BOOSTDIR env. variable
BOOST_DIR = $$(BOOSTDIR)
!isEmpty(BOOST_DIR) {
INCLUDEPATH += $$BOOST_DIR
message("boost location: $$BOOST_DIR")
win32:LIBS += -L$$BOOST_DIR/lib
}
}
win32 {
LIBS += -llibboost_thread-vc90-mt-s-1_46_1 -llibboost_program_options-vc90-mt-s-1_46_1
} else {
LIBS += -lboost_thread -lboost_program_options
}
}
boost {
isEmpty(DEPLOYDIR) {
# Optionally specify location of boost using the
# BOOSTDIR env. variable
BOOST_DIR = $$(BOOSTDIR)
!isEmpty(BOOST_DIR) {
INCLUDEPATH += $$BOOST_DIR
message("boost location: $$BOOST_DIR")
win32:LIBS += -L$$BOOST_DIR/lib
}
}
win32 {
LIBS += -llibboost_thread-vc90-mt-s-1_46_1 -llibboost_program_options-vc90-mt-s-1_46_1
} else {
LIBS += -lboost_thread -lboost_program_options
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
doc/OpenSCAD-csg.pdf Normal file

Binary file not shown.

Binary file not shown.

View File

@ -6,6 +6,7 @@ o Tesselation via GLU sometimes produces strange results
o Export STL: Exports existing CGAL model even though the current model is changed, but not CGAL rendered
o Look into the polygon winding and rotate_extrude() problem reported by Britton
o CGAL Aff_transformation_3 doesn't support non-affine transformations (non-aff-matrix.scad)
o 2D union of polygons with a touching vertex doesn't work. see testdata/scad/bugs/polygon-touch.scad
STL Import BUGS
---------------
@ -39,12 +40,6 @@ Using STL-imported models is tricky and triggers multiple issues:
CRASH BUGS
----------
o Broken polyhedron() entities are not correctly detected and cause CGAL segfaults
o linear_extrude(50) square([5,0]);
o union() {
linear_extrude(height=10, twist=90) circle(5);
translate([7,-5,0]) linear_extrude(height=10, twist=180) polygon(points = [[0,0], [10,0], [5,10]]);
}
o non-convex minkowski example from chrysn fails with an exception
USER INTERFACE
--------------
@ -78,9 +73,12 @@ o 3D View
- overlay indicator displaying current view mode
- OpenCSG rendering: Coincident surfaces causes z-buffer fighting. Is this somehow
avoidable tuning the depth tests in OpenCSG?
- Make the 10.000 element OpenCSG klimit configurable (Preferences) ?
- Make the 10.000 element OpenCSG limit configurable (Preferences) ?
- Use OpenGL picking to facilitate ray-tracing like features like measuring
thicknesses, distances, slot thicknesses etc.
- When specifying a transparency with the color() statement,
the object is not sorted and will be rendered wrongly
- Add option to change lights, e.g. add an optional camera light
o Editor wishlist
- More infrastructure for external editor (allow communication from the outside)
- Preferences GUI for the features below
@ -133,20 +131,16 @@ o 2D Subsystem
o Built-in modules
- extrude*: Allow the base 2D primitive to have a Z value
- rotate_extrude(): Allow for specification of start/stop/sweep angle?
- Convex hull of multiple 2D or 2D objects
- Convex hull of 3D objects
o Advanced Transformations
- Add statement for refinement via surface subdivision
- Add statement for intersections in cartesian product of childs
- non-convex minkowski example from chrysn fails with an exception (testdata/scad/bugs/minkowski-assert.scad)
o Function-Module-Interface
- Pass a module instanciation to a function (e.g. for a volume() function)
- Pass a function to a module instanciation (e.g. for dynamic extrusion paths)
o Language Frontend
- include statement doesn't support nesting. This can be fixed by
keeping a nested stack of current input files in the lexer. See
the "Flex & Bison" O'Reilly book, "Start States and Nested Input
Files", page 28, for an example.
- Allow local variables and functions everywhere (not only on module level)
- allow any expression to be evaluated as boolean (!0 = true, 0 = false)
- Rethink for vs. intersection_for vs. group. Should for loops
generate child lists instead, and make these passable to other
modules or accessible by child()?
@ -163,8 +157,6 @@ o Mesh optimization on STL export
- Remove super small triangles (all sides are short)
- Replace super thin triangles (one h is short)
o Misc
- When specifying a transparency with the color() statement,
the object is not sorted and will be rendered wrongly
- Go through default values of parameters (e.g. cube() has x,y,z=1 while linear_extrude() has height=100)
- Add support for symbolic names to child() statement
- Add 'lines' object type for non-solid 2d drawings
@ -176,7 +168,6 @@ o Misc
o Grammar
- dim->name -> dim->label
- A random(seed) function
- import_*() -> *_import() (consistent prefix vs. postfix)
- linear_extrude()/rotate_extrude(): Cumbersome names? -> (extrude, revolve, lathe, sweep ?)
o Hollow donut problem
When extruding a 2D CSG tree (e.g. a polygon with a hole), the hole
@ -184,7 +175,8 @@ o Hollow donut problem
extrusions, this has only a minor visual impact, but for rotate
extrusion, the resulting CGAL models will lose the hole. The OpenCSG
rendering keeps the hole, but renders slightly incorrect.
o CGAL issues
- CGAL doesn't handle almost planar polygons. Consider splitting into triangles ourselves. See WillamAdams/dodec.scad
IDEAS FOR LANGUAGE CHANGES
@ -223,11 +215,6 @@ o Caching and MDI looks suspicious when the code relies on external resources
which might be loaded from difference locations in different documents
-> we might get a false cache hit
o Are contructs like "child(0)" cached? Could this give false cache hits?
o Write some cmd-line apps that dump an openscad file to misc. formats
(dump, stl, dxf)
o Write a simple test script that collects verified and current STL renderings
and displays them side-by-side or smth.
o Write simple driver scripts for comparing output of above command
o Collect "all" available OpenSCAD scripts from the internets and run the integration
tests on them all
o dumptest tests:

View File

@ -16,12 +16,13 @@ Adding a new regression test:
1) create a test file at an appropriate location under testdata/
2) if the test is non-obvious, create a human readable description of the test in the same directory (e.g testdata/scad/mytest.txt)
3) if a new test app was written, this must be added to tests/CMakeLists
4) run the test with the environment variable TEST_GENERATE=1, e.g.:
3) if a new test app was written, this must be added to tests/CMakeLists.txt
4) Add the tests to the test apps for which you want them to run (in tests/CMakeLists.txt)
5) run the test with the environment variable TEST_GENERATE=1, e.g.:
$ TEST_GENERATE=1 ctest -R mytest
(this will generate a mytest-expected.txt file which is used for regression testing)
5) manually verify that the output is correct (test-data/scad/mytest-expected.txt)
6) run the test normally and verify that it passes:
6) manually verify that the output is correct (tests/regression/<testapp>/mytest-expected.<suffix>)
7) run the test normally and verify that it passes:
$ ctest -R mytest
Note that test files which don't have an *-expected.<suffix> file will

7
doc/visitor-changes.txt Normal file
View File

@ -0,0 +1,7 @@
Changes in visitor branch:
o import_dxf(): layername="" imports all layers. Importing a single layer with a zero-length name is no longer supported. FIXME: The same prob. goes for dims
o cylinder(): the r parameter will now always be used in place of a missing r1 or r2
o for():
- with scalar argument now works, e.g.: for (i=23) echo(i)
- empty for loop is not evaluated, e.g. for () echo(i)
- for loop with illegal value is not evaluated, e.g. for ([0:true:2])

1
libraries/MCAD Submodule

@ -0,0 +1 @@
Subproject commit 60490ebd2c722d70e06a5c12fb55d85b6f1aa1cc

View File

@ -1,43 +0,0 @@
// Library: boxes.scad
// Version: 1.0
// Author: Marius Kintel
// Copyright: 2010
// License: BSD
// roundedBox([width, height, depth], float radius, bool sidesonly);
// EXAMPLE USAGE:
// roundedBox([20, 30, 40], 5, true);
// size is a vector [w, h, d]
module roundedBox(size, radius, sidesonly)
{
rot = [ [0,0,0], [90,0,90], [90,90,0] ];
if (sidesonly) {
cube(size - [2*radius,0,0], true);
cube(size - [0,2*radius,0], true);
for (x = [radius-size[0]/2, -radius+size[0]/2],
y = [radius-size[1]/2, -radius+size[1]/2]) {
translate([x,y,0]) cylinder(r=radius, h=size[2], center=true);
}
}
else {
cube([size[0], size[1]-radius*2, size[2]-radius*2], center=true);
cube([size[0]-radius*2, size[1], size[2]-radius*2], center=true);
cube([size[0]-radius*2, size[1]-radius*2, size[2]], center=true);
for (axis = [0:2]) {
for (x = [radius-size[axis]/2, -radius+size[axis]/2],
y = [radius-size[(axis+1)%3]/2, -radius+size[(axis+1)%3]/2]) {
rotate(rot[axis])
translate([x,y,0])
cylinder(h=size[(axis+2)%3]-2*radius, r=radius, center=true);
}
}
for (x = [radius-size[0]/2, -radius+size[0]/2],
y = [radius-size[1]/2, -radius+size[1]/2],
z = [radius-size[2]/2, -radius+size[2]/2]) {
translate([x,y,z]) sphere(radius);
}
}
}

View File

@ -1,148 +0,0 @@
/*
* OpenSCAD Shapes Library (www.openscad.org)
* Copyright (C) 2009 Catarina Mota
*
* 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
*
*/
//box(width, height, depth);
//roundedBox(width, height, depth, factor);
//cone(height, radius);
//oval(width, height, depth);
//tube(height, radius, wall);
//ovalTube(width, height, depth, wall);
//hexagon(height, depth);
//octagon(height, depth);
//dodecagon(height, depth);
//hexagram(height, depth);
//rightTriangle(adjacent, opposite, depth);
//equiTriangle(side, depth);
//12ptStar(height, depth);
//----------------------
// size is a vector [w, h, d]
module box(size) {
cube(size, true);
}
// size is a vector [w, h, d]
module roundedBox(size, radius) {
cube(size - [2*radius,0,0], true);
cube(size - [0,2*radius,0], true);
for (x = [radius-size[0]/2, -radius+size[0]/2],
y = [radius-size[1]/2, -radius+size[1]/2]) {
translate([x,y,0]) cylinder(r=radius, h=size[2], center=true);
}
}
module cone(height, radius, center = false) {
cylinder(height, radius, 0, center);
}
module oval(w,h, height, center = false) {
scale([1, h/w, 1]) cylinder(h=height, r=w, center=center);
}
// wall is wall thickness
module tube(height, radius, wall, center = false) {
difference() {
cylinder(h=height, r=radius, center=center);
cylinder(h=height, r=radius-wall, center=center);
}
}
// wall is wall thickness
module ovalTube(height, rx, ry, wall, center = false) {
difference() {
scale([1, ry/rx, 1]) cylinder(h=height, r=rx, center=center);
scale([(rx-wall)/rx, (ry-wall)/rx, 1]) cylinder(h=height, r=rx, center=center);
}
}
// size is the XY plane size, height in Z
module hexagon(size, height) {
boxWidth = size/1.75;
for (r = [-60, 0, 60]) rotate([0,0,r]) cube([boxWidth, size, height], true);
}
// size is the XY plane size, height in Z
module octagon(size, height) {
intersection() {
cube([size, size, height], true);
rotate([0,0,45]) cube([size, size, height], true);
}
}
// size is the XY plane size, height in Z
module dodecagon(size, height) {
intersection() {
hexagon(size, height);
rotate([0,0,90]) hexagon(size, height);
}
}
// size is the XY plane size, height in Z
module hexagram(size, height) {
boxWidth=size/1.75;
for (v = [[0,1],[0,-1],[1,-1]]) {
intersection() {
rotate([0,0,60*v[0]]) cube([size, boxWidth, height], true);
rotate([0,0,60*v[1]]) cube([size, boxWidth, height], true);
}
}
}
module rightTriangle(adjacent, opposite, height) {
difference() {
translate([-adjacent/2,opposite/2,0]) cube([adjacent, opposite, height], true);
translate([-adjacent,0,0]) {
rotate([0,0,atan(opposite/adjacent)]) dislocateBox(adjacent*2, opposite, height);
}
}
}
module equiTriangle(side, height) {
difference() {
translate([-side/2,side/2,0]) cube([side, side, height], true);
rotate([0,0,30]) dislocateBox(side*2, side, height);
translate([-side,0,0]) {
rotate([0,0,60]) dislocateBox(side*2, side, height);
}
}
}
module 12ptStar(size, height) {
starNum = 3;
starAngle = 360/starNum;
for (s = [1:starNum]) {
rotate([0, 0, s*starAngle]) cube([size, size, height], true);
}
}
//-----------------------
//MOVES THE ROTATION AXIS OF A BOX FROM ITS CENTER TO THE BOTTOM LEFT CORNER
//FIXME: Why are the dimensions changed?
// why not just translate([0,0,-d/2]) cube([w,h,d]);
module dislocateBox(w,h,d) {
translate([w/2,h,0]) {
difference() {
cube([w, h*2, d+1]);
translate([-w,0,0]) cube([w, h*2, d+1]);
}
}
}

View File

@ -119,7 +119,6 @@ FORMS += src/MainWindow.ui \
src/Preferences.ui
HEADERS += src/renderer.h \
src/cgalrenderer.h \
src/ThrownTogetherRenderer.h \
src/CGAL_renderer.h \
src/OGL_helper.h \
@ -127,7 +126,6 @@ HEADERS += src/renderer.h \
src/MainWindow.h \
src/Preferences.h \
src/builtin.h \
src/cgal.h \
src/context.h \
src/csgterm.h \
src/dxfdata.h \
@ -144,10 +142,13 @@ HEADERS += src/renderer.h \
src/dxflinextrudenode.h \
src/dxfrotextrudenode.h \
src/projectionnode.h \
src/cgaladvnode.h \
src/importnode.h \
src/transformnode.h \
src/colornode.h \
src/rendernode.h \
src/openscad.h \
src/handle_dep.h \
src/polyset.h \
src/printutils.h \
src/value.h \
@ -158,19 +159,18 @@ HEADERS += src/renderer.h \
src/traverser.h \
src/nodecache.h \
src/nodedumper.h \
src/CGALEvaluator.h \
src/PolySetCache.h \
src/PolySetEvaluator.h \
src/PolySetCGALEvaluator.h \
src/CSGTermEvaluator.h \
src/myqhash.h \
src/Tree.h \
src/mathc99.h \
src/memory.h \
src/stl-utils.h
SOURCES += src/openscad.cc \
src/mainwin.cc \
src/cgalrenderer.cc \
src/cgal.cc \
src/handle_dep.cc \
src/ThrownTogetherRenderer.cc \
src/glview.cc \
src/export.cc \
@ -184,12 +184,10 @@ SOURCES += src/openscad.cc \
src/polyset.cc \
src/csgops.cc \
src/transform.cc \
src/color.cc \
src/primitives.cc \
src/projection.cc \
src/cgaladv.cc \
src/cgaladv_convexhull2.cc \
src/cgaladv_minkowski3.cc \
src/cgaladv_minkowski2.cc \
src/surface.cc \
src/control.cc \
src/render.cc \
@ -203,19 +201,38 @@ SOURCES += src/openscad.cc \
src/dxfrotextrude.cc \
src/highlighter.cc \
src/printutils.cc \
src/nef2dxf.cc \
src/Preferences.cc \
src/progress.cc \
src/editor.cc \
src/traverser.cc \
src/nodedumper.cc \
src/CGALEvaluator.cc \
src/PolySetEvaluator.cc \
src/PolySetCGALEvaluator.cc \
src/CSGTermEvaluator.cc \
src/qhash.cc \
src/Tree.cc \
src/mathc99.cc
src/mathc99.cc \
src/PolySetCache.cc \
src/PolySetEvaluator.cc
cgal {
HEADERS += src/cgal.h \
src/cgalfwd.h \
src/cgalutils.h \
src/CGALEvaluator.h \
src/CGALCache.h \
src/PolySetCGALEvaluator.h \
src/CGALRenderer.h \
src/CGAL_Nef_polyhedron.h
SOURCES += src/cgalutils.cc \
src/CGALEvaluator.cc \
src/PolySetCGALEvaluator.cc \
src/CGALCache.cc \
src/CGALRenderer.cc \
src/CGAL_Nef_polyhedron.cc \
src/CGAL_Nef_polyhedron_DxfData.cc \
src/cgaladv_convexhull2.cc \
src/cgaladv_minkowski2.cc
}
macx {
HEADERS += src/AppleEvents.h \

View File

@ -125,7 +125,7 @@ build_cgal()
tar xzf CGAL-$version.tar.gz
cd CGAL-$version
# We build a static lib. Not really necessary, but it's well tested.
cmake -DCMAKE_INSTALL_PREFIX=$DEPLOYDIR -DBUILD_SHARED_LIBS=FALSE -DCMAKE_OSX_DEPLOYMENT_TARGET="10.5" -DCMAKE_OSX_ARCHITECTURES="i386;x86_64"
cmake -DCMAKE_INSTALL_PREFIX=$DEPLOYDIR -DBUILD_SHARED_LIBS=FALSE -DCMAKE_OSX_DEPLOYMENT_TARGET="10.5" -DCMAKE_OSX_ARCHITECTURES="i386;x86_64" -DBOOST_ROOT=$DEPLOYDIR
make -j4
make install
}

View File

@ -20,3 +20,6 @@ cp OpenSCAD-$VERSION.dmg ~/Dropbox/Public
ln -sf OpenSCAD-$VERSION.dmg ~/Dropbox/Public/OpenSCAD-latest.dmg
echo "Upload in progress..."
# Update snapshot filename on wab page
`dirname $0`/update-web.sh OpenSCAD-$VERSION.dmg

View File

@ -80,17 +80,29 @@ echo "Creating directory structure..."
case $OS in
MACOSX)
EXAMPLESDIR=OpenSCAD.app/Contents/Resources/examples
LIBRARYDIR=OpenSCAD.app/Contents/Resources/libraries
;;
*)
EXAMPLESDIR=openscad-$VERSION/examples/
LIBRARYDIR=openscad-$VERSION/libraries/
rm -rf openscad-$VERSION
mkdir openscad-$VERSION
;;
esac
mkdir -p $EXAMPLESDIR
cp examples/* $EXAMPLESDIR
chmod -R 644 $EXAMPLESDIR/*
if [ -n $EXAMPLESDIR ]; then
echo $EXAMPLESDIR
mkdir -p $EXAMPLESDIR
cp examples/* $EXAMPLESDIR
chmod -R 644 $EXAMPLESDIR/*
fi
if [ -n $LIBRARYDIR ]; then
echo $LIBRARYDIR
mkdir -p $LIBRARYDIR
cp -R libraries/* $LIBRARYDIR
chmod -R u=rwx,go=r,+X $LIBRARYDIR/*
rm -rf `find $LIBRARYDIR -name ".git"`
fi
echo "Creating archive.."

View File

@ -87,6 +87,6 @@ chmod 755 -R release/
cp examples/* release/examples/
chmod 644 -R release/examples/*
cp libraries/* release/libraries/
chmod 644 -R release/libraries/*
cp -R libraries/* release/libraries/
chmod -R u=rwx,go=r,+X release/libraries/*
rm -rf `find release/libraries -name ".git"`

14
scripts/update-web.sh Executable file
View File

@ -0,0 +1,14 @@
#!/bin/bash
dmgfile=$1
if [ -z "$dmgfile" ]; then
echo "Usage: $0 <dmgfile>"
exit 1
fi
indexfile=../openscad.github.com/index.html
if [ -f $indexfile ]; then
sed -i .backup -e "s/^\(.*mac-snapshot.*\)\(OpenSCAD-.*\.dmg\)\(.*\)\(OpenSCAD-.*dmg\)\(.*$\)/\\1$dmgfile\\3$dmgfile\\5/" $indexfile
echo "Web page updated. Remember to commit and push openscad.github.com"
else
echo "Web page not found at $indexfile"
fi

View File

@ -5,3 +5,7 @@ export DYLD_LIBRARY_PATH=$MACOSX_DEPLOY_DIR/lib
#export CGALDIR=$PWD/../install/CGAL-3.6
#export QCODEEDITDIR=$PWD/../qcodeedit-2.2.3/install
#export DYLD_LIBRARY_PATH=$OPENCSGDIR/lib:$QCODEEDITDIR/lib
# ccache:
export PATH=/opt/local/libexec/ccache:$PATH
export CCACHE_BASEDIR=$PWD/..

17
src/CGALCache.cc Normal file
View File

@ -0,0 +1,17 @@
#include "CGALCache.h"
#include "printutils.h"
#include "CGAL_Nef_polyhedron.h"
CGALCache *CGALCache::inst = NULL;
void CGALCache::insert(const std::string &id, const CGAL_Nef_polyhedron &N)
{
this->cache.insert(id, new CGAL_Nef_polyhedron(N), N.weight());
PRINTF("CGAL Cache insert: %s (%d verts)", id.substr(0, 40).c_str(), N.weight());
}
void CGALCache::print()
{
PRINTF("CGAL Polyhedrons in cache: %d", this->cache.size());
PRINTF("Vertices in cache: %d", this->cache.totalCost());
}

28
src/CGALCache.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef CGALCACHE_H_
#define CGALCACHE_H_
#include "myqhash.h"
#include <QCache>
/*!
*/
class CGALCache
{
public:
CGALCache(size_t limit = 100000) : cache(limit) {}
static CGALCache *instance() { if (!inst) inst = new CGALCache; return inst; }
bool contains(const std::string &id) const { return this->cache.contains(id); }
const class CGAL_Nef_polyhedron &get(const std::string &id) const { return *this->cache[id]; }
void insert(const std::string &id, const CGAL_Nef_polyhedron &N);
void clear() { cache.clear(); }
void print();
private:
static CGALCache *inst;
QCache<std::string, CGAL_Nef_polyhedron> cache;
};
#endif

View File

@ -1,3 +1,4 @@
#include "CGALCache.h"
#include "CGALEvaluator.h"
#include "visitor.h"
#include "state.h"
@ -5,11 +6,15 @@
#include "printutils.h"
#include "csgnode.h"
#include "cgaladvnode.h"
#include "transformnode.h"
#include "polyset.h"
#include "dxfdata.h"
#include "dxftess.h"
#include "CGALCache.h"
#include "cgal.h"
#include "cgalutils.h"
#include <CGAL/assertions_behaviour.h>
#include <CGAL/exceptions.h>
@ -28,12 +33,12 @@ CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const AbstractNode &node)
evaluate.execute();
assert(isCached(node));
}
return this->cache[this->tree.getString(node)];
return CGALCache::instance()->get(this->tree.getIdString(node));
}
bool CGALEvaluator::isCached(const AbstractNode &node) const
{
return this->cache.contains(this->tree.getString(node));
return CGALCache::instance()->contains(this->tree.getIdString(node));
}
/*!
@ -45,58 +50,31 @@ void CGALEvaluator::process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedr
if (target.dim != 2 && target.dim != 3) {
assert(false && "Dimension of Nef polyhedron must be 2 or 3");
}
if (src.empty()) return; // Empty polyhedron. This can happen for e.g. square([0,0])
if (target.dim != src.dim) return; // If someone tries to e.g. union 2d and 3d objects
if (target.dim == 2) {
switch (op) {
case CGE_UNION:
target.p2 += src.p2;
break;
case CGE_INTERSECTION:
target.p2 *= src.p2;
break;
case CGE_DIFFERENCE:
target.p2 -= src.p2;
break;
case CGE_MINKOWSKI:
target.p2 = minkowski2(target.p2, src.p2);
break;
case CGE_HULL:
//FIXME: Port convex hull to a binary operator or process it all in the end somehow
// target.p2 = convexhull2(target.p2, src.p2);
// target.p2 = convexhull2(polys);
break;
}
}
else if (target.dim == 3) {
switch (op) {
case CGE_UNION:
target.p3 += src.p3;
break;
case CGE_INTERSECTION:
target.p3 *= src.p3;
break;
case CGE_DIFFERENCE:
target.p3 -= src.p3;
break;
case CGE_MINKOWSKI:
target.p3 = minkowski3(target.p3, src.p3);
break;
case CGE_HULL:
// FIXME: Print warning: hull() not supported in 3D
break;
}
switch (op) {
case CGE_UNION:
target += src;
break;
case CGE_INTERSECTION:
target *= src;
break;
case CGE_DIFFERENCE:
target -= src;
break;
case CGE_MINKOWSKI:
target.minkowski(src);
break;
}
}
/*!
FIXME: Let caller insert into the cache since caller might modify the result
(e.g. transform)
*/
void CGALEvaluator::applyToChildren(const AbstractNode &node, CGALEvaluator::CsgOp op)
CGAL_Nef_polyhedron CGALEvaluator::applyToChildren(const AbstractNode &node, CGALEvaluator::CsgOp op)
{
CGAL_Nef_polyhedron N;
if (this->visitedchildren[node.index()].size() > 0) {
bool first = true;
for (ChildList::const_iterator iter = this->visitedchildren[node.index()].begin();
iter != this->visitedchildren[node.index()].end();
iter++) {
@ -105,18 +83,49 @@ void CGALEvaluator::applyToChildren(const AbstractNode &node, CGALEvaluator::Csg
// FIXME: Don't use deep access to modinst members
if (chnode->modinst->tag_background) continue;
assert(isCached(*chnode));
if (first) {
N = this->cache[chcacheid];
// If the first child(ren) are empty (e.g. echo) nodes,
// ignore them (reset first flag)
if (N.dim != 0) first = false;
if (N.empty()) {
N = CGALCache::instance()->get(chcacheid).copy();
} else {
process(N, this->cache[chcacheid], op);
process(N, CGALCache::instance()->get(chcacheid), op);
}
chnode->progress_report();
}
}
this->cache.insert(this->tree.getString(node), N);
return N;
}
extern CGAL_Nef_polyhedron2 *convexhull2(std::list<CGAL_Nef_polyhedron2*> a);
CGAL_Nef_polyhedron CGALEvaluator::applyHull(const CgaladvNode &node)
{
CGAL_Nef_polyhedron N;
if (this->visitedchildren[node.index()].size() > 0) {
std::list<CGAL_Nef_polyhedron2*> polys;
bool all2d = true;
for (ChildList::const_iterator iter = this->visitedchildren[node.index()].begin();
iter != this->visitedchildren[node.index()].end();
iter++) {
const AbstractNode *chnode = iter->first;
const string &chcacheid = iter->second;
// FIXME: Don't use deep access to modinst members
if (chnode->modinst->tag_background) continue;
assert(isCached(*chnode));
const CGAL_Nef_polyhedron &ch = CGALCache::instance()->get(chcacheid);
if (ch.dim == 2) {
polys.push_back(ch.p2.get());
}
else if (ch.dim == 3) {
PRINT("WARNING: hull() is not implemented yet for 3D objects!");
all2d = false;
}
chnode->progress_report();
}
if (all2d) {
N = CGAL_Nef_polyhedron(convexhull2(polys));
}
}
return N;
}
/*
@ -130,7 +139,10 @@ Response CGALEvaluator::visit(State &state, const AbstractNode &node)
{
if (state.isPrefix() && isCached(node)) return PruneTraversal;
if (state.isPostfix()) {
if (!isCached(node)) applyToChildren(node, CGE_UNION);
if (!isCached(node)) {
CGAL_Nef_polyhedron N = applyToChildren(node, CGE_UNION);
CGALCache::instance()->insert(this->tree.getIdString(node), N);
}
addToParent(state, node);
}
return ContinueTraversal;
@ -140,7 +152,10 @@ Response CGALEvaluator::visit(State &state, const AbstractIntersectionNode &node
{
if (state.isPrefix() && isCached(node)) return PruneTraversal;
if (state.isPostfix()) {
if (!isCached(node)) applyToChildren(node, CGE_INTERSECTION);
if (!isCached(node)) {
CGAL_Nef_polyhedron N = applyToChildren(node, CGE_INTERSECTION);
CGALCache::instance()->insert(this->tree.getIdString(node), N);
}
addToParent(state, node);
}
return ContinueTraversal;
@ -162,8 +177,11 @@ Response CGALEvaluator::visit(State &state, const CsgNode &node)
case CSG_TYPE_INTERSECTION:
op = CGE_INTERSECTION;
break;
default:
assert(false);
}
applyToChildren(node, op);
CGAL_Nef_polyhedron N = applyToChildren(node, op);
CGALCache::instance()->insert(this->tree.getIdString(node), N);
}
addToParent(state, node);
}
@ -176,10 +194,9 @@ Response CGALEvaluator::visit(State &state, const TransformNode &node)
if (state.isPostfix()) {
if (!isCached(node)) {
// First union all children
applyToChildren(node, CGE_UNION);
CGAL_Nef_polyhedron N = applyToChildren(node, CGE_UNION);
// Then apply transform
CGAL_Nef_polyhedron N = this->cache[this->tree.getString(node)];
// If there is no geometry under the transform, N will be empty and of dim 0,
// just just silently ignore such nodes
if (N.dim == 2) {
@ -191,68 +208,80 @@ Response CGALEvaluator::visit(State &state, const TransformNode &node)
node.matrix[0], node.matrix[4], node.matrix[12],
node.matrix[1], node.matrix[5], node.matrix[13], node.matrix[15]);
DxfData dd(N);
for (int i=0; i < dd.points.size(); i++) {
CGAL_Kernel2::Point_2 p = CGAL_Kernel2::Point_2(dd.points[i][0], dd.points[i][1]);
DxfData *dd = N.convertToDxfData();
for (size_t i=0; i < dd->points.size(); i++) {
CGAL_Kernel2::Point_2 p = CGAL_Kernel2::Point_2(dd->points[i][0], dd->points[i][1]);
p = t.transform(p);
dd.points[i][0] = to_double(p.x());
dd.points[i][1] = to_double(p.y());
dd->points[i][0] = to_double(p.x());
dd->points[i][1] = to_double(p.y());
}
PolySet ps;
ps.is2d = true;
dxf_tesselate(&ps, &dd, 0, true, false, 0);
dxf_tesselate(&ps, *dd, 0, true, false, 0);
N = evaluateCGALMesh(ps);
ps.refcount = 0;
delete dd;
}
else if (N.dim == 3) {
CGAL_Aff_transformation t(
node.matrix[0], node.matrix[4], node.matrix[ 8], node.matrix[12],
node.matrix[1], node.matrix[5], node.matrix[ 9], node.matrix[13],
node.matrix[2], node.matrix[6], node.matrix[10], node.matrix[14], node.matrix[15]);
N.p3.transform(t);
N.p3->transform(t);
}
this->cache.insert(this->tree.getString(node), N);
CGALCache::instance()->insert(this->tree.getIdString(node), N);
}
addToParent(state, node);
}
return ContinueTraversal;
}
// FIXME: EvaluateNode: Union over children + some magic
// FIXME: CgaladvNode: Iterate over children. Special operation
// FIXME: Subtypes of AbstractPolyNode:
// ProjectionNode
// DxfLinearExtrudeNode
// DxfRotateExtrudeNode
// (SurfaceNode)
// (PrimitiveNode)
Response CGALEvaluator::visit(State &state, const AbstractPolyNode &node)
{
if (state.isPrefix() && isCached(node)) return PruneTraversal;
if (state.isPostfix()) {
if (!isCached(node)) {
// First union all children
applyToChildren(node, CGE_UNION);
// Then apply polyset operation
PolySet *ps = node.evaluate_polyset(AbstractPolyNode::RENDER_CGAL, &this->psevaluator);
// Apply polyset operation
shared_ptr<PolySet> ps = this->psevaluator.getPolySet(node, false);
CGAL_Nef_polyhedron N;
if (ps) {
try {
CGAL_Nef_polyhedron N = evaluateCGALMesh(*ps);
N = evaluateCGALMesh(*ps);
// print_messages_pop();
node.progress_report();
ps->unlink();
this->cache.insert(this->tree.getString(node), N);
}
catch (...) { // Don't leak the PolySet on ProgressCancelException
ps->unlink();
throw;
}
node.progress_report();
}
CGALCache::instance()->insert(this->tree.getIdString(node), N);
}
addToParent(state, node);
}
return ContinueTraversal;
}
Response CGALEvaluator::visit(State &state, const CgaladvNode &node)
{
if (state.isPrefix() && isCached(node)) return PruneTraversal;
if (state.isPostfix()) {
if (!isCached(node)) {
CGAL_Nef_polyhedron N;
CGALEvaluator::CsgOp op;
switch (node.type) {
case MINKOWSKI:
op = CGE_MINKOWSKI;
N = applyToChildren(node, op);
break;
case GLIDE:
PRINT("WARNING: glide() is not implemented yet!");
return PruneTraversal;
break;
case SUBDIV:
PRINT("WARNING: subdiv() is not implemented yet!");
return PruneTraversal;
break;
case HULL:
N = applyHull(node);
break;
}
CGALCache::instance()->insert(this->tree.getIdString(node), N);
}
addToParent(state, node);
}
@ -268,129 +297,14 @@ void CGALEvaluator::addToParent(const State &state, const AbstractNode &node)
assert(state.isPostfix());
this->visitedchildren.erase(node.index());
if (state.parent()) {
this->visitedchildren[state.parent()->index()].push_back(std::make_pair(&node, this->tree.getString(node)));
this->visitedchildren[state.parent()->index()].push_back(std::make_pair(&node, this->tree.getIdString(node)));
}
}
#if 0
/*!
Static function to evaluate CGAL meshes.
NB! This is just a support function used for development and debugging
*/
CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const AbstractPolyNode &node)
{
// FIXME: Lookup Nef polyhedron in cache.
// print_messages_push();
PolySet *ps = node.evaluate_polyset(AbstractPolyNode::RENDER_CGAL);
if (ps) {
try {
CGAL_Nef_polyhedron N = ps->evaluateCSGMesh();
// FIXME: Insert into cache
// print_messages_pop();
node.progress_report();
ps->unlink();
return N;
}
catch (...) { // Don't leak the PolySet on ProgressCancelException
ps->unlink();
throw;
}
}
}
#endif
#ifdef ENABLE_CGAL
#undef GEN_SURFACE_DEBUG
class CGAL_Build_PolySet : public CGAL::Modifier_base<CGAL_HDS>
{
public:
typedef CGAL_HDS::Vertex::Point CGALPoint;
const PolySet &ps;
CGAL_Build_PolySet(const PolySet &ps) : ps(ps) { }
void operator()(CGAL_HDS& hds)
{
CGAL_Polybuilder B(hds, true);
QList<CGALPoint> vertices;
Grid3d<int> vertices_idx(GRID_FINE);
for (size_t i = 0; i < ps.polygons.size(); i++) {
const PolySet::Polygon *poly = &ps.polygons[i];
for (size_t j = 0; j < poly->size(); j++) {
const Vector3d &p = poly->at(j);
if (!vertices_idx.has(p[0], p[1], p[2])) {
vertices_idx.data(p[0], p[1], p[2]) = vertices.size();
vertices.append(CGALPoint(p[0], p[1], p[2]));
}
}
}
B.begin_surface(vertices.size(), ps.polygons.size());
#ifdef GEN_SURFACE_DEBUG
printf("=== CGAL Surface ===\n");
#endif
for (size_t i = 0; i < vertices.size(); i++) {
const CGALPoint &p = vertices[i];
B.add_vertex(p);
#ifdef GEN_SURFACE_DEBUG
printf("%d: %f %f %f\n", i, p[0], p[1], p[2]);
#endif
}
for (size_t i = 0; i < ps.polygons.size(); i++) {
const PolySet::Polygon *poly = &ps.polygons[i];
QHash<int,int> fc;
bool facet_is_degenerated = false;
for (size_t j = 0; j < poly->size(); j++) {
const Vector3d &p = poly->at(j);
int v = vertices_idx.data(p[0], p[1], p[2]);
if (fc[v]++ > 0)
facet_is_degenerated = true;
}
if (!facet_is_degenerated)
B.begin_facet();
#ifdef GEN_SURFACE_DEBUG
printf("F:");
#endif
for (size_t j = 0; j < poly->size(); j++) {
const Vector3d &p = poly->at(j);
#ifdef GEN_SURFACE_DEBUG
printf(" %d (%f,%f,%f)", vertices_idx.data(p[0], p[1], p[2]), p[0], p[1], p[2]);
#endif
if (!facet_is_degenerated)
B.add_vertex_to_facet(vertices_idx.data(p[0], p[1], p[2]));
}
#ifdef GEN_SURFACE_DEBUG
if (facet_is_degenerated)
printf(" (degenerated)");
printf("\n");
#endif
if (!facet_is_degenerated)
B.end_facet();
}
#ifdef GEN_SURFACE_DEBUG
printf("====================\n");
#endif
B.end_surface();
#undef PointKey
}
};
#endif /* ENABLE_CGAL */
CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const PolySet &ps)
{
if (ps.empty()) return CGAL_Nef_polyhedron();
if (ps.is2d)
{
#if 0
@ -499,7 +413,13 @@ CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const PolySet &ps)
double x = ps.polygons[i][j][0];
double y = ps.polygons[i][j][1];
if (this->grid.has(x, y)) {
this->polygons[this->poly_n].append(this->grid.data(x, y));
int idx = this->grid.data(x, y);
// Filter away two vertices with the same index (due to grid)
// This could be done in a more general way, but we'd rather redo the entire
// grid concept instead.
if (this->polygons[this->poly_n].indexOf(idx) == -1) {
this->polygons[this->poly_n].append(this->grid.data(x, y));
}
} else {
this->grid.align(x, y) = point_n;
this->polygons[this->poly_n].append(point_n);
@ -507,8 +427,13 @@ CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const PolySet &ps)
point_n++;
}
}
add_edges(this->poly_n);
this->poly_n++;
if (this->polygons[this->poly_n].size() >= 3) {
add_edges(this->poly_n);
this->poly_n++;
}
else {
this->polygons.remove(this->poly_n);
}
}
}
@ -574,9 +499,9 @@ CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const PolySet &ps)
}
}
CGAL_Nef_polyhedron2 toNef()
CGAL_Nef_polyhedron2 *toNef()
{
CGAL_Nef_polyhedron2 N;
CGAL_Nef_polyhedron2 *N = new CGAL_Nef_polyhedron2;
QHashIterator< int, QList<int> > it(polygons);
while (it.hasNext()) {
@ -586,7 +511,7 @@ CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const PolySet &ps)
int p = it.value()[j];
plist.push_back(points[p]);
}
N += CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED);
*N += CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED);
}
return N;
@ -594,9 +519,9 @@ CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const PolySet &ps)
};
PolyReducer pr(ps);
// printf("Number of polygons before reduction: %d\n", pr.polygons.size());
PRINTF("Number of polygons before reduction: %d\n", pr.polygons.size());
pr.reduce();
// printf("Number of polygons after reduction: %d\n", pr.polygons.size());
PRINTF("Number of polygons after reduction: %d\n", pr.polygons.size());
return CGAL_Nef_polyhedron(pr.toNef());
#endif
#if 0
@ -636,17 +561,14 @@ CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const PolySet &ps)
{
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
try {
CGAL_Polyhedron P;
CGAL_Build_PolySet builder(ps);
P.delegate(builder);
#if 0
std::cout << P;
#endif
CGAL_Nef_polyhedron3 N(P);
return CGAL_Nef_polyhedron(N);
}
CGAL_Polyhedron *P = createPolyhedronFromPolySet(ps);
if (P) {
CGAL_Nef_polyhedron3 *N = new CGAL_Nef_polyhedron3(*P);
return CGAL_Nef_polyhedron(N);
}
}
catch (CGAL::Assertion_exception e) {
PRINTF("ERROR: Illegal polygonal object - make sure all polygons are defined with the same winding order. Skipping affected object.");
PRINTF("CGAL error in CGA_Nef_polyhedron3(): %s", e.what());
CGAL::set_error_behaviour(old_behaviour);
return CGAL_Nef_polyhedron();
}

View File

@ -4,16 +4,13 @@
#include "myqhash.h"
#include "visitor.h"
#include "Tree.h"
#include "cgal.h"
#include "CGAL_Nef_polyhedron.h"
#include "PolySetCGALEvaluator.h"
#include <string>
#include <map>
#include <list>
extern CGAL_Nef_polyhedron3 minkowski3(CGAL_Nef_polyhedron3 a, CGAL_Nef_polyhedron3 b);
extern CGAL_Nef_polyhedron2 minkowski2(CGAL_Nef_polyhedron2 a, CGAL_Nef_polyhedron2 b);
using std::string;
using std::map;
using std::list;
@ -22,9 +19,8 @@ using std::pair;
class CGALEvaluator : public Visitor
{
public:
enum CsgOp {CGE_UNION, CGE_INTERSECTION, CGE_DIFFERENCE, CGE_MINKOWSKI, CGE_HULL};
// FIXME: If a cache is not given, we need to fix this ourselves
CGALEvaluator(QHash<string, CGAL_Nef_polyhedron> &cache, const Tree &tree) : cache(cache), tree(tree), psevaluator(*this) {}
enum CsgOp {CGE_UNION, CGE_INTERSECTION, CGE_DIFFERENCE, CGE_MINKOWSKI};
CGALEvaluator(const Tree &tree) : tree(tree), psevaluator(*this) {}
virtual ~CGALEvaluator() {}
virtual Response visit(State &state, const AbstractNode &node);
@ -32,6 +28,7 @@ public:
virtual Response visit(State &state, const CsgNode &node);
virtual Response visit(State &state, const TransformNode &node);
virtual Response visit(State &state, const AbstractPolyNode &node);
virtual Response visit(State &state, const CgaladvNode &node);
CGAL_Nef_polyhedron evaluateCGALMesh(const AbstractNode &node);
CGAL_Nef_polyhedron evaluateCGALMesh(const PolySet &polyset);
@ -42,14 +39,17 @@ private:
void addToParent(const State &state, const AbstractNode &node);
bool isCached(const AbstractNode &node) const;
void process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, CGALEvaluator::CsgOp op);
void applyToChildren(const AbstractNode &node, CGALEvaluator::CsgOp op);
CGAL_Nef_polyhedron applyToChildren(const AbstractNode &node, CGALEvaluator::CsgOp op);
CGAL_Nef_polyhedron applyHull(const CgaladvNode &node);
string currindent;
typedef list<pair<const AbstractNode *, string> > ChildList;
map<int, ChildList> visitedchildren;
QHash<string, CGAL_Nef_polyhedron> &cache;
const Tree &tree;
public:
// FIXME: Do we need to make this visible? Used for cache management
// Note: psevaluator constructor needs this->tree to be initialized first
PolySetCGALEvaluator psevaluator;
};

View File

@ -24,37 +24,40 @@
*
*/
#include "cgalrenderer.h"
#include "CGALRenderer.h"
#include "polyset.h"
#include "CGAL_renderer.h"
#include "dxfdata.h"
#include "dxftess.h"
#include "CGAL_Nef_polyhedron.h"
#include "cgal.h"
#include "Preferences.h"
//#include "Preferences.h"
CGALRenderer::CGALRenderer(const CGAL_Nef_polyhedron &root) : root(root)
{
if (root.dim == 2) {
DxfData dd(root);
DxfData *dd = root.convertToDxfData();
this->polyhedron = NULL;
this->polyset = new PolySet();
this->polyset->is2d = true;
dxf_tesselate(this->polyset, &dd, 0, true, false, 0);
dxf_tesselate(this->polyset, *dd, 0, true, false, 0);
delete dd;
}
else if (root.dim == 3) {
this->polyset = NULL;
this->polyhedron = new Polyhedron();
// FIXME: Make independent of Preferences
this->polyhedron->setColor(Polyhedron::CGAL_NEF3_MARKED_FACET_COLOR,
Preferences::inst()->color(Preferences::CGAL_FACE_BACK_COLOR).red(),
Preferences::inst()->color(Preferences::CGAL_FACE_BACK_COLOR).green(),
Preferences::inst()->color(Preferences::CGAL_FACE_BACK_COLOR).blue());
this->polyhedron->setColor(Polyhedron::CGAL_NEF3_UNMARKED_FACET_COLOR,
Preferences::inst()->color(Preferences::CGAL_FACE_FRONT_COLOR).red(),
Preferences::inst()->color(Preferences::CGAL_FACE_FRONT_COLOR).green(),
Preferences::inst()->color(Preferences::CGAL_FACE_FRONT_COLOR).blue());
// this->polyhedron->setColor(Polyhedron::CGAL_NEF3_MARKED_FACET_COLOR,
// Preferences::inst()->color(Preferences::CGAL_FACE_BACK_COLOR).red(),
// Preferences::inst()->color(Preferences::CGAL_FACE_BACK_COLOR).green(),
// Preferences::inst()->color(Preferences::CGAL_FACE_BACK_COLOR).blue());
// this->polyhedron->setColor(Polyhedron::CGAL_NEF3_UNMARKED_FACET_COLOR,
// Preferences::inst()->color(Preferences::CGAL_FACE_FRONT_COLOR).red(),
// Preferences::inst()->color(Preferences::CGAL_FACE_FRONT_COLOR).green(),
// Preferences::inst()->color(Preferences::CGAL_FACE_FRONT_COLOR).blue());
CGAL::OGL::Nef3_Converter<CGAL_Nef_polyhedron3>::convert_to_OGLPolyhedron(this->root.p3, this->polyhedron);
CGAL::OGL::Nef3_Converter<CGAL_Nef_polyhedron3>::convert_to_OGLPolyhedron(*this->root.p3, this->polyhedron);
this->polyhedron->init();
}
else {
@ -65,7 +68,7 @@ CGALRenderer::CGALRenderer(const CGAL_Nef_polyhedron &root) : root(root)
CGALRenderer::~CGALRenderer()
{
if (this->polyset) this->polyset->unlink();
delete this->polyset;
delete this->polyhedron;
}
@ -74,12 +77,13 @@ void CGALRenderer::draw(bool showfaces, bool showedges) const
if (this->root.dim == 2) {
// Draw 2D polygons
glDisable(GL_LIGHTING);
const QColor &col = Preferences::inst()->color(Preferences::CGAL_FACE_2D_COLOR);
// FIXME: const QColor &col = Preferences::inst()->color(Preferences::CGAL_FACE_2D_COLOR);
const QColor &col = QColor(0x00, 0xbf, 0x99);
glColor3f(col.redF(), col.greenF(), col.blueF());
for (int i=0; i < this->polyset->polygons.size(); i++) {
for (size_t i=0; i < this->polyset->polygons.size(); i++) {
glBegin(GL_POLYGON);
for (int j=0; j < this->polyset->polygons[i].size(); j++) {
for (size_t j=0; j < this->polyset->polygons[i].size(); j++) {
const Vector3d &p = this->polyset->polygons[i][j];
glVertex3d(p[0], p[1], -0.1);
}
@ -90,13 +94,14 @@ void CGALRenderer::draw(bool showfaces, bool showedges) const
typedef Explorer::Face_const_iterator fci_t;
typedef Explorer::Halfedge_around_face_const_circulator heafcc_t;
typedef Explorer::Point Point;
Explorer E = this->root.p2.explorer();
Explorer E = this->root.p2->explorer();
// Draw 2D edges
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glLineWidth(2);
const QColor &col2 = Preferences::inst()->color(Preferences::CGAL_EDGE_2D_COLOR);
// FIXME: const QColor &col2 = Preferences::inst()->color(Preferences::CGAL_EDGE_2D_COLOR);
const QColor &col2 = QColor(0xff, 0x00, 0x00);
glColor3f(col2.redF(), col2.greenF(), col2.blueF());
// Extract the boundary, including inner boundaries of the polygons

View File

@ -2,7 +2,7 @@
#define CGALRENDERER_H_
#include "renderer.h"
#include "cgal.h"
#include "CGAL_Nef_polyhedron.h"
class CGALRenderer : public Renderer
{
@ -11,7 +11,7 @@ public:
~CGALRenderer();
void draw(bool showfaces, bool showedges) const;
private:
public:
const CGAL_Nef_polyhedron &root;
class Polyhedron *polyhedron;
class PolySet *polyset;

View File

@ -0,0 +1,91 @@
#include "CGAL_Nef_polyhedron.h"
#include "cgal.h"
#include "cgalutils.h"
#include "printutils.h"
#include "polyset.h"
#include "dxfdata.h"
#include "dxftess.h"
#include <CGAL/minkowski_sum_3.h>
#include <CGAL/assertions_behaviour.h>
#include <CGAL/exceptions.h>
CGAL_Nef_polyhedron& CGAL_Nef_polyhedron::operator+=(const CGAL_Nef_polyhedron &other)
{
if (this->dim == 2) (*this->p2) += (*other.p2);
else if (this->dim == 3) (*this->p3) += (*other.p3);
return *this;
}
CGAL_Nef_polyhedron& CGAL_Nef_polyhedron::operator*=(const CGAL_Nef_polyhedron &other)
{
if (this->dim == 2) (*this->p2) *= (*other.p2);
else if (this->dim == 3) (*this->p3) *= (*other.p3);
return *this;
}
CGAL_Nef_polyhedron& CGAL_Nef_polyhedron::operator-=(const CGAL_Nef_polyhedron &other)
{
if (this->dim == 2) (*this->p2) -= (*other.p2);
else if (this->dim == 3) (*this->p3) -= (*other.p3);
return *this;
}
extern CGAL_Nef_polyhedron2 minkowski2(const CGAL_Nef_polyhedron2 &a, const CGAL_Nef_polyhedron2 &b);
CGAL_Nef_polyhedron &CGAL_Nef_polyhedron::minkowski(const CGAL_Nef_polyhedron &other)
{
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
try {
if (this->dim == 2) (*this->p2) = minkowski2(*this->p2, *other.p2);
else if (this->dim == 3) (*this->p3) = CGAL::minkowski_sum_3(*this->p3, *other.p3);
}
catch (CGAL::Assertion_exception e) {
PRINTF("CGAL error in minkowski %s", e.what());
CGAL::set_error_behaviour(old_behaviour);
}
return *this;
}
int CGAL_Nef_polyhedron::weight() const
{
if (this->dim == 2) return this->p2->explorer().number_of_vertices();
if (this->dim == 3) return this->p3->number_of_vertices();
return 0;
}
/*!
Creates a new PolySet and initializes it with the data from this polyhedron
This method is not const since convert_to_Polyhedron() wasn't const
in earlier versions of CGAL.
*/
PolySet *CGAL_Nef_polyhedron::convertToPolyset()
{
assert(!this->empty());
PolySet *ps = NULL;
if (this->dim == 2) {
ps = new PolySet();
DxfData *dd = this->convertToDxfData();
ps->is2d = true;
dxf_tesselate(ps, *dd, 0, true, false, 0);
dxf_border_to_ps(ps, *dd);
delete dd;
}
else if (this->dim == 3) {
CGAL_Polyhedron P;
this->p3->convert_to_Polyhedron(P);
ps = createPolySetFromPolyhedron(P);
}
return ps;
}
/*!
Deep copy
*/
CGAL_Nef_polyhedron CGAL_Nef_polyhedron::copy() const
{
CGAL_Nef_polyhedron copy = *this;
if (copy.p2) copy.p2.reset(new CGAL_Nef_polyhedron2(*copy.p2));
else if (copy.p3) copy.p3.reset(new CGAL_Nef_polyhedron3(*copy.p3));
return copy;
}

34
src/CGAL_Nef_polyhedron.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef CGAL_NEF_POLYHEDRON_H_
#define CGAL_NEF_POLYHEDRON_H_
#ifdef ENABLE_CGAL
#include "cgalfwd.h"
#include "memory.h"
class CGAL_Nef_polyhedron
{
public:
CGAL_Nef_polyhedron() : dim(0) {}
CGAL_Nef_polyhedron(CGAL_Nef_polyhedron2 *p) : dim(2), p2(p) {}
CGAL_Nef_polyhedron(CGAL_Nef_polyhedron3 *p) : dim(3), p3(p) {}
~CGAL_Nef_polyhedron() {}
bool empty() const { return (dim == 0 || (!p2 && !p3)); }
CGAL_Nef_polyhedron &operator+=(const CGAL_Nef_polyhedron &other);
CGAL_Nef_polyhedron &operator*=(const CGAL_Nef_polyhedron &other);
CGAL_Nef_polyhedron &operator-=(const CGAL_Nef_polyhedron &other);
CGAL_Nef_polyhedron &minkowski(const CGAL_Nef_polyhedron &other);
CGAL_Nef_polyhedron copy() const;
int weight() const;
class PolySet *convertToPolyset();
class DxfData *convertToDxfData() const;
int dim;
shared_ptr<CGAL_Nef_polyhedron2> p2;
shared_ptr<CGAL_Nef_polyhedron3> p3;
};
#endif /* ENABLE_CGAL */
#endif

View File

@ -26,19 +26,21 @@
#include "dxfdata.h"
#include "grid.h"
#include "CGAL_Nef_polyhedron.h"
#include "cgal.h"
#ifdef ENABLE_CGAL
DxfData::DxfData(const struct CGAL_Nef_polyhedron &N)
DxfData *CGAL_Nef_polyhedron::convertToDxfData() const
{
assert(N.dim == 2);
assert(this->dim == 2);
DxfData *dxfdata = new DxfData();
Grid2d<int> grid(GRID_COARSE);
typedef CGAL_Nef_polyhedron2::Explorer Explorer;
typedef Explorer::Face_const_iterator fci_t;
typedef Explorer::Halfedge_around_face_const_circulator heafcc_t;
Explorer E = N.p2.explorer();
Explorer E = this->p2->explorer();
for (fci_t fit = E.faces_begin(), facesend = E.faces_end(); fit != facesend; ++fit)
{
@ -52,26 +54,27 @@ DxfData::DxfData(const struct CGAL_Nef_polyhedron &N)
if (grid.has(x, y)) {
this_point = grid.align(x, y);
} else {
this_point = grid.align(x, y) = points.size();
points.append(Vector2d(x, y));
this_point = grid.align(x, y) = dxfdata->points.size();
dxfdata->points.push_back(Vector2d(x, y));
}
if (first_point < 0) {
paths.append(Path());
dxfdata->paths.push_back(DxfData::Path());
first_point = this_point;
}
if (this_point != last_point) {
paths.last().points.append(&points[this_point]);
dxfdata->paths.back().indices.push_back(this_point);
last_point = this_point;
}
}
}
if (first_point >= 0) {
paths.last().is_closed = 1;
paths.last().points.append(&points[first_point]);
dxfdata->paths.back().is_closed = 1;
dxfdata->paths.back().indices.push_back(first_point);
}
}
fixup_path_direction();
dxfdata->fixup_path_direction();
return dxfdata;
}
#endif // ENABLE_CGAL

View File

@ -5,8 +5,11 @@
#include "module.h"
#include "csgnode.h"
#include "transformnode.h"
#include "colornode.h"
#include "rendernode.h"
#include "cgaladvnode.h"
#include "printutils.h"
#include "PolySetEvaluator.h"
#include <string>
#include <map>
@ -82,14 +85,16 @@ Response CSGTermEvaluator::visit(State &state, const AbstractIntersectionNode &n
return ContinueTraversal;
}
static CSGTerm *evaluate_csg_term_from_ps(const double m[20],
vector<CSGTerm*> &highlights,
vector<CSGTerm*> &background,
PolySet *ps,
const ModuleInstantiation *modinst,
const AbstractPolyNode &node)
static CSGTerm *evaluate_csg_term_from_ps(const State &state,
vector<CSGTerm*> &highlights,
vector<CSGTerm*> &background,
const shared_ptr<PolySet> &ps,
const ModuleInstantiation *modinst,
const AbstractNode &node)
{
CSGTerm *t = new CSGTerm(ps, m, QString("%1%2").arg(node.name().c_str()).arg(node.index()));
std::stringstream stream;
stream << node.name() << node.index();
CSGTerm *t = new CSGTerm(ps, state.matrix(), state.color(), stream.str());
if (modinst->tag_highlight)
highlights.push_back(t->link());
if (modinst->tag_background) {
@ -103,10 +108,12 @@ Response CSGTermEvaluator::visit(State &state, const AbstractPolyNode &node)
{
if (state.isPostfix()) {
CSGTerm *t1 = NULL;
PolySet *ps = node.evaluate_polyset(AbstractPolyNode::RENDER_OPENCSG, this->psevaluator);
if (ps) {
t1 = evaluate_csg_term_from_ps(state.matrix(), this->highlights, this->background,
ps, node.modinst, node);
if (this->psevaluator) {
shared_ptr<PolySet> ps = this->psevaluator->getPolySet(node, true);
if (ps) {
t1 = evaluate_csg_term_from_ps(state, this->highlights, this->background,
ps, node.modinst, node);
}
}
this->stored_term[node.index()] = t1;
addToParent(state, node);
@ -128,6 +135,8 @@ Response CSGTermEvaluator::visit(State &state, const CsgNode &node)
case CSG_TYPE_INTERSECTION:
op = CSGT_INTERSECTION;
break;
default:
assert(false);
}
applyToChildren(node, op);
addToParent(state, node);
@ -138,7 +147,7 @@ Response CSGTermEvaluator::visit(State &state, const CsgNode &node)
Response CSGTermEvaluator::visit(State &state, const TransformNode &node)
{
if (state.isPrefix()) {
double m[20];
double m[16];
for (int i = 0; i < 16; i++)
{
@ -149,11 +158,6 @@ Response CSGTermEvaluator::visit(State &state, const TransformNode &node)
m[i] += state.matrix()[c_row + j*4] * node.matrix[m_col*4 + j];
}
}
for (int i = 16; i < 20; i++) {
m[i] = node.matrix[i] < 0 ? state.matrix()[i] : node.matrix[i];
}
state.setMatrix(m);
}
if (state.isPostfix()) {
@ -163,10 +167,11 @@ Response CSGTermEvaluator::visit(State &state, const TransformNode &node)
return ContinueTraversal;
}
// FIXME: Find out how to best call into CGAL from this visitor
Response CSGTermEvaluator::visit(State &state, const RenderNode &node)
Response CSGTermEvaluator::visit(State &state, const ColorNode &node)
{
PRINT("WARNING: Found render() statement but compiled without CGAL support!");
if (state.isPrefix()) {
state.setColor(node.color);
}
if (state.isPostfix()) {
applyToChildren(node, CSGT_UNION);
addToParent(state, node);
@ -174,6 +179,44 @@ Response CSGTermEvaluator::visit(State &state, const RenderNode &node)
return ContinueTraversal;
}
// FIXME: If we've got CGAL support, render this node as a CGAL union into a PolySet
Response CSGTermEvaluator::visit(State &state, const RenderNode &node)
{
if (state.isPostfix()) {
CSGTerm *t1 = NULL;
shared_ptr<PolySet> ps;
if (this->psevaluator) {
ps = this->psevaluator->getPolySet(node, true);
}
if (ps) {
t1 = evaluate_csg_term_from_ps(state, this->highlights, this->background,
ps, node.modinst, node);
}
this->stored_term[node.index()] = t1;
addToParent(state, node);
}
return ContinueTraversal;
}
Response CSGTermEvaluator::visit(State &state, const CgaladvNode &node)
{
if (state.isPostfix()) {
CSGTerm *t1 = NULL;
// FIXME: Calling evaluator directly since we're not a PolyNode. Generalize this.
shared_ptr<PolySet> ps;
if (this->psevaluator) {
ps = this->psevaluator->getPolySet(node, true);
}
if (ps) {
t1 = evaluate_csg_term_from_ps(state, this->highlights, this->background,
ps, node.modinst, node);
}
this->stored_term[node.index()] = t1;
addToParent(state, node);
}
return ContinueTraversal;
}
/*!
Adds ourself to out parent's list of traversed children.
Call this for _every_ node which affects output during the postfix traversal.
@ -186,168 +229,3 @@ void CSGTermEvaluator::addToParent(const State &state, const AbstractNode &node)
this->visitedchildren[state.parent()->index()].push_back(&node);
}
}
#if 0
// FIXME: #ifdef ENABLE_CGAL
#if 0
CSGTerm *CgaladvNode::evaluate_csg_term(double m[20], QVector<CSGTerm*> &highlights, QVector<CSGTerm*> &background) const
{
if (type == MINKOWSKI)
return evaluate_csg_term_from_nef(m, highlights, background, "minkowski", this->convexity);
if (type == GLIDE)
return evaluate_csg_term_from_nef(m, highlights, background, "glide", this->convexity);
if (type == SUBDIV)
return evaluate_csg_term_from_nef(m, highlights, background, "subdiv", this->convexity);
if (type == HULL)
return evaluate_csg_term_from_nef(m, highlights, background, "hull", this->convexity);
return NULL;
}
#else // ENABLE_CGAL
CSGTerm *CgaladvNode::evaluate_csg_term(double m[20], QVector<CSGTerm*> &highlights, QVector<CSGTerm*> &background) const
{
PRINT("WARNING: Found minkowski(), glide(), subdiv() or hull() statement but compiled without CGAL support!");
return NULL;
}
#endif // ENABLE_CGAL
// FIXME: #ifdef ENABLE_CGAL
#if 0
CSGTerm *AbstractNode::evaluate_csg_term_from_nef(double m[20], QVector<CSGTerm*> &highlights, QVector<CSGTerm*> &background, const char *statement, int convexity) const
{
QString key = mk_cache_id();
if (PolySet::ps_cache.contains(key)) {
PRINT(PolySet::ps_cache[key]->msg);
return AbstractPolyNode::evaluate_csg_term_from_ps(m, highlights, background,
PolySet::ps_cache[key]->ps->link(), modinst, idx);
}
print_messages_push();
CGAL_Nef_polyhedron N;
QString cache_id = mk_cache_id();
if (cgal_nef_cache.contains(cache_id))
{
PRINT(cgal_nef_cache[cache_id]->msg);
N = cgal_nef_cache[cache_id]->N;
}
else
{
PRINTF_NOCACHE("Processing uncached %s statement...", statement);
// PRINTA("Cache ID: %1", cache_id);
QApplication::processEvents();
QTime t;
t.start();
N = this->evaluateCSGMesh();
int s = t.elapsed() / 1000;
PRINTF_NOCACHE("..processing time: %d hours, %d minutes, %d seconds", s / (60*60), (s / 60) % 60, s % 60);
}
PolySet *ps = NULL;
if (N.dim == 2)
{
DxfData dd(N);
ps = new PolySet();
ps->is2d = true;
dxf_tesselate(ps, &dd, 0, true, false, 0);
dxf_border_to_ps(ps, &dd);
}
if (N.dim == 3)
{
if (!N.p3.is_simple()) {
PRINTF("WARNING: Result of %s() isn't valid 2-manifold! Modify your design..", statement);
return NULL;
}
ps = new PolySet();
CGAL_Polyhedron P;
N.p3.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;
for (FCI fi = P.facets_begin(); fi != P.facets_end(); ++fi) {
HFCC hc = fi->facet_begin();
HFCC hc_end = hc;
ps->append_poly();
do {
Vertex v = *VCI((hc++)->vertex());
double x = CGAL::to_double(v.point().x());
double y = CGAL::to_double(v.point().y());
double z = CGAL::to_double(v.point().z());
ps->append_vertex(x, y, z);
} while (hc != hc_end);
}
}
if (ps)
{
ps->convexity = convexity;
PolySet::ps_cache.insert(key, new PolySet::ps_cache_entry(ps->link()));
CSGTerm *term = new CSGTerm(ps, m, QString("n%1").arg(idx));
if (modinst->tag_highlight)
highlights.push_back(term->link());
if (modinst->tag_background) {
background.push_back(term);
return NULL;
}
return term;
}
print_messages_pop();
return NULL;
}
CSGTerm *RenderNode::evaluate_csg_term(double m[20], QVector<CSGTerm*> &highlights, QVector<CSGTerm*> &background) const
{
return evaluate_csg_term_from_nef(m, highlights, background, "render", this->convexity);
}
#else
CSGTerm *RenderNode::evaluate_csg_term(double m[20], QVector<CSGTerm*> &highlights, QVector<CSGTerm*> &background) const
{
CSGTerm *t1 = NULL;
PRINT("WARNING: Found render() statement but compiled without CGAL support!");
foreach(AbstractNode * v, children) {
CSGTerm *t2 = v->evaluate_csg_term(m, highlights, background);
if (t2 && !t1) {
t1 = t2;
} else if (t2 && t1) {
t1 = new CSGTerm(CSGTerm::TYPE_UNION, t1, t2);
}
}
if (modinst->tag_highlight)
highlights.push_back(t1->link());
if (t1 && modinst->tag_background) {
background.push_back(t1);
return NULL;
}
return t1;
}
#endif
#endif

View File

@ -27,7 +27,9 @@ public:
virtual Response visit(State &state, const AbstractPolyNode &node);
virtual Response visit(State &state, const CsgNode &node);
virtual Response visit(State &state, const TransformNode &node);
virtual Response visit(State &state, const ColorNode &node);
virtual Response visit(State &state, const RenderNode &node);
virtual Response visit(State &state, const CgaladvNode &node);
class CSGTerm *evaluateCSGTerm(const AbstractNode &node,
vector<CSGTerm*> &highlights,

View File

@ -92,6 +92,7 @@ private slots:
void actionOpen();
void actionOpenRecent();
void actionOpenExample();
void updateRecentFiles();
void clearRecentFiles();
void updateRecentFileActions();
void actionSave();

View File

@ -28,6 +28,7 @@
#include "OpenCSGRenderer.h"
#include "polyset.h"
#include "csgterm.h"
#include "stl-utils.h"
#ifdef ENABLE_OPENCSG
# include <opencsg.h>
#endif
@ -37,13 +38,13 @@ class OpenCSGPrim : public OpenCSG::Primitive
public:
OpenCSGPrim(OpenCSG::Operation operation, unsigned int convexity) :
OpenCSG::Primitive(operation, convexity) { }
PolySet *p;
shared_ptr<PolySet> ps;
double *m;
int csgmode;
virtual void render() {
glPushMatrix();
glMultMatrixd(m);
p->render_surface(PolySet::COLORMODE_NONE, PolySet::csgmode_e(csgmode), m);
ps->render_surface(PolySet::COLORMODE_NONE, PolySet::csgmode_e(csgmode), m);
glPopMatrix();
}
};
@ -74,8 +75,8 @@ void OpenCSGRenderer::renderCSGChain(CSGChain *chain, GLint *shaderinfo,
bool highlight, bool background) const
{
std::vector<OpenCSG::Primitive*> primitives;
int j = 0;
for (int i = 0;; i++) {
size_t j = 0;
for (size_t i = 0;; i++) {
bool last = i == chain->polysets.size();
if (last || chain->types[i] == CSGTerm::TYPE_UNION) {
if (j+1 != i) {
@ -85,6 +86,7 @@ void OpenCSGRenderer::renderCSGChain(CSGChain *chain, GLint *shaderinfo,
if (shaderinfo) glUseProgram(shaderinfo[0]);
for (; j < i; j++) {
double *m = chain->matrices[j];
double *c = chain->colors[j];
glPushMatrix();
glMultMatrixd(m);
int csgmode = chain->types[j] == CSGTerm::TYPE_DIFFERENCE ? PolySet::CSGMODE_DIFFERENCE : PolySet::CSGMODE_NORMAL;
@ -92,12 +94,12 @@ void OpenCSGRenderer::renderCSGChain(CSGChain *chain, GLint *shaderinfo,
chain->polysets[j]->render_surface(PolySet::COLORMODE_HIGHLIGHT, PolySet::csgmode_e(csgmode + 20), m, shaderinfo);
} else if (background) {
chain->polysets[j]->render_surface(PolySet::COLORMODE_BACKGROUND, PolySet::csgmode_e(csgmode + 10), m, shaderinfo);
} else if (m[16] >= 0 || m[17] >= 0 || m[18] >= 0) {
} else if (c[0] >= 0 || c[1] >= 0 || c[2] >= 0) {
// User-defined color from source
glColor4d(m[16], m[17], m[18], m[19]);
glColor4dv(c);
if (shaderinfo) {
glUniform4f(shaderinfo[1], m[16], m[17], m[18], m[19]);
glUniform4f(shaderinfo[2], (m[16]+1)/2, (m[17]+1)/2, (m[18]+1)/2, 1.0);
glUniform4f(shaderinfo[1], c[0], c[1], c[2], c[3]);
glUniform4f(shaderinfo[2], (c[0]+1)/2, (c[1]+1)/2, (c[2]+1)/2, 1.0);
}
chain->polysets[j]->render_surface(PolySet::COLORMODE_NONE, PolySet::csgmode_e(csgmode), m, shaderinfo);
} else if (chain->types[j] == CSGTerm::TYPE_DIFFERENCE) {
@ -119,11 +121,12 @@ void OpenCSGRenderer::renderCSGChain(CSGChain *chain, GLint *shaderinfo,
OpenCSGPrim *prim = new OpenCSGPrim(chain->types[i] == CSGTerm::TYPE_DIFFERENCE ?
OpenCSG::Subtraction : OpenCSG::Intersection, chain->polysets[i]->convexity);
prim->p = chain->polysets[i];
prim->ps = chain->polysets[i];
prim->m = chain->matrices[i];
prim->csgmode = chain->types[i] == CSGTerm::TYPE_DIFFERENCE ? PolySet::CSGMODE_DIFFERENCE : PolySet::CSGMODE_NORMAL;
if (highlight) prim->csgmode += 20;
else if (background) prim->csgmode += 10;
primitives.push_back(prim);
}
std::for_each(primitives.begin(), primitives.end(), del_fun<OpenCSG::Primitive>());
}

View File

@ -1,22 +1,39 @@
#include "PolySetCGALEvaluator.h"
#include "cgal.h"
#include "cgalutils.h"
#include "polyset.h"
#include "CGALEvaluator.h"
#include "projectionnode.h"
#include "dxflinextrudenode.h"
#include "dxfrotextrudenode.h"
#include "cgaladvnode.h"
#include "rendernode.h"
#include "dxfdata.h"
#include "dxftess.h"
#include "module.h"
#include "printutils.h"
#include "openscad.h" // get_fragments_from_r()
#include <boost/foreach.hpp>
PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node, AbstractPolyNode::render_mode_e)
PolySetCGALEvaluator::PolySetCGALEvaluator(CGALEvaluator &cgalevaluator)
: PolySetEvaluator(cgalevaluator.getTree()), cgalevaluator(cgalevaluator)
{
const string &cacheid = this->cgalevaluator.getTree().getString(node);
if (this->cache.contains(cacheid)) return this->cache[cacheid]->ps->link();
}
CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(node);
PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node)
{
// Before projecting, union all children
CGAL_Nef_polyhedron sum;
BOOST_FOREACH (AbstractNode * v, node.getChildren()) {
if (v->modinst->tag_background) continue;
CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(*v);
if (N.dim == 3) {
if (sum.empty()) sum = N.copy();
else sum += N;
}
}
if (sum.empty()) return NULL;
PolySet *ps = new PolySet();
ps->convexity = node.convexity;
@ -24,56 +41,55 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node, Abstr
if (node.cut_mode)
{
PolySet *cube = new PolySet();
PolySet cube;
double infval = 1e8, eps = 0.1;
double x1 = -infval, x2 = +infval, y1 = -infval, y2 = +infval, z1 = 0, z2 = eps;
cube->append_poly(); // top
cube->append_vertex(x1, y1, z2);
cube->append_vertex(x2, y1, z2);
cube->append_vertex(x2, y2, z2);
cube->append_vertex(x1, y2, z2);
cube.append_poly(); // top
cube.append_vertex(x1, y1, z2);
cube.append_vertex(x2, y1, z2);
cube.append_vertex(x2, y2, z2);
cube.append_vertex(x1, y2, z2);
cube->append_poly(); // bottom
cube->append_vertex(x1, y2, z1);
cube->append_vertex(x2, y2, z1);
cube->append_vertex(x2, y1, z1);
cube->append_vertex(x1, y1, z1);
cube.append_poly(); // bottom
cube.append_vertex(x1, y2, z1);
cube.append_vertex(x2, y2, z1);
cube.append_vertex(x2, y1, z1);
cube.append_vertex(x1, y1, z1);
cube->append_poly(); // side1
cube->append_vertex(x1, y1, z1);
cube->append_vertex(x2, y1, z1);
cube->append_vertex(x2, y1, z2);
cube->append_vertex(x1, y1, z2);
cube.append_poly(); // side1
cube.append_vertex(x1, y1, z1);
cube.append_vertex(x2, y1, z1);
cube.append_vertex(x2, y1, z2);
cube.append_vertex(x1, y1, z2);
cube->append_poly(); // side2
cube->append_vertex(x2, y1, z1);
cube->append_vertex(x2, y2, z1);
cube->append_vertex(x2, y2, z2);
cube->append_vertex(x2, y1, z2);
cube.append_poly(); // side2
cube.append_vertex(x2, y1, z1);
cube.append_vertex(x2, y2, z1);
cube.append_vertex(x2, y2, z2);
cube.append_vertex(x2, y1, z2);
cube->append_poly(); // side3
cube->append_vertex(x2, y2, z1);
cube->append_vertex(x1, y2, z1);
cube->append_vertex(x1, y2, z2);
cube->append_vertex(x2, y2, z2);
cube.append_poly(); // side3
cube.append_vertex(x2, y2, z1);
cube.append_vertex(x1, y2, z1);
cube.append_vertex(x1, y2, z2);
cube.append_vertex(x2, y2, z2);
cube->append_poly(); // side4
cube->append_vertex(x1, y2, z1);
cube->append_vertex(x1, y1, z1);
cube->append_vertex(x1, y1, z2);
cube->append_vertex(x1, y2, z2);
CGAL_Nef_polyhedron Ncube = this->cgalevaluator.evaluateCGALMesh(*cube);
cube->unlink();
cube.append_poly(); // side4
cube.append_vertex(x1, y2, z1);
cube.append_vertex(x1, y1, z1);
cube.append_vertex(x1, y1, z2);
cube.append_vertex(x1, y2, z2);
CGAL_Nef_polyhedron Ncube = this->cgalevaluator.evaluateCGALMesh(cube);
// N.p3 *= CGAL_Nef_polyhedron3(CGAL_Plane(0, 0, 1, 0), CGAL_Nef_polyhedron3::INCLUDED);
N.p3 *= Ncube.p3;
if (!N.p3.is_simple()) {
sum *= Ncube;
if (!sum.p3->is_simple()) {
PRINTF("WARNING: Body of projection(cut = true) isn't valid 2-manifold! Modify your design..");
goto cant_project_non_simple_polyhedron;
}
PolySet *ps3 = N.convertToPolyset();
PolySet *ps3 = sum.convertToPolyset();
Grid2d<int> conversion_grid(GRID_COARSE);
for (size_t i = 0; i < ps3->polygons.size(); i++) {
for (size_t j = 0; j < ps3->polygons[i].size(); j++) {
@ -95,18 +111,17 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node, Abstr
}
next_ps3_polygon_cut_mode:;
}
ps3->unlink();
delete ps3;
}
else
{
if (!N.p3.is_simple()) {
if (!sum.p3->is_simple()) {
PRINTF("WARNING: Body of projection(cut = false) isn't valid 2-manifold! Modify your design..");
goto cant_project_non_simple_polyhedron;
}
PolySet *ps3 = N.convertToPolyset();
PolySet *ps3 = sum.convertToPolyset();
CGAL_Nef_polyhedron np;
np.dim = 2;
for (size_t i = 0; i < ps3->polygons.size(); i++)
{
int min_x_p = -1;
@ -144,38 +159,43 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node, Abstr
else
plist.push_back(p);
}
np.p2 += CGAL_Nef_polyhedron2(plist.begin(), plist.end(),
CGAL_Nef_polyhedron2::INCLUDED);
// FIXME: Should the CGAL_Nef_polyhedron2 be cached?
if (np.empty()) {
np.dim = 2;
np.p2.reset(new CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED));
}
else {
(*np.p2) += CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED);
}
}
DxfData dxf(np);
dxf_tesselate(ps, &dxf, 0, true, false, 0);
dxf_border_to_ps(ps, &dxf);
ps3->unlink();
delete ps3;
DxfData *dxf = np.convertToDxfData();
dxf_tesselate(ps, *dxf, 0, true, false, 0);
dxf_border_to_ps(ps, *dxf);
delete dxf;
}
cant_project_non_simple_polyhedron:
this->cache.insert(cacheid, new cache_entry(ps->link()));
return ps;
}
static void add_slice(PolySet *ps, DxfData::Path *pt, double rot1, double rot2, double h1, double h2)
static void add_slice(PolySet *ps, const DxfData &dxf, DxfData::Path &path, double rot1, double rot2, double h1, double h2)
{
for (int j = 1; j < pt->points.count(); j++)
for (size_t j = 1; j < path.indices.size(); j++)
{
int k = j - 1;
double jx1 = (*pt->points[j])[0] * cos(rot1*M_PI/180) + (*pt->points[j])[1] * sin(rot1*M_PI/180);
double jy1 = (*pt->points[j])[0] * -sin(rot1*M_PI/180) + (*pt->points[j])[1] * cos(rot1*M_PI/180);
double jx1 = dxf.points[path.indices[j]][0] * cos(rot1*M_PI/180) + dxf.points[path.indices[j]][1] * sin(rot1*M_PI/180);
double jy1 = dxf.points[path.indices[j]][0] * -sin(rot1*M_PI/180) + dxf.points[path.indices[j]][1] * cos(rot1*M_PI/180);
double jx2 = (*pt->points[j])[0] * cos(rot2*M_PI/180) + (*pt->points[j])[1] * sin(rot2*M_PI/180);
double jy2 = (*pt->points[j])[0] * -sin(rot2*M_PI/180) + (*pt->points[j])[1] * cos(rot2*M_PI/180);
double jx2 = dxf.points[path.indices[j]][0] * cos(rot2*M_PI/180) + dxf.points[path.indices[j]][1] * sin(rot2*M_PI/180);
double jy2 = dxf.points[path.indices[j]][0] * -sin(rot2*M_PI/180) + dxf.points[path.indices[j]][1] * cos(rot2*M_PI/180);
double kx1 = (*pt->points[k])[0] * cos(rot1*M_PI/180) + (*pt->points[k])[1] * sin(rot1*M_PI/180);
double ky1 = (*pt->points[k])[0] * -sin(rot1*M_PI/180) + (*pt->points[k])[1] * cos(rot1*M_PI/180);
double kx1 = dxf.points[path.indices[k]][0] * cos(rot1*M_PI/180) + dxf.points[path.indices[k]][1] * sin(rot1*M_PI/180);
double ky1 = dxf.points[path.indices[k]][0] * -sin(rot1*M_PI/180) + dxf.points[path.indices[k]][1] * cos(rot1*M_PI/180);
double kx2 = (*pt->points[k])[0] * cos(rot2*M_PI/180) + (*pt->points[k])[1] * sin(rot2*M_PI/180);
double ky2 = (*pt->points[k])[0] * -sin(rot2*M_PI/180) + (*pt->points[k])[1] * cos(rot2*M_PI/180);
double kx2 = dxf.points[path.indices[k]][0] * cos(rot2*M_PI/180) + dxf.points[path.indices[k]][1] * sin(rot2*M_PI/180);
double ky2 = dxf.points[path.indices[k]][0] * -sin(rot2*M_PI/180) + dxf.points[path.indices[k]][1] * cos(rot2*M_PI/180);
double dia1_len_sq = (jy1-ky2)*(jy1-ky2) + (jx1-kx2)*(jx1-kx2);
double dia2_len_sq = (jy2-ky1)*(jy2-ky1) + (jx2-kx1)*(jx2-kx1);
@ -183,7 +203,7 @@ static void add_slice(PolySet *ps, DxfData::Path *pt, double rot1, double rot2,
if (dia1_len_sq > dia2_len_sq)
{
ps->append_poly();
if (pt->is_inner) {
if (path.is_inner) {
ps->append_vertex(kx1, ky1, h1);
ps->append_vertex(jx1, jy1, h1);
ps->append_vertex(jx2, jy2, h2);
@ -194,7 +214,7 @@ static void add_slice(PolySet *ps, DxfData::Path *pt, double rot1, double rot2,
}
ps->append_poly();
if (pt->is_inner) {
if (path.is_inner) {
ps->append_vertex(kx2, ky2, h2);
ps->append_vertex(kx1, ky1, h1);
ps->append_vertex(jx2, jy2, h2);
@ -207,7 +227,7 @@ static void add_slice(PolySet *ps, DxfData::Path *pt, double rot1, double rot2,
else
{
ps->append_poly();
if (pt->is_inner) {
if (path.is_inner) {
ps->append_vertex(kx1, ky1, h1);
ps->append_vertex(jx1, jy1, h1);
ps->append_vertex(kx2, ky2, h2);
@ -218,7 +238,7 @@ static void add_slice(PolySet *ps, DxfData::Path *pt, double rot1, double rot2,
}
ps->append_poly();
if (pt->is_inner) {
if (path.is_inner) {
ps->append_vertex(jx2, jy2, h2);
ps->append_vertex(kx2, ky2, h2);
ps->append_vertex(jx1, jy1, h1);
@ -231,29 +251,40 @@ static void add_slice(PolySet *ps, DxfData::Path *pt, double rot1, double rot2,
}
}
PolySet *PolySetCGALEvaluator::evaluatePolySet(const DxfLinearExtrudeNode &node, AbstractPolyNode::render_mode_e)
PolySet *PolySetCGALEvaluator::evaluatePolySet(const DxfLinearExtrudeNode &node)
{
const string &cacheid = this->cgalevaluator.getTree().getString(node);
if (this->cache.contains(cacheid)) return this->cache[cacheid]->ps->link();
DxfData *dxf;
if (node.filename.isEmpty())
if (node.filename.empty())
{
// Before extruding, union all (2D) children nodes
// to a single DxfData, then tesselate this into a PolySet
CGAL_Nef_polyhedron N;
N.dim = 2;
foreach (AbstractNode * v, node.getChildren()) {
CGAL_Nef_polyhedron sum;
BOOST_FOREACH (AbstractNode * v, node.getChildren()) {
if (v->modinst->tag_background) continue;
N.p2 += this->cgalevaluator.evaluateCGALMesh(*v).p2;
CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(*v);
if (N.dim != 2) {
PRINT("ERROR: rotate_extrude() is not defined for 3D child objects!");
}
else {
if (sum.empty()) sum = N.copy();
else sum += N;
}
}
dxf = new DxfData(N);
if (sum.empty()) return NULL;
dxf = sum.convertToDxfData();;
} else {
dxf = new DxfData(node.fn, node.fs, node.fa, node.filename, node.layername, node.origin_x, node.origin_y, node.scale);
}
PolySet *ps = extrudeDxfData(node, *dxf);
delete dxf;
return ps;
}
PolySet *PolySetCGALEvaluator::extrudeDxfData(const DxfLinearExtrudeNode &node, DxfData &dxf)
{
PolySet *ps = new PolySet();
ps->convexity = node.convexity;
@ -268,20 +299,20 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const DxfLinearExtrudeNode &node,
}
bool first_open_path = true;
for (int i = 0; i < dxf->paths.count(); i++)
for (size_t i = 0; i < dxf.paths.size(); i++)
{
if (dxf->paths[i].is_closed)
if (dxf.paths[i].is_closed)
continue;
if (first_open_path) {
PRINTF("WARNING: Open paths in dxf_linear_extrude(file = \"%s\", layer = \"%s\"):",
node.filename.toAscii().data(), node.layername.toAscii().data());
node.filename.c_str(), node.layername.c_str());
first_open_path = false;
}
PRINTF(" %9.5f %10.5f ... %10.5f %10.5f",
(*dxf->paths[i].points.first())[0] / node.scale + node.origin_x,
(*dxf->paths[i].points.first())[1] / node.scale + node.origin_y,
(*dxf->paths[i].points.last())[0] / node.scale + node.origin_x,
(*dxf->paths[i].points.last())[1] / node.scale + node.origin_y);
dxf.points[dxf.paths[i].indices.front()][0] / node.scale + node.origin_x,
dxf.points[dxf.paths[i].indices.front()][1] / node.scale + node.origin_y,
dxf.points[dxf.paths[i].indices.back()][0] / node.scale + node.origin_x,
dxf.points[dxf.paths[i].indices.back()][1] / node.scale + node.origin_y);
}
@ -295,11 +326,11 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const DxfLinearExtrudeNode &node,
double t2 = node.twist*(j+1) / node.slices;
double g1 = h1 + (h2-h1)*j / node.slices;
double g2 = h1 + (h2-h1)*(j+1) / node.slices;
for (int i = 0; i < dxf->paths.count(); i++)
for (size_t i = 0; i < dxf.paths.size(); i++)
{
if (!dxf->paths[i].is_closed)
if (!dxf.paths[i].is_closed)
continue;
add_slice(ps, &dxf->paths[i], t1, t2, g1, g2);
add_slice(ps, dxf, dxf.paths[i], t1, t2, g1, g2);
}
}
}
@ -307,52 +338,76 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const DxfLinearExtrudeNode &node,
{
dxf_tesselate(ps, dxf, 0, false, true, h1);
dxf_tesselate(ps, dxf, 0, true, true, h2);
for (int i = 0; i < dxf->paths.count(); i++)
for (size_t i = 0; i < dxf.paths.size(); i++)
{
if (!dxf->paths[i].is_closed)
if (!dxf.paths[i].is_closed)
continue;
add_slice(ps, &dxf->paths[i], 0, 0, h1, h2);
add_slice(ps, dxf, dxf.paths[i], 0, 0, h1, h2);
}
}
delete dxf;
this->cache.insert(cacheid, new cache_entry(ps->link()));
return ps;
}
PolySet *PolySetCGALEvaluator::evaluatePolySet(const DxfRotateExtrudeNode &node,
AbstractPolyNode::render_mode_e)
PolySet *PolySetCGALEvaluator::evaluatePolySet(const DxfRotateExtrudeNode &node)
{
const string &cacheid = this->cgalevaluator.getTree().getString(node);
if (this->cache.contains(cacheid)) return this->cache[cacheid]->ps->link();
DxfData *dxf;
if (node.filename.isEmpty())
if (node.filename.empty())
{
// Before extruding, union all (2D) children nodes
// to a single DxfData, then tesselate this into a PolySet
CGAL_Nef_polyhedron N;
N.dim = 2;
foreach (AbstractNode * v, node.getChildren()) {
CGAL_Nef_polyhedron sum;
BOOST_FOREACH (AbstractNode * v, node.getChildren()) {
if (v->modinst->tag_background) continue;
N.p2 += this->cgalevaluator.evaluateCGALMesh(*v).p2;
CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(*v);
if (N.dim != 2) {
PRINT("ERROR: rotate_extrude() is not defined for 3D child objects!");
}
else {
if (sum.empty()) sum = N.copy();
else sum += N;
}
}
dxf = new DxfData(N);
if (sum.empty()) return NULL;
dxf = sum.convertToDxfData();
} else {
dxf = new DxfData(node.fn, node.fs, node.fa, node.filename, node.layername, node.origin_x, node.origin_y, node.scale);
}
PolySet *ps = rotateDxfData(node, *dxf);
delete dxf;
return ps;
}
PolySet *PolySetCGALEvaluator::evaluatePolySet(const CgaladvNode &node)
{
CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(node);
PolySet *ps = NULL;
if (!N.empty()) ps = N.convertToPolyset();
return ps;
}
PolySet *PolySetCGALEvaluator::evaluatePolySet(const RenderNode &node)
{
CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(node);
PolySet *ps = NULL;
if (!N.empty()) ps = N.convertToPolyset();
return ps;
}
PolySet *PolySetCGALEvaluator::rotateDxfData(const DxfRotateExtrudeNode &node, DxfData &dxf)
{
PolySet *ps = new PolySet();
ps->convexity = node.convexity;
for (int i = 0; i < dxf->paths.count(); i++)
for (size_t i = 0; i < dxf.paths.size(); i++)
{
double max_x = 0;
for (int j = 0; j < dxf->paths[i].points.count(); j++) {
max_x = fmax(max_x, (*dxf->paths[i].points[j])[0]);
for (size_t j = 0; j < dxf.paths[i].indices.size(); j++) {
max_x = fmax(max_x, dxf.points[dxf.paths[i].indices[j]][0]);
}
int fragments = get_fragments_from_r(max_x, node.fn, node.fs, node.fa);
@ -360,29 +415,29 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const DxfRotateExtrudeNode &node,
double ***points;
points = new double**[fragments];
for (int j=0; j < fragments; j++) {
points[j] = new double*[dxf->paths[i].points.count()];
for (int k=0; k < dxf->paths[i].points.count(); k++)
points[j] = new double*[dxf.paths[i].indices.size()];
for (size_t k=0; k < dxf.paths[i].indices.size(); k++)
points[j][k] = new double[3];
}
for (int j = 0; j < fragments; j++) {
double a = (j*2*M_PI) / fragments;
for (int k = 0; k < dxf->paths[i].points.count(); k++) {
if ((*dxf->paths[i].points[k])[0] == 0) {
for (size_t k = 0; k < dxf.paths[i].indices.size(); k++) {
if (dxf.points[dxf.paths[i].indices[k]][0] == 0) {
points[j][k][0] = 0;
points[j][k][1] = 0;
} else {
points[j][k][0] = (*dxf->paths[i].points[k])[0] * sin(a);
points[j][k][1] = (*dxf->paths[i].points[k])[0] * cos(a);
points[j][k][0] = dxf.points[dxf.paths[i].indices[k]][0] * sin(a);
points[j][k][1] = dxf.points[dxf.paths[i].indices[k]][0] * cos(a);
}
points[j][k][2] = (*dxf->paths[i].points[k])[1];
points[j][k][2] = dxf.points[dxf.paths[i].indices[k]][1];
}
}
for (int j = 0; j < fragments; j++) {
int j1 = j + 1 < fragments ? j + 1 : 0;
for (int k = 0; k < dxf->paths[i].points.count(); k++) {
int k1 = k + 1 < dxf->paths[i].points.count() ? k + 1 : 0;
for (size_t k = 0; k < dxf.paths[i].indices.size(); k++) {
int k1 = k + 1 < dxf.paths[i].indices.size() ? k + 1 : 0;
if (points[j][k][0] != points[j1][k][0] ||
points[j][k][1] != points[j1][k][1] ||
points[j][k][2] != points[j1][k][2]) {
@ -409,15 +464,12 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const DxfRotateExtrudeNode &node,
}
for (int j=0; j < fragments; j++) {
for (int k=0; k < dxf->paths[i].points.count(); k++)
for (size_t k=0; k < dxf.paths[i].indices.size(); k++)
delete[] points[j][k];
delete[] points[j];
}
delete[] points;
}
delete dxf;
this->cache.insert(cacheid, new cache_entry(ps->link()));
return ps;
}

View File

@ -10,14 +10,18 @@
class PolySetCGALEvaluator : public PolySetEvaluator
{
public:
PolySetCGALEvaluator(class CGALEvaluator &CGALEvaluator) :
PolySetEvaluator(), cgalevaluator(CGALEvaluator) { }
PolySetCGALEvaluator(class CGALEvaluator &cgalevaluator);
virtual ~PolySetCGALEvaluator() { }
virtual PolySet *evaluatePolySet(const ProjectionNode &node, AbstractPolyNode::render_mode_e);
virtual PolySet *evaluatePolySet(const DxfLinearExtrudeNode &node, AbstractPolyNode::render_mode_e);
virtual PolySet *evaluatePolySet(const DxfRotateExtrudeNode &node, AbstractPolyNode::render_mode_e);
virtual PolySet *evaluatePolySet(const ProjectionNode &node);
virtual PolySet *evaluatePolySet(const DxfLinearExtrudeNode &node);
virtual PolySet *evaluatePolySet(const DxfRotateExtrudeNode &node);
virtual PolySet *evaluatePolySet(const CgaladvNode &node);
virtual PolySet *evaluatePolySet(const RenderNode &node);
protected:
PolySet *extrudeDxfData(const DxfLinearExtrudeNode &node, class DxfData &dxf);
PolySet *rotateDxfData(const DxfRotateExtrudeNode &node, class DxfData &dxf);
private:
CGALEvaluator &cgalevaluator;
};

21
src/PolySetCache.cc Normal file
View File

@ -0,0 +1,21 @@
#include "PolySetCache.h"
#include "printutils.h"
#include "polyset.h"
PolySetCache *PolySetCache::inst = NULL;
void PolySetCache::insert(const std::string &id, const shared_ptr<PolySet> &ps)
{
this->cache.insert(id, new cache_entry(ps), ps ? ps->polygons.size() : 0);
}
void PolySetCache::print()
{
PRINTF("PolySets in cache: %d", this->cache.size());
PRINTF("Polygons in cache: %d", this->cache.totalCost());
}
PolySetCache::cache_entry::cache_entry(const shared_ptr<PolySet> &ps) : ps(ps)
{
if (print_messages_stack.size() > 0) this->msg = print_messages_stack.last();
}

34
src/PolySetCache.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef POLYSETCACHE_H_
#define POLYSETCACHE_H_
#include "myqhash.h"
#include <QCache>
#include "memory.h"
class PolySetCache
{
public:
PolySetCache(size_t polygonlimit = 100000) : cache(polygonlimit) {}
static PolySetCache *instance() { if (!inst) inst = new PolySetCache; return inst; }
bool contains(const std::string &id) const { return this->cache.contains(id); }
shared_ptr<class PolySet> get(const std::string &id) const { return this->cache[id]->ps; }
void insert(const std::string &id, const shared_ptr<PolySet> &ps);
void clear() { cache.clear(); }
void print();
private:
static PolySetCache *inst;
struct cache_entry {
shared_ptr<class PolySet> ps;
QString msg;
cache_entry(const shared_ptr<PolySet> &ps);
~cache_entry() { }
};
QCache<std::string, cache_entry> cache;
};
#endif

View File

@ -1,15 +1,32 @@
#include "PolySetCache.h"
#include "PolySetEvaluator.h"
#include "printutils.h"
#include "polyset.h"
PolySetEvaluator *PolySetEvaluator::global_evaluator = NULL;
/*!
The task of PolySetEvaluator is to create, keep track of and cache PolySet instances.
PolySetEvaluator::cache_entry::cache_entry(PolySet *ps) :
ps(ps), msg(print_messages_stack.last())
{
}
All instances of PolySet which are not strictly temporary should be requested through this
class.
*/
PolySetEvaluator::cache_entry::~cache_entry()
/*!
Factory method returning a PolySet from the given node. If the
node is already cached, the cached PolySet will be returned
otherwise a new PolySet will be created from the node. If cache is
true, the newly created PolySet will be cached.
*/
shared_ptr<PolySet> PolySetEvaluator::getPolySet(const AbstractNode &node, bool cache)
{
ps->unlink();
std::string cacheid = this->tree.getIdString(node);
if (PolySetCache::instance()->contains(cacheid)) {
// For cache debugging
// PRINTF("Cache hit: %s", cacheid.substr(0, 40).c_str());
return PolySetCache::instance()->get(cacheid);
}
shared_ptr<PolySet> ps(node.evaluate_polyset(this));
if (cache) PolySetCache::instance()->insert(cacheid, ps);
return ps;
}

View File

@ -1,39 +1,28 @@
#ifndef POLYSETEVALUATOR_H_
#define POLYSETEVALUATOR_H_
#include "myqhash.h"
#include "node.h"
#include <QCache>
#include "Tree.h"
#include "memory.h"
class PolySetEvaluator
{
public:
enum EvaluateMode { EVALUATE_CGAL, EVALUATE_OPENCSG };
PolySetEvaluator() : cache(100) {}
PolySetEvaluator(const Tree &tree) : tree(tree) {}
virtual ~PolySetEvaluator() {}
virtual PolySet *evaluatePolySet(const class ProjectionNode &, AbstractPolyNode::render_mode_e) = 0;
virtual PolySet *evaluatePolySet(const class DxfLinearExtrudeNode &, AbstractPolyNode::render_mode_e) = 0;
virtual PolySet *evaluatePolySet(const class DxfRotateExtrudeNode &, AbstractPolyNode::render_mode_e) = 0;
const Tree &getTree() const { return this->tree; }
void clearCache() {
this->cache.clear();
}
virtual shared_ptr<PolySet> getPolySet(const class AbstractNode &, bool cache);
protected:
struct cache_entry {
class PolySet *ps;
QString msg;
cache_entry(PolySet *ps);
~cache_entry();
};
QCache<std::string, cache_entry> cache;
virtual PolySet *evaluatePolySet(const class ProjectionNode &) { return NULL; }
virtual PolySet *evaluatePolySet(const class DxfLinearExtrudeNode &) { return NULL; }
virtual PolySet *evaluatePolySet(const class DxfRotateExtrudeNode &) { return NULL; }
virtual PolySet *evaluatePolySet(const class CgaladvNode &) { return NULL; }
virtual PolySet *evaluatePolySet(const class RenderNode &) { return NULL; }
private:
static PolySetEvaluator *global_evaluator;
const Tree &tree;
};
#endif

View File

@ -62,10 +62,11 @@ void ThrownTogetherRenderer::renderCSGChain(CSGChain *chain, bool highlight,
{
glDepthFunc(GL_LEQUAL);
QHash<QPair<PolySet*,double*>,int> polySetVisitMark;
for (int i = 0; i < chain->polysets.size(); i++) {
if (polySetVisitMark[QPair<PolySet*,double*>(chain->polysets[i], chain->matrices[i])]++ > 0)
for (size_t i = 0; i < chain->polysets.size(); i++) {
if (polySetVisitMark[QPair<PolySet*,double*>(chain->polysets[i].get(), chain->matrices[i])]++ > 0)
continue;
double *m = chain->matrices[i];
double *c = chain->colors[i];
glPushMatrix();
glMultMatrixd(m);
int csgmode = chain->types[i] == CSGTerm::TYPE_DIFFERENCE ? PolySet::CSGMODE_DIFFERENCE : PolySet::CSGMODE_NORMAL;
@ -91,12 +92,12 @@ void ThrownTogetherRenderer::renderCSGChain(CSGChain *chain, bool highlight,
} else {
chain->polysets[i]->render_surface(PolySet::COLORMODE_NONE, PolySet::csgmode_e(csgmode), m);
}
} else if (m[16] >= 0 || m[17] >= 0 || m[18] >= 0) {
glColor4d(m[16], m[17], m[18], m[19]);
} else if (c[0] >= 0 || c[1] >= 0 || c[2] >= 0) {
glColor4dv(c);
chain->polysets[i]->render_surface(PolySet::COLORMODE_NONE, PolySet::csgmode_e(csgmode), m);
if (showedges) {
glDisable(GL_LIGHTING);
glColor4d((m[16]+1)/2, (m[17]+1)/2, (m[18]+1)/2, 1.0);
glColor4d((c[0]+1)/2, (c[1]+1)/2, (c[2]+1)/2, 1.0);
chain->polysets[i]->render_edges(PolySet::COLORMODE_NONE, PolySet::csgmode_e(csgmode));
glEnable(GL_LIGHTING);
}

View File

@ -2,15 +2,18 @@
#include "nodedumper.h"
#include <assert.h>
#include <algorithm>
/*!
Returns the cached string representation of the subtree rootet by \a node.
Returns the cached string representation of the subtree rooted by \a node.
If node is not cached, the cache will be rebuilt.
*/
const std::string &Tree::getString(const AbstractNode &node) const
{
assert(this->root_node);
if (!this->nodecache.contains(node)) {
this->nodecache.clear();
this->nodeidcache.clear();
NodeDumper dumper(this->nodecache, false);
Traverser trav(dumper, *this->root_node, Traverser::PRE_AND_POSTFIX);
trav.execute();
@ -20,6 +23,30 @@ const std::string &Tree::getString(const AbstractNode &node) const
return this->nodecache[node];
}
static bool filter(char c)
{
return c == ' ' || c == '\n' || c == '\t' || c == '\r';
}
/*!
Returns the cached ID string representation of the subtree rooted by \a node.
If node is not cached, the cache will be rebuilt.
The difference between this method and getString() is that the ID string
is stripped for whitespace. Especially indentation whitespace is important to
strip to enable cache hits for equivalent nodes from different scopes.
*/
const std::string &Tree::getIdString(const AbstractNode &node) const
{
assert(this->root_node);
if (!this->nodeidcache.contains(node)) {
std::string str = getString(node);
str.erase(std::remove_if(str.begin(), str.end(), filter), str.end());
return this->nodeidcache.insert(node, str);
}
return this->nodeidcache[node];
}
/*!
Sets a new root. Will clear the existing cache.
*/

View File

@ -20,12 +20,13 @@ public:
void setRoot(const AbstractNode *root);
const AbstractNode *root() const { return this->root_node; }
// FIXME: Really return a reference?
const string &getString(const AbstractNode &node) const;
const string &getIdString(const AbstractNode &node) const;
private:
const AbstractNode *root_node;
mutable NodeCache nodecache;
mutable NodeCache nodeidcache;
};
#endif

View File

@ -1,18 +1,20 @@
#ifndef BUILTIN_H_
#define BUILTIN_H_
#include <QHash>
#include <string>
#include <boost/unordered_map.hpp>
extern QHash<QString, class AbstractFunction*> builtin_functions;
extern boost::unordered_map<std::string, class AbstractFunction*> builtin_functions;
extern void initialize_builtin_functions();
extern void destroy_builtin_functions();
extern QHash<QString, class AbstractModule*> builtin_modules;
extern boost::unordered_map<std::string, class AbstractModule*> builtin_modules;
extern void initialize_builtin_modules();
extern void destroy_builtin_modules();
extern void register_builtin_csgops();
extern void register_builtin_transform();
extern void register_builtin_color();
extern void register_builtin_primitives();
extern void register_builtin_surface();
extern void register_builtin_control();

View File

@ -1,46 +0,0 @@
#include "cgal.h"
#include "polyset.h"
/*!
Creates a new PolySet and initializes it with the data from this polyhedron
This method is not const since convert_to_Polyhedron() wasn't const
in earlier versions of CGAL.
*/
PolySet *CGAL_Nef_polyhedron::convertToPolyset()
{
PolySet *ps = new PolySet();
CGAL_Polyhedron P;
this->p3.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;
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());
ps->append_poly();
ps->append_vertex(x1, y1, z1);
ps->append_vertex(x2, y2, z2);
ps->append_vertex(x3, y3, z3);
} while (hc != hc_end);
}
return ps;
}

View File

@ -14,89 +14,22 @@
#include <CGAL/Polygon_2.h>
#include <CGAL/Polygon_with_holes_2.h>
typedef CGAL::Extended_cartesian<CGAL::Gmpq> CGAL_Kernel2;
typedef CGAL::Gmpq NT;
typedef CGAL::Extended_cartesian<NT> CGAL_Kernel2;
typedef CGAL::Nef_polyhedron_2<CGAL_Kernel2> CGAL_Nef_polyhedron2;
typedef CGAL_Kernel2::Aff_transformation_2 CGAL_Aff_transformation2;
typedef CGAL::Cartesian<CGAL::Gmpq> CGAL_Kernel3;
typedef CGAL::Polyhedron_3<CGAL_Kernel3> CGAL_Polyhedron;
typedef CGAL_Polyhedron::HalfedgeDS CGAL_HDS;
typedef CGAL::Polyhedron_incremental_builder_3<CGAL_HDS> CGAL_Polybuilder;
typedef CGAL::Nef_polyhedron_3<CGAL_Kernel3> CGAL_Nef_polyhedron3;
typedef CGAL_Nef_polyhedron3::Aff_transformation_3 CGAL_Aff_transformation;
typedef CGAL_Nef_polyhedron3::Vector_3 CGAL_Vector;
typedef CGAL_Nef_polyhedron3::Plane_3 CGAL_Plane;
typedef CGAL_Nef_polyhedron3::Point_3 CGAL_Point;
typedef CGAL::Exact_predicates_exact_constructions_kernel CGAL_ExactKernel2;
typedef CGAL::Polygon_2<CGAL_ExactKernel2> CGAL_Poly2;
typedef CGAL::Polygon_with_holes_2<CGAL_ExactKernel2> CGAL_Poly2h;
struct CGAL_Nef_polyhedron
{
int dim;
CGAL_Nef_polyhedron2 p2;
CGAL_Nef_polyhedron3 p3;
typedef CGAL::Cartesian<NT> CGAL_Kernel3;
typedef CGAL::Nef_polyhedron_3<CGAL_Kernel3> CGAL_Nef_polyhedron3;
typedef CGAL_Nef_polyhedron3::Aff_transformation_3 CGAL_Aff_transformation;
CGAL_Nef_polyhedron() {
dim = 0;
}
CGAL_Nef_polyhedron(const CGAL_Nef_polyhedron2 &p) {
dim = 2;
p2 = p;
}
CGAL_Nef_polyhedron(const CGAL_Nef_polyhedron3 &p) {
dim = 3;
p3 = p;
}
CGAL_Nef_polyhedron& operator+=(const CGAL_Nef_polyhedron &other) {
if (other.dim == 2) {
this->p2 += other.p2;
this->dim = 2;
}
if (other.dim == 3) {
this->p3 += other.p3;
this->dim = 3;
}
return *this;
}
CGAL_Nef_polyhedron& operator*=(const CGAL_Nef_polyhedron &other) {
if (other.dim == 2) {
this->p2 *= other.p2;
this->dim = 2;
}
if (other.dim == 3) {
this->p3 *= other.p3;
this->dim = 3;
}
return *this;
}
CGAL_Nef_polyhedron& operator-=(const CGAL_Nef_polyhedron &other) {
if (other.dim == 2) {
this->p2 -= other.p2;
this->dim = 2;
}
if (other.dim == 3) {
this->p3 -= other.p3;
this->dim = 3;
}
return *this;
}
int weight() {
if (dim == 2)
return p2.explorer().number_of_vertices();
if (dim == 3)
return p3.number_of_vertices();
return 0;
}
class PolySet *convertToPolyset();
};
typedef CGAL::Polyhedron_3<CGAL_Kernel3> CGAL_Polyhedron;
typedef CGAL_Polyhedron::HalfedgeDS CGAL_HDS;
typedef CGAL::Polyhedron_incremental_builder_3<CGAL_HDS> CGAL_Polybuilder;
#endif /* ENABLE_CGAL */

View File

@ -24,28 +24,16 @@
*
*/
#include "cgaladvnode.h"
#include "module.h"
#include "node.h"
#include "context.h"
#include "builtin.h"
#include "printutils.h"
#include "cgal.h"
#include "visitor.h"
#include "PolySetEvaluator.h"
#include <sstream>
#include <assert.h>
#ifdef ENABLE_CGAL
extern CGAL_Nef_polyhedron3 minkowski3(CGAL_Nef_polyhedron3 a, CGAL_Nef_polyhedron3 b);
extern CGAL_Nef_polyhedron2 minkowski2(CGAL_Nef_polyhedron2 a, CGAL_Nef_polyhedron2 b);
extern CGAL_Nef_polyhedron2 convexhull2(std::list<CGAL_Nef_polyhedron2> a);
#endif
enum cgaladv_type_e {
MINKOWSKI,
GLIDE,
SUBDIV,
HULL
};
#include <boost/assign/std/vector.hpp>
using namespace boost::assign; // bring 'operator+=()' into scope
class CgaladvModule : public AbstractModule
{
@ -55,57 +43,21 @@ public:
virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
};
class CgaladvNode : public AbstractNode
{
public:
CgaladvNode(const ModuleInstantiation *mi, cgaladv_type_e type) : AbstractNode(mi), type(type) {
convexity = 1;
}
virtual ~CgaladvNode() { }
virtual Response accept(class State &state, Visitor &visitor) const {
return visitor.visit(state, *this);
}
virtual std::string toString() const;
virtual std::string name() const {
switch (this->type) {
case MINKOWSKI:
return "minkowski";
break;
case GLIDE:
return "glide";
break;
case SUBDIV:
return "subdiv";
break;
case HULL:
return "hull";
break;
default:
assert(false);
}
}
Value path;
std::string subdiv_type;
int convexity, level;
cgaladv_type_e type;
};
AbstractNode *CgaladvModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
{
CgaladvNode *node = new CgaladvNode(inst, type);
QVector<QString> argnames;
QVector<Expression*> argexpr;
std::vector<std::string> argnames;
std::vector<Expression*> argexpr;
if (type == MINKOWSKI)
argnames = QVector<QString>() << "convexity";
argnames += "convexity";
if (type == GLIDE)
argnames = QVector<QString>() << "path" << "convexity";
argnames += "path", "convexity";
if (type == SUBDIV)
argnames = QVector<QString>() << "type" << "level" << "convexity";
argnames += "type", "level", "convexity";
Context c(ctx);
c.args(argnames, argexpr, inst->argnames, inst->argvalues);
@ -135,15 +87,17 @@ AbstractNode *CgaladvModule::evaluate(const Context *ctx, const ModuleInstantiat
if (node->level <= 1)
node->level = 1;
foreach (ModuleInstantiation *v, inst->children) {
AbstractNode *n = v->evaluate(inst->ctx);
if (n)
node->children.push_back(n);
}
std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren();
node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
return node;
}
PolySet *CgaladvNode::evaluate_polyset(PolySetEvaluator *ps) const
{
return ps->evaluatePolySet(*this);
}
void register_builtin_cgaladv()
{
builtin_modules["minkowski"] = new CgaladvModule(MINKOWSKI);
@ -152,6 +106,26 @@ void register_builtin_cgaladv()
builtin_modules["hull"] = new CgaladvModule(HULL);
}
std::string CgaladvNode::name() const
{
switch (this->type) {
case MINKOWSKI:
return "minkowski";
break;
case GLIDE:
return "glide";
break;
case SUBDIV:
return "subdiv";
break;
case HULL:
return "hull";
break;
default:
assert(false);
}
}
std::string CgaladvNode::toString() const
{
std::stringstream stream;

View File

@ -29,16 +29,15 @@
#include "cgal.h"
#include <CGAL/convex_hull_2.h>
extern CGAL_Nef_polyhedron2 convexhull2(std::list<CGAL_Nef_polyhedron2> a);
extern CGAL_Poly2 nef2p2(CGAL_Nef_polyhedron2 p);
CGAL_Nef_polyhedron2 convexhull2(std::list<CGAL_Nef_polyhedron2> a)
CGAL_Nef_polyhedron2 *convexhull2(std::list<CGAL_Nef_polyhedron2*> a)
{
std::list<CGAL_Nef_polyhedron2::Point> points;
std::list<CGAL_Nef_polyhedron2>::iterator i;
std::list<CGAL_Nef_polyhedron2*>::iterator i;
for (i=a.begin(); i!=a.end(); i++) {
CGAL_Poly2 ap=nef2p2(*i);
CGAL_Poly2 ap=nef2p2(**i);
for (size_t j=0;j<ap.size();j++) {
double x=to_double(ap[j].x()),y=to_double(ap[j].y());
CGAL_Nef_polyhedron2::Point p=CGAL_Nef_polyhedron2::Point(x,y);
@ -49,7 +48,7 @@ CGAL_Nef_polyhedron2 convexhull2(std::list<CGAL_Nef_polyhedron2> a)
std::list<CGAL_Nef_polyhedron2::Point> result;
CGAL::convex_hull_2(points.begin(),points.end(),std::back_inserter(result));
return CGAL_Nef_polyhedron2(result.begin(),result.end(),CGAL_Nef_polyhedron2::INCLUDED);
return new CGAL_Nef_polyhedron2(result.begin(),result.end(),CGAL_Nef_polyhedron2::INCLUDED);
}
#endif

View File

@ -34,7 +34,6 @@
#include <CGAL/minkowski_sum_2.h>
extern CGAL_Nef_polyhedron2 minkowski2(CGAL_Nef_polyhedron2 a, CGAL_Nef_polyhedron2 b);
extern CGAL_Poly2 nef2p2(CGAL_Nef_polyhedron2 p);
//-----------------------------------------------------------------------------
@ -120,7 +119,7 @@ static CGAL_Nef_polyhedron2 p2nef2(CGAL_Poly2 p2) {
return CGAL_Nef_polyhedron2(points.begin(), points.end(), CGAL_Nef_polyhedron2::INCLUDED);
}
CGAL_Nef_polyhedron2 minkowski2(CGAL_Nef_polyhedron2 a, CGAL_Nef_polyhedron2 b)
CGAL_Nef_polyhedron2 minkowski2(const CGAL_Nef_polyhedron2 &a, const CGAL_Nef_polyhedron2 &b)
{
CGAL_Poly2 ap = nef2p2(a), bp = nef2p2(b);

View File

@ -1,39 +0,0 @@
/*
* 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
*
*/
#ifdef ENABLE_CGAL
#include "cgal.h"
#include <CGAL/minkowski_sum_3.h>
extern CGAL_Nef_polyhedron3 minkowski3(CGAL_Nef_polyhedron3 a, CGAL_Nef_polyhedron3 b);
CGAL_Nef_polyhedron3 minkowski3(CGAL_Nef_polyhedron3 a, CGAL_Nef_polyhedron3 b)
{
return CGAL::minkowski_sum_3(a, b);
}
#endif

35
src/cgaladvnode.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef CGALADVNODE_H_
#define CGALADVNODE_H_
#include "node.h"
#include "visitor.h"
#include "value.h"
enum cgaladv_type_e {
MINKOWSKI,
GLIDE,
SUBDIV,
HULL
};
class CgaladvNode : public AbstractNode
{
public:
CgaladvNode(const ModuleInstantiation *mi, cgaladv_type_e type) : AbstractNode(mi), type(type) {
convexity = 1;
}
virtual ~CgaladvNode() { }
virtual Response accept(class State &state, Visitor &visitor) const {
return visitor.visit(state, *this);
}
virtual std::string toString() const;
virtual std::string name() const;
PolySet *evaluate_polyset(class PolySetEvaluator *ps) const;
Value path;
std::string subdiv_type;
int convexity, level;
cgaladv_type_e type;
};
#endif

45
src/cgalfwd.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef CGALFWD_H_
#define CGALFWD_H_
#ifndef CGAL_FORWARD
#include "cgal.h"
#else
#ifdef ENABLE_CGAL
#include <memory>
namespace CGAL {
class Gmpq;
template <class T> class Extended_cartesian;
class HDS_items;
template <class A, typename Items_, typename Mark_> class Nef_polyhedron_2;
}
typedef CGAL::Gmpq NT;
typedef CGAL::Extended_cartesian<NT> CGAL_Kernel2;
typedef CGAL::Nef_polyhedron_2<CGAL_Kernel2, CGAL::HDS_items, bool> CGAL_Nef_polyhedron2;
namespace CGAL {
template <class T> class Cartesian;
template<class T> struct Default_items;
class SNC_indexed_items;
template <typename Kernel_, typename Items_, typename Mark_> class Nef_polyhedron_3;
}
typedef CGAL::Cartesian<NT> CGAL_Kernel3;
typedef CGAL::Nef_polyhedron_3<CGAL_Kernel3, CGAL::SNC_indexed_items, bool> CGAL_Nef_polyhedron3;
namespace CGAL {
#ifndef CGAL_ALLOCATOR
# define CGAL_ALLOCATOR(T) std::allocator< T >
#endif
class HalfedgeDS_items_2;
template <class Traits_, class HalfedgeDSItems, class Alloc> class HalfedgeDS_default;
class Polyhedron_items_3;
template <class PolyhedronTraits_3, class PolyhedronItems_3, class T_HDS, class Alloc> class Polyhedron_3;
}
typedef CGAL::Polyhedron_3<CGAL_Kernel3, CGAL::Polyhedron_items_3, CGAL::HalfedgeDS_default<CGAL_Kernel3, CGAL::HalfedgeDS_items_2, CGAL_ALLOCATOR(int)>, CGAL_ALLOCATOR(int)> CGAL_Polyhedron;
#endif /* ENABLE_CGAL */
#endif
#endif

147
src/cgalutils.cc Normal file
View File

@ -0,0 +1,147 @@
#ifdef ENABLE_CGAL
#include "cgalutils.h"
#include "polyset.h"
#include "printutils.h"
#include "cgal.h"
#include <CGAL/assertions_behaviour.h>
#include <CGAL/exceptions.h>
PolySet *createPolySetFromPolyhedron(const CGAL_Polyhedron &p)
{
PolySet *ps = new PolySet();
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;
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());
ps->append_poly();
ps->append_vertex(x1, y1, z1);
ps->append_vertex(x2, y2, z2);
ps->append_vertex(x3, y3, z3);
} while (hc != hc_end);
}
return ps;
}
#undef GEN_SURFACE_DEBUG
class CGAL_Build_PolySet : public CGAL::Modifier_base<CGAL_HDS>
{
public:
typedef CGAL_HDS::Vertex::Point CGALPoint;
const PolySet &ps;
CGAL_Build_PolySet(const PolySet &ps) : ps(ps) { }
void operator()(CGAL_HDS& hds)
{
CGAL_Polybuilder B(hds, true);
std::vector<CGALPoint> vertices;
Grid3d<int> vertices_idx(GRID_FINE);
for (size_t i = 0; i < ps.polygons.size(); i++) {
const PolySet::Polygon *poly = &ps.polygons[i];
for (size_t j = 0; j < poly->size(); j++) {
const Vector3d &p = poly->at(j);
if (!vertices_idx.has(p[0], p[1], p[2])) {
vertices_idx.data(p[0], p[1], p[2]) = vertices.size();
vertices.push_back(CGALPoint(p[0], p[1], p[2]));
}
}
}
B.begin_surface(vertices.size(), ps.polygons.size());
#ifdef GEN_SURFACE_DEBUG
printf("=== CGAL Surface ===\n");
#endif
for (size_t i = 0; i < vertices.size(); i++) {
const CGALPoint &p = vertices[i];
B.add_vertex(p);
#ifdef GEN_SURFACE_DEBUG
printf("%d: %f %f %f\n", i, p[0], p[1], p[2]);
#endif
}
for (size_t i = 0; i < ps.polygons.size(); i++) {
const PolySet::Polygon *poly = &ps.polygons[i];
QHash<int,int> fc;
bool facet_is_degenerated = false;
for (size_t j = 0; j < poly->size(); j++) {
const Vector3d &p = poly->at(j);
int v = vertices_idx.data(p[0], p[1], p[2]);
if (fc[v]++ > 0)
facet_is_degenerated = true;
}
if (!facet_is_degenerated)
B.begin_facet();
#ifdef GEN_SURFACE_DEBUG
printf("F:");
#endif
for (size_t j = 0; j < poly->size(); j++) {
const Vector3d &p = poly->at(j);
#ifdef GEN_SURFACE_DEBUG
printf(" %d (%f,%f,%f)", vertices_idx.data(p[0], p[1], p[2]), p[0], p[1], p[2]);
#endif
if (!facet_is_degenerated)
B.add_vertex_to_facet(vertices_idx.data(p[0], p[1], p[2]));
}
#ifdef GEN_SURFACE_DEBUG
if (facet_is_degenerated)
printf(" (degenerated)");
printf("\n");
#endif
if (!facet_is_degenerated)
B.end_facet();
}
#ifdef GEN_SURFACE_DEBUG
printf("====================\n");
#endif
B.end_surface();
#undef PointKey
}
};
CGAL_Polyhedron *createPolyhedronFromPolySet(const PolySet &ps)
{
CGAL_Polyhedron *P = NULL;
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
try {
P = new CGAL_Polyhedron;
CGAL_Build_PolySet builder(ps);
P->delegate(builder);
}
catch (CGAL::Assertion_exception e) {
PRINTF("CGAL error in CGAL_Build_PolySet: %s", e.what());
CGAL::set_error_behaviour(old_behaviour);
}
return P;
}
#endif /* ENABLE_CGAL */

9
src/cgalutils.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef CGALUTILS_H_
#define CGALUTILS_H_
#include <cgalfwd.h>
class PolySet *createPolySetFromPolyhedron(const CGAL_Polyhedron &p);
CGAL_Polyhedron *createPolyhedronFromPolySet(const class PolySet &ps);
#endif

108
src/color.cc Normal file
View File

@ -0,0 +1,108 @@
/*
* 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 "colornode.h"
#include "module.h"
#include "context.h"
#include "builtin.h"
#include "printutils.h"
#include "visitor.h"
#include <sstream>
#include <assert.h>
#include <QColor>
#include <boost/assign/std/vector.hpp>
using namespace boost::assign; // bring 'operator+=()' into scope
class ColorModule : public AbstractModule
{
public:
ColorModule() { }
virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
};
using std::string;
AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
{
ColorNode *node = new ColorNode(inst);
node->color[0] = node->color[1] = node->color[2] = -1.0;
node->color[3] = 1.0;
std::vector<std::string> argnames;
std::vector<Expression*> argexpr;
argnames += "c", "alpha";
Context c(ctx);
c.args(argnames, argexpr, inst->argnames, inst->argvalues);
Value v = c.lookup_variable("c");
if (v.type == Value::VECTOR) {
for (size_t i = 0; i < 4; i++)
node->color[i] = i < v.vec.size() ? v.vec[i]->num : 1.0;
} else if (v.type == Value::STRING) {
std::string colorname = v.text;
QColor color;
color.setNamedColor(QString::fromStdString(colorname));
if (color.isValid()) {
node->color[0] = color.redF();
node->color[1] = color.greenF();
node->color[2] = color.blueF();
} else {
PRINTF_NOCACHE("WARNING: Color name \"%s\" unknown. Please see", colorname.c_str());
PRINTF_NOCACHE("WARNING: http://en.wikipedia.org/wiki/Web_colors");
}
}
Value alpha = c.lookup_variable("alpha");
if (alpha.type == Value::NUMBER) {
node->color[3] = alpha.num;
}
std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren();
node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
return node;
}
string ColorNode::toString() const
{
std::stringstream stream;
stream << "color([" << this->color[0] << ", " << this->color[1] << ", " << this->color[2] << ", " << this->color[3] << "])";
return stream.str();
}
string ColorNode::name() const
{
return "color";
}
void register_builtin_color()
{
builtin_modules["color"] = new ColorModule();
}

20
src/colornode.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef COLORNODE_H_
#define COLORNODE_H_
#include "node.h"
#include "visitor.h"
class ColorNode : public AbstractNode
{
public:
ColorNode(const ModuleInstantiation *mi) : AbstractNode(mi) { }
virtual Response accept(class State &state, Visitor &visitor) const {
return visitor.visit(state, *this);
}
virtual std::string toString() const;
virtual std::string name() const;
double color[4];
};
#endif

View File

@ -28,19 +28,36 @@
#include "expression.h"
#include "function.h"
#include "module.h"
#include "builtin.h"
#include "printutils.h"
#include <QFileInfo>
#include <QDir>
#include <boost/foreach.hpp>
Context::Context(const Context *parent)
std::vector<const Context*> Context::ctx_stack;
/*!
Initializes this context. Optionally initializes a context for an external library
*/
Context::Context(const Context *parent, const Module *library)
: parent(parent), inst_p(NULL)
{
this->parent = parent;
functions_p = NULL;
modules_p = NULL;
usedlibs_p = NULL;
inst_p = NULL;
ctx_stack.push_back(this);
if (parent) document_path = parent->document_path;
ctx_stack.append(this);
if (library) {
this->functions_p = &library->functions;
this->modules_p = &library->modules;
this->usedlibs_p = &library->usedlibs;
for (size_t j = 0; j < library->assignments_var.size(); j++) {
this->set_variable(library->assignments_var[j],
library->assignments_expr[j]->evaluate(this));
}
}
else {
functions_p = NULL;
modules_p = NULL;
usedlibs_p = NULL;
}
}
Context::~Context()
@ -48,16 +65,22 @@ Context::~Context()
ctx_stack.pop_back();
}
void Context::args(const QVector<QString> &argnames, const QVector<Expression*> &argexpr,
const QVector<QString> &call_argnames, const QVector<Value> &call_argvalues)
/*!
Initialize context from argument lists (function call/module instantiation)
*/
void Context::args(const std::vector<std::string> &argnames,
const std::vector<Expression*> &argexpr,
const std::vector<std::string> &call_argnames,
const std::vector<Value> &call_argvalues)
{
for (int i=0; i<argnames.size(); i++) {
set_variable(argnames[i], i < argexpr.size() && argexpr[i] ? argexpr[i]->evaluate(this->parent) : Value());
for (size_t i=0; i<argnames.size(); i++) {
set_variable(argnames[i], i < argexpr.size() && argexpr[i] ?
argexpr[i]->evaluate(this->parent) : Value());
}
int posarg = 0;
for (int i=0; i<call_argnames.size(); i++) {
if (call_argnames[i].isEmpty()) {
size_t posarg = 0;
for (size_t i=0; i<call_argnames.size(); i++) {
if (call_argnames[i].empty()) {
if (posarg < argnames.size())
set_variable(argnames[posarg++], call_argvalues[i]);
} else {
@ -66,108 +89,107 @@ void Context::args(const QVector<QString> &argnames, const QVector<Expression*>
}
}
QVector<const Context*> Context::ctx_stack;
void Context::set_variable(QString name, Value value)
void Context::set_variable(const std::string &name, const Value &value)
{
if (name.startsWith("$"))
config_variables[name] = value;
if (name[0] == '$')
this->config_variables[name] = value;
else
variables[name] = value;
this->variables[name] = value;
}
Value Context::lookup_variable(QString name, bool silent) const
void Context::set_constant(const std::string &name, const Value &value)
{
if (name.startsWith("$")) {
if (this->constants.find(name) != this->constants.end())
PRINTF("WARNING: Attempt to modify constant '%s'.",name.c_str());
else
this->constants[name] = value;
}
Value Context::lookup_variable(const std::string &name, bool silent) const
{
if (name[0] == '$') {
for (int i = ctx_stack.size()-1; i >= 0; i--) {
if (ctx_stack[i]->config_variables.contains(name))
return ctx_stack[i]->config_variables[name];
const ValueMap &confvars = ctx_stack[i]->config_variables;
if (confvars.find(name) != confvars.end())
return confvars.find(name)->second;
}
return Value();
}
if (!parent && constants.contains(name))
return constants[name];
if (variables.contains(name))
return variables[name];
if (parent)
return parent->lookup_variable(name, silent);
if (!this->parent && this->constants.find(name) != this->constants.end())
return this->constants.find(name)->second;
if (this->variables.find(name) != this->variables.end())
return this->variables.find(name)->second;
if (this->parent)
return this->parent->lookup_variable(name, silent);
if (!silent)
PRINTA("WARNING: Ignoring unknown variable '%1'.", name);
PRINTF("WARNING: Ignoring unknown variable '%s'.", name.c_str());
return Value();
}
void Context::set_constant(QString name, Value value)
Value Context::evaluate_function(const std::string &name,
const std::vector<std::string> &argnames,
const std::vector<Value> &argvalues) const
{
if (constants.contains(name))
PRINTA("WARNING: Attempt to modify constant '%1'.",name);
else
constants.insert(name,value);
}
Value Context::evaluate_function(QString name, const QVector<QString> &argnames, const QVector<Value> &argvalues) const
{
if (functions_p && functions_p->contains(name))
return functions_p->value(name)->evaluate(this, argnames, argvalues);
if (usedlibs_p) {
QHashIterator<QString, Module*> i(*usedlibs_p);
while (i.hasNext()) {
i.next();
if (i.value()->functions.contains(name)) {
Module *lib = i.value();
Context ctx(parent);
ctx.functions_p = &lib->functions;
ctx.modules_p = &lib->modules;
ctx.usedlibs_p = &lib->usedlibs;
for (int j = 0; j < lib->assignments_var.size(); j++) {
ctx.set_variable(lib->assignments_var[j], lib->assignments_expr[j]->evaluate(&ctx));
}
return i.value()->functions.value(name)->evaluate(&ctx, argnames, argvalues);
if (this->functions_p && this->functions_p->find(name) != this->functions_p->end())
return this->functions_p->find(name)->second->evaluate(this, argnames, argvalues);
if (this->usedlibs_p) {
BOOST_FOREACH(const ModuleContainer::value_type &m, *this->usedlibs_p) {
if (m.second->functions.find(name) != m.second->functions.end()) {
Context ctx(this->parent, m.second);
return m.second->functions[name]->evaluate(&ctx, argnames, argvalues);
}
}
}
if (parent)
return parent->evaluate_function(name, argnames, argvalues);
PRINTA("WARNING: Ignoring unkown function '%1'.", name);
if (this->parent)
return this->parent->evaluate_function(name, argnames, argvalues);
PRINTF("WARNING: Ignoring unknown function '%s'.", name.c_str());
return Value();
}
AbstractNode *Context::evaluate_module(const ModuleInstantiation *inst) const
AbstractNode *Context::evaluate_module(const ModuleInstantiation &inst) const
{
if (modules_p && modules_p->contains(inst->modname))
return modules_p->value(inst->modname)->evaluate(this, inst);
if (usedlibs_p) {
QHashIterator<QString, Module*> i(*usedlibs_p);
while (i.hasNext()) {
i.next();
if (i.value()->modules.contains(inst->modname)) {
Module *lib = i.value();
Context ctx(parent);
ctx.functions_p = &lib->functions;
ctx.modules_p = &lib->modules;
ctx.usedlibs_p = &lib->usedlibs;
for (int j = 0; j < lib->assignments_var.size(); j++) {
ctx.set_variable(lib->assignments_var[j], lib->assignments_expr[j]->evaluate(&ctx));
}
return i.value()->modules.value(inst->modname)->evaluate(&ctx, inst);
if (this->modules_p && this->modules_p->find(inst.modname) != this->modules_p->end()) {
AbstractModule *m = this->modules_p->find(inst.modname)->second;
if (m == builtin_modules["dxf_linear_extrude"]) {
PRINTF("DEPRECATED: The dxf_linear_extrude() module will be removed in future releases. Use a linear_extrude() instead.");
}
else if (m == builtin_modules["dxf_rotate_extrude"]) {
PRINTF("DEPRECATED: The dxf_rotate_extrude() module will be removed in future releases. Use a rotate_extrude() instead.");
}
else if (m == builtin_modules["import_stl"]) {
PRINTF("DEPRECATED: The import_stl() module will be removed in future releases. Use import() instead.");
}
else if (m == builtin_modules["import_dxf"]) {
PRINTF("DEPRECATED: The import_dxf() module will be removed in future releases. Use import() instead.");
}
else if (m == builtin_modules["import_off"]) {
PRINTF("DEPRECATED: The import_off() module will be removed in future releases. Use import() instead.");
}
return m->evaluate(this, &inst);
}
if (this->usedlibs_p) {
BOOST_FOREACH(const ModuleContainer::value_type &m, *this->usedlibs_p) {
if (m.second->modules.find(inst.modname) != m.second->modules.end()) {
Context ctx(this->parent, m.second);
return m.second->modules[inst.modname]->evaluate(&ctx, &inst);
}
}
}
if (parent)
return parent->evaluate_module(inst);
PRINTA("WARNING: Ignoring unkown module '%1'.", inst->modname);
if (this->parent) return this->parent->evaluate_module(inst);
PRINTF("WARNING: Ignoring unknown module '%s'.", inst.modname.c_str());
return NULL;
}
/*!
Returns the absolute path to the given filename, unless it's empty.
*/
QString Context::get_absolute_path(const QString &filename) const
std::string Context::getAbsolutePath(const std::string &filename) const
{
if (!filename.isEmpty()) {
return QFileInfo(QDir(this->document_path), filename).absoluteFilePath();
if (!filename.empty()) {
return QFileInfo(QDir(QString::fromStdString(this->document_path)),
QString::fromStdString(filename)).absoluteFilePath().toStdString();
}
else {
return filename;
}
}

View File

@ -1,39 +1,52 @@
#ifndef CONTEXT_H_
#define CONTEXT_H_
#include <QHash>
#include <QString>
#include <string>
#include <vector>
#include <boost/unordered_map.hpp>
#include "value.h"
using boost::unordered_map;
class Context
{
public:
const Context *parent;
QHash<QString, Value> constants;
QHash<QString, Value> variables;
QHash<QString, Value> config_variables;
const QHash<QString, class AbstractFunction*> *functions_p;
const QHash<QString, class AbstractModule*> *modules_p;
const QHash<QString, class Module*> *usedlibs_p;
const class ModuleInstantiation *inst_p;
QString document_path;
static QVector<const Context*> ctx_stack;
Context(const Context *parent = NULL);
Context(const Context *parent = NULL, const class Module *library = NULL);
~Context();
void args(const QVector<QString> &argnames, const QVector<class Expression*> &argexpr, const QVector<QString> &call_argnames, const QVector<Value> &call_argvalues);
void args(const std::vector<std::string> &argnames,
const std::vector<class Expression*> &argexpr,
const std::vector<std::string> &call_argnames,
const std::vector<Value> &call_argvalues);
void set_variable(QString name, Value value);
Value lookup_variable(QString name, bool silent = false) const;
void set_variable(const std::string &name, const Value &value);
void set_constant(const std::string &name, const Value &value);
void set_constant(QString name, Value value);
Value lookup_variable(const std::string &name, bool silent = false) const;
Value evaluate_function(const std::string &name,
const std::vector<std::string> &argnames,
const std::vector<Value> &argvalues) const;
class AbstractNode *evaluate_module(const class ModuleInstantiation &inst) const;
QString get_absolute_path(const QString &filename) const;
void setDocumentPath(const std::string &path) { this->document_path = path; }
std::string getAbsolutePath(const std::string &filename) const;
Value evaluate_function(QString name, const QVector<QString> &argnames, const QVector<Value> &argvalues) const;
class AbstractNode *evaluate_module(const ModuleInstantiation *inst) const;
public:
const Context *parent;
const unordered_map<std::string, class AbstractFunction*> *functions_p;
const unordered_map<std::string, class AbstractModule*> *modules_p;
typedef unordered_map<std::string, class Module*> ModuleContainer;
const ModuleContainer *usedlibs_p;
const ModuleInstantiation *inst_p;
static std::vector<const Context*> ctx_stack;
private:
typedef unordered_map<std::string, Value> ValueMap;
ValueMap constants;
ValueMap variables;
ValueMap config_variables;
std::string document_path;
};
#endif

View File

@ -29,6 +29,7 @@
#include "context.h"
#include "builtin.h"
#include "printutils.h"
#include <sstream>
enum control_type_e {
CHILD,
@ -47,11 +48,14 @@ public:
virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
};
void for_eval(AbstractNode *node, int l, const QVector<QString> &call_argnames, const QVector<Value> &call_argvalues, const QVector<ModuleInstantiation*> arg_children, const Context *arg_context)
void for_eval(AbstractNode &node, const ModuleInstantiation &inst, size_t l,
const std::vector<std::string> &call_argnames,
const std::vector<Value> &call_argvalues,
const Context *arg_context)
{
if (call_argnames.size() > l) {
QString it_name = call_argnames[l];
Value it_values = call_argvalues[l];
const std::string &it_name = call_argnames[l];
const Value &it_values = call_argvalues[l];
Context c(arg_context);
if (it_values.type == Value::RANGE) {
double range_begin = it_values.range_begin;
@ -65,25 +69,23 @@ void for_eval(AbstractNode *node, int l, const QVector<QString> &call_argnames,
if (range_step > 0 && (range_begin-range_end)/range_step < 10000) {
for (double i = range_begin; i <= range_end; i += range_step) {
c.set_variable(it_name, Value(i));
for_eval(node, l+1, call_argnames, call_argvalues, arg_children, &c);
for_eval(node, inst, l+1, call_argnames, call_argvalues, &c);
}
}
}
else if (it_values.type == Value::VECTOR) {
for (int i = 0; i < it_values.vec.size(); i++) {
for (size_t i = 0; i < it_values.vec.size(); i++) {
c.set_variable(it_name, *it_values.vec[i]);
for_eval(node, l+1, call_argnames, call_argvalues, arg_children, &c);
for_eval(node, inst, l+1, call_argnames, call_argvalues, &c);
}
}
else {
for_eval(node, l+1, call_argnames, call_argvalues, arg_children, &c);
}
} else {
foreach (ModuleInstantiation *v, arg_children) {
AbstractNode *n = v->evaluate(arg_context);
if (n != NULL)
node->children.push_back(n);
else if (it_values.type != Value::UNDEFINED) {
c.set_variable(it_name, it_values);
for_eval(node, inst, l+1, call_argnames, call_argvalues, &c);
}
} else if (l > 0) {
std::vector<AbstractNode *> evaluatednodes = inst.evaluateChildren(arg_context);
node.children.insert(node.children.end(), evaluatednodes.begin(), evaluatednodes.end());
}
}
@ -91,7 +93,7 @@ AbstractNode *ControlModule::evaluate(const Context*, const ModuleInstantiation
{
if (type == CHILD)
{
int n = 0;
size_t n = 0;
if (inst->argvalues.size() > 0) {
double v;
if (inst->argvalues[0].getnum(v))
@ -118,52 +120,42 @@ AbstractNode *ControlModule::evaluate(const Context*, const ModuleInstantiation
if (type == ECHO)
{
QString msg = QString("ECHO: ");
for (int i = 0; i < inst->argnames.size(); i++) {
if (i > 0)
msg += QString(", ");
if (!inst->argnames[i].isEmpty())
msg += inst->argnames[i] + QString(" = ");
msg += QString::fromStdString(inst->argvalues[i].toString());
std::stringstream msg;
msg << "ECHO: ";
for (size_t i = 0; i < inst->argnames.size(); i++) {
if (i > 0) msg << ", ";
if (!inst->argnames[i].empty()) msg << inst->argnames[i] << " = ";
msg << inst->argvalues[i];
}
PRINT(msg);
PRINTF("%s", msg.str().c_str());
}
if (type == ASSIGN)
{
Context c(inst->ctx);
for (int i = 0; i < inst->argnames.size(); i++) {
if (!inst->argnames[i].isEmpty())
for (size_t i = 0; i < inst->argnames.size(); i++) {
if (!inst->argnames[i].empty())
c.set_variable(inst->argnames[i], inst->argvalues[i]);
}
foreach (ModuleInstantiation *v, inst->children) {
AbstractNode *n = v->evaluate(&c);
if (n != NULL)
node->children.push_back(n);
}
std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(&c);
node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
}
if (type == FOR || type == INT_FOR)
{
for_eval(node, 0, inst->argnames, inst->argvalues, inst->children, inst->ctx);
for_eval(*node, *inst, 0, inst->argnames, inst->argvalues, inst->ctx);
}
if (type == IF)
{
const IfElseModuleInstantiation *ifelse = dynamic_cast<const IfElseModuleInstantiation*>(inst);
if (ifelse->argvalues.size() > 0 && ifelse->argvalues[0].type == Value::BOOL && ifelse->argvalues[0].b) {
foreach (ModuleInstantiation *v, ifelse->children) {
AbstractNode *n = v->evaluate(ifelse->ctx);
if (n != NULL)
node->children.push_back(n);
}
if (ifelse->argvalues.size() > 0 && ifelse->argvalues[0].toBool()) {
std::vector<AbstractNode *> evaluatednodes = ifelse->evaluateChildren();
node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
}
else {
foreach (ModuleInstantiation *v, ifelse->else_children) {
AbstractNode *n = v->evaluate(ifelse->ctx);
if (n != NULL)
node->children.push_back(n);
}
std::vector<AbstractNode *> evaluatednodes = ifelse->evaluateElseChildren();
node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
}
}

View File

@ -44,11 +44,8 @@ public:
AbstractNode *CsgModule::evaluate(const Context*, const ModuleInstantiation *inst) const
{
CsgNode *node = new CsgNode(inst, type);
foreach (ModuleInstantiation *v, inst->children) {
AbstractNode *n = v->evaluate(inst->ctx);
if (n != NULL)
node->children.push_back(n);
}
std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren();
node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
return node;
}

View File

@ -26,6 +26,7 @@
#include "csgterm.h"
#include "polyset.h"
#include <sstream>
/*!
\class CSGTerm
@ -46,24 +47,17 @@
*/
CSGTerm::CSGTerm(PolySet *polyset, const double m[20], QString label)
CSGTerm::CSGTerm(const shared_ptr<PolySet> &polyset, const double matrix[16], const double color[4], const std::string &label)
: type(TYPE_PRIMITIVE), polyset(polyset), label(label), left(NULL), right(NULL)
{
this->type = TYPE_PRIMITIVE;
this->polyset = polyset;
this->label = label;
this->left = NULL;
this->right = NULL;
for (int i = 0; i < 20; i++)
this->m[i] = m[i];
for (int i = 0; i < 16; i++) this->m[i] = matrix[i];
for (int i = 0; i < 4; i++) this->color[i] = color[i];
refcounter = 1;
}
CSGTerm::CSGTerm(type_e type, CSGTerm *left, CSGTerm *right)
: type(type), left(left), right(right)
{
this->type = type;
this->polyset = NULL;
this->left = left;
this->right = right;
refcounter = 1;
}
@ -166,8 +160,6 @@ CSGTerm *CSGTerm::link()
void CSGTerm::unlink()
{
if (--refcounter <= 0) {
if (polyset)
polyset->unlink();
if (left)
left->unlink();
if (right)
@ -176,57 +168,63 @@ void CSGTerm::unlink()
}
}
QString CSGTerm::dump()
std::string CSGTerm::dump()
{
std::stringstream dump;
if (type == TYPE_UNION)
return QString("(%1 + %2)").arg(left->dump(), right->dump());
if (type == TYPE_INTERSECTION)
return QString("(%1 * %2)").arg(left->dump(), right->dump());
if (type == TYPE_DIFFERENCE)
return QString("(%1 - %2)").arg(left->dump(), right->dump());
return label;
dump << "(" << left->dump() << " + " << right->dump() << ")";
else if (type == TYPE_INTERSECTION)
dump << "(" << left->dump() << " * " << right->dump() << ")";
else if (type == TYPE_DIFFERENCE)
dump << "(" << left->dump() << " - " << right->dump() << ")";
else
dump << this->label;
return dump.str();
}
CSGChain::CSGChain()
{
}
void CSGChain::add(PolySet *polyset, double *m, CSGTerm::type_e type, QString label)
void CSGChain::add(const shared_ptr<PolySet> &polyset, double *m, double *color, CSGTerm::type_e type, std::string label)
{
polysets.append(polyset);
matrices.append(m);
types.append(type);
labels.append(label);
polysets.push_back(polyset);
matrices.push_back(m);
colors.push_back(color);
types.push_back(type);
labels.push_back(label);
}
void CSGChain::import(CSGTerm *term, CSGTerm::type_e type)
{
if (term->type == CSGTerm::TYPE_PRIMITIVE) {
add(term->polyset, term->m, type, term->label);
add(term->polyset, term->m, term->color, type, term->label);
} else {
import(term->left, type);
import(term->right, term->type);
}
}
QString CSGChain::dump()
std::string CSGChain::dump()
{
QString text;
for (int i = 0; i < types.size(); i++)
std::stringstream dump;
for (size_t i = 0; i < types.size(); i++)
{
if (types[i] == CSGTerm::TYPE_UNION) {
if (i != 0)
text += "\n";
text += "+";
if (i != 0) dump << "\n";
dump << "+";
}
else if (types[i] == CSGTerm::TYPE_DIFFERENCE)
text += " -";
dump << " -";
else if (types[i] == CSGTerm::TYPE_INTERSECTION)
text += " *";
text += labels[i];
dump << " *";
dump << labels[i];
}
text += "\n";
return text;
dump << "\n";
return dump.str();
}
BoundingBox CSGChain::getBoundingBox() const
@ -234,7 +232,18 @@ BoundingBox CSGChain::getBoundingBox() const
BoundingBox bbox;
for (size_t i=0;i<polysets.size();i++) {
if (types[i] != CSGTerm::TYPE_DIFFERENCE) {
bbox.extend(polysets[i]->getBoundingBox());
BoundingBox psbox = polysets[i]->getBoundingBox();
if (!psbox.isNull()) {
Eigen::Transform3d t;
// Column-major vs. Row-major
t.matrix() <<
matrices[i][0], matrices[i][4], matrices[i][8], matrices[i][12],
matrices[i][1], matrices[i][5], matrices[i][9], matrices[i][13],
matrices[i][2], matrices[i][6], matrices[i][10], matrices[i][14],
matrices[i][3], matrices[i][7], matrices[i][11], matrices[i][15];
bbox.extend(t * psbox.min());
bbox.extend(t * psbox.max());
}
}
}
return bbox;

View File

@ -1,9 +1,10 @@
#ifndef CSGTERM_H_
#define CSGTERM_H_
#include <QString>
#include <QVector>
#include <string>
#include <vector>
#include "polyset.h"
#include "memory.h"
class CSGTerm
{
@ -16,14 +17,15 @@ public:
};
type_e type;
PolySet *polyset;
QString label;
shared_ptr<PolySet> polyset;
std::string label;
CSGTerm *left;
CSGTerm *right;
double m[20];
double m[16];
double color[4];
int refcounter;
CSGTerm(PolySet *polyset, const double m[20], QString label);
CSGTerm(const shared_ptr<PolySet> &polyset, const double matrix[16], const double color[4], const std::string &label);
CSGTerm(type_e type, CSGTerm *left, CSGTerm *right);
CSGTerm *normalize();
@ -31,22 +33,23 @@ public:
CSGTerm *link();
void unlink();
QString dump();
std::string dump();
};
class CSGChain
{
public:
QVector<PolySet*> polysets;
QVector<double*> matrices;
QVector<CSGTerm::type_e> types;
QVector<QString> labels;
std::vector<shared_ptr<PolySet> > polysets;
std::vector<double*> matrices;
std::vector<double*> colors;
std::vector<CSGTerm::type_e> types;
std::vector<std::string> labels;
CSGChain();
void add(PolySet *polyset, double *m, CSGTerm::type_e type, QString label);
void add(const shared_ptr<PolySet> &polyset, double *m, double *color, CSGTerm::type_e type, std::string label);
void import(CSGTerm *term, CSGTerm::type_e type = CSGTerm::TYPE_UNION);
QString dump();
std::string dump();
BoundingBox getBoundingBox() const;
};

View File

@ -24,23 +24,25 @@
*
*/
#include "myqhash.h"
#include "dxfdata.h"
#include "grid.h"
#include "printutils.h"
#include "openscad.h" // handle_dep()
#include "handle_dep.h"
#include "openscad.h" // get_fragments_from_r()
#include <QFile>
#include <QTextStream>
#include <QHash>
#include <QVector>
#include "mathc99.h"
#include <assert.h>
#include <boost/unordered_map.hpp>
#include <boost/foreach.hpp>
#include <algorithm>
struct Line {
Vector2d *p[2];
int idx[2]; // indices into DxfData::points
bool disabled;
Line(Vector2d *p1, Vector2d *p2) { p[0] = p1; p[1] = p2; disabled = false; }
Line() { p[0] = NULL; p[1] = NULL; disabled = false; }
Line(int i1 = -1, int i2 = -1) { idx[0] = i1; idx[1] = i2; disabled = false; }
};
DxfData::DxfData()
@ -48,51 +50,53 @@ DxfData::DxfData()
}
/*!
Reads a layer from the given file, or all layers if layename.isNull()
Reads a layer from the given file, or all layers if layername.empty()
*/
DxfData::DxfData(double fn, double fs, double fa, QString filename, QString layername, double xorigin, double yorigin, double scale)
DxfData::DxfData(double fn, double fs, double fa,
const std::string &filename, const std::string &layername,
double xorigin, double yorigin, double scale)
{
handle_dep(filename); // Register ourselves as a dependency
QFile f(filename);
QFile f(QString::fromStdString(filename));
if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) {
PRINTF("WARNING: Can't open DXF file `%s'.", filename.toUtf8().data());
PRINTF("WARNING: Can't open DXF file `%s'.", filename.c_str());
return;
}
QTextStream stream(&f);
Grid2d< QVector<int> > grid(GRID_COARSE);
QList<Line> lines; // Global lines
QHash< QString, QList<Line> > blockdata; // Lines in blocks
Grid2d< std::vector<int> > grid(GRID_COARSE);
std::vector<Line> lines; // Global lines
boost::unordered_map< std::string, std::vector<Line> > blockdata; // Lines in blocks
bool in_entities_section = false;
bool in_blocks_section = false;
QString current_block;
std::string current_block;
#define ADD_LINE(_x1, _y1, _x2, _y2) do { \
double _p1x = _x1, _p1y = _y1, _p2x = _x2, _p2y = _y2; \
if (!in_entities_section && !in_blocks_section) \
break; \
if (in_entities_section && \
!(layername.isNull() || layername == layer)) \
!(layername.empty() || layername == layer)) \
break; \
grid.align(_p1x, _p1y); \
grid.align(_p2x, _p2y); \
grid.data(_p1x, _p1y).append(lines.count()); \
grid.data(_p2x, _p2y).append(lines.count()); \
grid.data(_p1x, _p1y).push_back(lines.size()); \
grid.data(_p2x, _p2y).push_back(lines.size()); \
if (in_entities_section) \
lines.append( \
lines.push_back( \
Line(addPoint(_p1x, _p1y), addPoint(_p2x, _p2y))); \
if (in_blocks_section && !current_block.isNull()) \
blockdata[current_block].append( \
if (in_blocks_section && !current_block.empty()) \
blockdata[current_block].push_back( \
Line(addPoint(_p1x, _p1y), addPoint(_p2x, _p2y))); \
} while (0)
QString mode, layer, name, iddata;
std::string mode, layer, name, iddata;
int dimtype = 0;
double coords[7][2]; // Used by DIMENSION entities
QVector<double> xverts;
QVector<double> yverts;
std::vector<double> xverts;
std::vector<double> yverts;
double radius = 0;
double arc_start_angle = 0, arc_stop_angle = 0;
double ellipse_start_angle = 0, ellipse_stop_angle = 0;
@ -101,8 +105,8 @@ DxfData::DxfData(double fn, double fs, double fa, QString filename, QString laye
for (int j = 0; j < 2; j++)
coords[i][j] = 0;
QHash<QString, int> unsupported_entities_list;
typedef boost::unordered_map<std::string, int> EntityList;
EntityList unsupported_entities_list;
//
// Parse DXF file. Will populate this->points, this->dims, lines and blockdata
@ -116,7 +120,7 @@ DxfData::DxfData(double fn, double fs, double fa, QString filename, QString laye
int id = id_str.toInt(&status);
if (!status) {
PRINTA("WARNING: Illegal ID `%1' in `%3'.", id_str, filename);
PRINTF("WARNING: Illegal ID `%s' in `%s'.", id_str.toUtf8().data(), filename.c_str());
break;
}
@ -237,10 +241,10 @@ DxfData::DxfData(double fn, double fs, double fa, QString filename, QString laye
int n = blockdata[iddata].size();
for (int i = 0; i < n; i++) {
double a = arc_start_angle * M_PI / 180.0;
double lx1 = (*blockdata[iddata][i].p[0])[0] * ellipse_start_angle;
double ly1 = (*blockdata[iddata][i].p[0])[1] * ellipse_stop_angle;
double lx2 = (*blockdata[iddata][i].p[1])[0] * ellipse_start_angle;
double ly2 = (*blockdata[iddata][i].p[1])[1] * ellipse_stop_angle;
double lx1 = this->points[blockdata[iddata][i].idx[0]][0] * ellipse_start_angle;
double ly1 = this->points[blockdata[iddata][i].idx[0]][1] * ellipse_stop_angle;
double lx2 = this->points[blockdata[iddata][i].idx[1]][0] * ellipse_start_angle;
double ly2 = this->points[blockdata[iddata][i].idx[1]][1] * ellipse_stop_angle;
double px1 = (cos(a)*lx1 - sin(a)*ly1) * scale + xverts[0];
double py1 = (sin(a)*lx1 + cos(a)*ly1) * scale + yverts[0];
double px2 = (cos(a)*lx2 - sin(a)*ly2) * scale + xverts[0];
@ -249,32 +253,32 @@ DxfData::DxfData(double fn, double fs, double fa, QString filename, QString laye
}
}
else if (mode == "DIMENSION" &&
(layername.isNull() || layername == layer)) {
this->dims.append(Dim());
this->dims.last().type = dimtype;
(layername.empty() || layername == layer)) {
this->dims.push_back(Dim());
this->dims.back().type = dimtype;
for (int i = 0; i < 7; i++)
for (int j = 0; j < 2; j++)
this->dims.last().coords[i][j] = coords[i][j];
this->dims.last().angle = arc_start_angle;
this->dims.last().length = radius;
this->dims.last().name = name;
this->dims.back().coords[i][j] = coords[i][j];
this->dims.back().angle = arc_start_angle;
this->dims.back().length = radius;
this->dims.back().name = name;
}
else if (mode == "BLOCK") {
current_block = iddata;
}
else if (mode == "ENDBLK") {
current_block = QString();
current_block.erase();
}
else if (mode == "ENDSEC") {
}
else if (in_blocks_section || (in_entities_section &&
(layername.isNull() || layername == layer))) {
(layername.empty() || layername == layer))) {
unsupported_entities_list[mode]++;
}
mode = data;
layer = QString();
name = QString();
iddata = QString();
mode = data.toStdString();
layer.erase();
name.erase();
iddata.erase();
dimtype = 0;
for (int i = 0; i < 7; i++)
for (int j = 0; j < 2; j++)
@ -288,37 +292,37 @@ DxfData::DxfData(double fn, double fs, double fa, QString filename, QString laye
}
break;
case 1:
name = data;
name = data.toStdString();
break;
case 2:
iddata = data;
iddata = data.toStdString();
break;
case 8:
layer = data;
layer = data.toStdString();
break;
case 10:
if (in_blocks_section)
xverts.append((data.toDouble()));
xverts.push_back((data.toDouble()));
else
xverts.append((data.toDouble() - xorigin) * scale);
xverts.push_back((data.toDouble() - xorigin) * scale);
break;
case 11:
if (in_blocks_section)
xverts.append((data.toDouble()));
xverts.push_back((data.toDouble()));
else
xverts.append((data.toDouble() - xorigin) * scale);
xverts.push_back((data.toDouble() - xorigin) * scale);
break;
case 20:
if (in_blocks_section)
yverts.append((data.toDouble()));
yverts.push_back((data.toDouble()));
else
yverts.append((data.toDouble() - yorigin) * scale);
yverts.push_back((data.toDouble() - yorigin) * scale);
break;
case 21:
if (in_blocks_section)
yverts.append((data.toDouble()));
yverts.push_back((data.toDouble()));
else
yverts.append((data.toDouble() - yorigin) * scale);
yverts.push_back((data.toDouble() - yorigin) * scale);
break;
case 40:
// CIRCLE, ARC: radius
@ -354,40 +358,40 @@ DxfData::DxfData(double fn, double fs, double fa, QString filename, QString laye
}
}
QHashIterator<QString, int> i(unsupported_entities_list);
while (i.hasNext()) {
i.next();
if (layername.isNull()) {
PRINTA("WARNING: Unsupported DXF Entity `%1' (%2x) in `%3'.",
i.key(), QString::number(i.value()), filename);
BOOST_FOREACH(const EntityList::value_type &i, unsupported_entities_list) {
if (layername.empty()) {
PRINTF("WARNING: Unsupported DXF Entity `%s' (%x) in `%s'.",
i.first.c_str(), i.second, filename.c_str());
} else {
PRINTA("WARNING: Unsupported DXF Entity `%1' (%2x) in layer `%3' of `%4'.",
i.key(), QString::number(i.value()), layername, filename);
PRINTF("WARNING: Unsupported DXF Entity `%s' (%x) in layer `%s' of `%s'.",
i.first.c_str(), i.second, layername.c_str(), filename.c_str());
}
}
// Extract paths from parsed data
QHash<int, int> enabled_lines;
for (int i = 0; i < lines.count(); i++) {
typedef boost::unordered_map<int, int> LineMap;
LineMap enabled_lines;
for (size_t i = 0; i < lines.size(); i++) {
enabled_lines[i] = i;
}
// extract all open paths
while (enabled_lines.count() > 0)
while (enabled_lines.size() > 0)
{
int current_line, current_point;
foreach (int i, enabled_lines) {
BOOST_FOREACH(const LineMap::value_type &l, enabled_lines) {
int idx = l.second;
for (int j = 0; j < 2; j++) {
QVector<int> *lv = &grid.data((*lines[i].p[j])[0], (*lines[i].p[j])[1]);
for (int ki = 0; ki < lv->count(); ki++) {
std::vector<int> *lv = &grid.data(this->points[lines[idx].idx[j]][0], this->points[lines[idx].idx[j]][1]);
for (size_t ki = 0; ki < lv->size(); ki++) {
int k = lv->at(ki);
if (k == i || lines[k].disabled)
if (k == idx || lines[k].disabled)
continue;
goto next_open_path_j;
}
current_line = i;
current_line = idx;
current_point = j;
goto create_open_path;
next_open_path_j:;
@ -397,26 +401,26 @@ DxfData::DxfData(double fn, double fs, double fa, QString filename, QString laye
break;
create_open_path:
this->paths.append(Path());
Path *this_path = &this->paths.last();
this->paths.push_back(Path());
Path *this_path = &this->paths.back();
this_path->points.append(lines[current_line].p[current_point]);
this_path->indices.push_back(lines[current_line].idx[current_point]);
while (1) {
this_path->points.append(lines[current_line].p[!current_point]);
const Vector2d &ref_point = *lines[current_line].p[!current_point];
this_path->indices.push_back(lines[current_line].idx[!current_point]);
const Vector2d &ref_point = this->points[lines[current_line].idx[!current_point]];
lines[current_line].disabled = true;
enabled_lines.remove(current_line);
QVector<int> *lv = &grid.data(ref_point[0], ref_point[1]);
for (int ki = 0; ki < lv->count(); ki++) {
enabled_lines.erase(current_line);
std::vector<int> *lv = &grid.data(ref_point[0], ref_point[1]);
for (size_t ki = 0; ki < lv->size(); ki++) {
int k = lv->at(ki);
if (lines[k].disabled)
continue;
if (grid.eq(ref_point[0], ref_point[1], (*lines[k].p[0])[0], (*lines[k].p[0])[1])) {
if (grid.eq(ref_point[0], ref_point[1], this->points[lines[k].idx[0]][0], this->points[lines[k].idx[0]][1])) {
current_line = k;
current_point = 0;
goto found_next_line_in_open_path;
}
if (grid.eq(ref_point[0], ref_point[1], (*lines[k].p[1])[0], (*lines[k].p[1])[1])) {
if (grid.eq(ref_point[0], ref_point[1], this->points[lines[k].idx[1]][0], this->points[lines[k].idx[1]][1])) {
current_line = k;
current_point = 1;
goto found_next_line_in_open_path;
@ -428,31 +432,31 @@ DxfData::DxfData(double fn, double fs, double fa, QString filename, QString laye
}
// extract all closed paths
while (enabled_lines.count() > 0)
while (enabled_lines.size() > 0)
{
int current_line = enabled_lines.begin().value(), current_point = 0;
int current_line = enabled_lines.begin()->second, current_point = 0;
this->paths.append(Path());
Path *this_path = &this->paths.last();
this->paths.push_back(Path());
Path *this_path = &this->paths.back();
this_path->is_closed = true;
this_path->points.append(lines[current_line].p[current_point]);
this_path->indices.push_back(lines[current_line].idx[current_point]);
while (1) {
this_path->points.append(lines[current_line].p[!current_point]);
const Vector2d &ref_point = *lines[current_line].p[!current_point];
this_path->indices.push_back(lines[current_line].idx[!current_point]);
const Vector2d &ref_point = this->points[lines[current_line].idx[!current_point]];
lines[current_line].disabled = true;
enabled_lines.remove(current_line);
QVector<int> *lv = &grid.data(ref_point[0], ref_point[1]);
for (int ki = 0; ki < lv->count(); ki++) {
enabled_lines.erase(current_line);
std::vector<int> *lv = &grid.data(ref_point[0], ref_point[1]);
for (size_t ki = 0; ki < lv->size(); ki++) {
int k = lv->at(ki);
if (lines[k].disabled)
continue;
if (grid.eq(ref_point[0], ref_point[1], (*lines[k].p[0])[0], (*lines[k].p[0])[1])) {
if (grid.eq(ref_point[0], ref_point[1], this->points[lines[k].idx[0]][0], this->points[lines[k].idx[0]][1])) {
current_line = k;
current_point = 0;
goto found_next_line_in_closed_path;
}
if (grid.eq(ref_point[0], ref_point[1], (*lines[k].p[1])[0], (*lines[k].p[1])[1])) {
if (grid.eq(ref_point[0], ref_point[1], this->points[lines[k].idx[1]][0], this->points[lines[k].idx[1]][1])) {
current_line = k;
current_point = 1;
goto found_next_line_in_closed_path;
@ -467,9 +471,9 @@ DxfData::DxfData(double fn, double fs, double fa, QString filename, QString laye
#if 0
printf("----- DXF Data -----\n");
for (int i = 0; i < this->paths.count(); i++) {
for (int i = 0; i < this->paths.size(); i++) {
printf("Path %d (%s):\n", i, this->paths[i].is_closed ? "closed" : "open");
for (int j = 0; j < this->paths[i].points.count(); j++)
for (int j = 0; j < this->paths[i].points.size(); j++)
printf(" %f %f\n", (*this->paths[i].points[j])[0], (*this->paths[i].points[j])[1]);
}
printf("--------------------\n");
@ -483,26 +487,26 @@ DxfData::DxfData(double fn, double fs, double fa, QString filename, QString laye
*/
void DxfData::fixup_path_direction()
{
for (int i = 0; i < this->paths.count(); i++) {
for (size_t i = 0; i < this->paths.size(); i++) {
if (!this->paths[i].is_closed)
break;
this->paths[i].is_inner = true;
double min_x = (*this->paths[i].points[0])[0];
double min_x = this->points[this->paths[i].indices[0]][0];
int min_x_point = 0;
for (int j = 1; j < this->paths[i].points.count(); j++) {
if ((*this->paths[i].points[j])[0] < min_x) {
min_x = (*this->paths[i].points[j])[0];
for (size_t j = 1; j < this->paths[i].indices.size(); j++) {
if (this->points[this->paths[i].indices[j]][0] < min_x) {
min_x = this->points[this->paths[i].indices[j]][0];
min_x_point = j;
}
}
// rotate points if the path is in non-standard rotation
int b = min_x_point;
int a = b == 0 ? this->paths[i].points.count() - 2 : b - 1;
int c = b == this->paths[i].points.count() - 1 ? 1 : b + 1;
double ax = (*this->paths[i].points[a])[0] - (*this->paths[i].points[b])[0];
double ay = (*this->paths[i].points[a])[1] - (*this->paths[i].points[b])[1];
double cx = (*this->paths[i].points[c])[0] - (*this->paths[i].points[b])[0];
double cy = (*this->paths[i].points[c])[1] - (*this->paths[i].points[b])[1];
int a = b == 0 ? this->paths[i].indices.size() - 2 : b - 1;
int c = b == this->paths[i].indices.size() - 1 ? 1 : b + 1;
double ax = this->points[this->paths[i].indices[a]][0] - this->points[this->paths[i].indices[b]][0];
double ay = this->points[this->paths[i].indices[a]][1] - this->points[this->paths[i].indices[b]][1];
double cx = this->points[this->paths[i].indices[c]][0] - this->points[this->paths[i].indices[b]][0];
double cy = this->points[this->paths[i].indices[c]][1] - this->points[this->paths[i].indices[b]][1];
#if 0
printf("Rotate check:\n");
printf(" a/b/c indices = %d %d %d\n", a, b, c);
@ -511,15 +515,17 @@ void DxfData::fixup_path_direction()
#endif
// FIXME: atan2() usually takes y,x. This variant probably makes the path clockwise..
if (atan2(ax, ay) < atan2(cx, cy)) {
for (int j = 0; j < this->paths[i].points.count()/2; j++)
this->paths[i].points.swap(j, this->paths[i].points.count()-1-j);
std::reverse(this->paths[i].indices.begin(), this->paths[i].indices.end());
}
}
}
Vector2d *DxfData::addPoint(double x, double y)
/*!
Adds a vertex and returns the index into DxfData::points
*/
int DxfData::addPoint(double x, double y)
{
this->points.append(Vector2d(x, y));
return &this->points.last();
this->points.push_back(Vector2d(x, y));
return this->points.size()-1;
}

View File

@ -1,8 +1,7 @@
#ifndef DXFDATA_H_
#define DXFDATA_H_
#include <QList>
#include <QString>
#include <vector>
#include <Eigen/Dense>
using Eigen::Vector2d;
@ -11,7 +10,7 @@ class DxfData
{
public:
struct Path {
QList<Vector2d*> points;
std::vector<int> indices; // indices into DxfData::points
bool is_closed, is_inner;
Path() : is_closed(false), is_inner(false) { }
};
@ -20,7 +19,7 @@ public:
double coords[7][2];
double angle;
double length;
QString name;
std::string name;
Dim() {
for (int i = 0; i < 7; i++)
for (int j = 0; j < 2; j++)
@ -31,19 +30,17 @@ public:
}
};
QList<Vector2d> points;
QList<Path> paths;
QList<Dim> dims;
std::vector<Vector2d> points;
std::vector<Path> paths;
std::vector<Dim> dims;
DxfData();
DxfData(double fn, double fs, double fa, QString filename, QString layername = QString(), double xorigin = 0.0, double yorigin = 0.0, double scale = 1.0);
#ifdef ENABLE_CGAL
DxfData(const struct CGAL_Nef_polyhedron &N);
#endif
DxfData(double fn, double fs, double fa,
const std::string &filename, const std::string &layername = "",
double xorigin = 0.0, double yorigin = 0.0, double scale = 1.0);
Vector2d *addPoint(double x, double y);
int addPoint(double x, double y);
private:
void fixup_path_direction();
};

View File

@ -33,48 +33,50 @@
#include "context.h"
#include "mathc99.h"
#include <QHash>
#include <QDateTime>
#include <QFileInfo>
#include <sstream>
QHash<QString,Value> dxf_dim_cache;
QHash<QString,Value> dxf_cross_cache;
boost::unordered_map<std::string,Value> dxf_dim_cache;
boost::unordered_map<std::string,Value> dxf_cross_cache;
Value builtin_dxf_dim(const Context *ctx, const QVector<QString> &argnames, const QVector<Value> &args)
Value builtin_dxf_dim(const Context *ctx, const std::vector<std::string> &argnames, const std::vector<Value> &args)
{
QString filename;
QString layername;
QString name;
std::string filename;
std::string layername;
std::string name;
double xorigin = 0;
double yorigin = 0;
double scale = 1;
for (int i = 0; i < argnames.count() && i < args.count(); i++) {
for (size_t i = 0; i < argnames.size() && i < args.size(); i++) {
if (argnames[i] == "file")
filename = ctx->get_absolute_path(QString::fromStdString(args[i].text));
filename = ctx->getAbsolutePath(args[i].text);
if (argnames[i] == "layer")
layername = QString::fromStdString(args[i].text);
layername = args[i].text;
if (argnames[i] == "origin")
args[i].getv2(xorigin, yorigin);
if (argnames[i] == "scale")
args[i].getnum(scale);
if (argnames[i] == "name")
name = QString::fromStdString(args[i].text);
name = args[i].text;
}
QFileInfo fileInfo(filename);
QFileInfo fileInfo(QString::fromStdString(filename));
QString key = filename + "|" + layername + "|" + name + "|" + QString::number(xorigin) + "|" + QString::number(yorigin) +
"|" + QString::number(scale) + "|" + QString::number(fileInfo.lastModified().toTime_t()) + "|" + QString::number(fileInfo.size());
if (dxf_dim_cache.contains(key))
return dxf_dim_cache[key];
std::stringstream keystream;
keystream << filename << "|" << layername << "|" << name << "|" << xorigin
<< "|" << yorigin <<"|" << scale << "|" << fileInfo.lastModified().toTime_t()
<< "|" << fileInfo.size();
std::string key = keystream.str();
if (dxf_dim_cache.find(key) != dxf_dim_cache.end())
return dxf_dim_cache.find(key)->second;
DxfData dxf(36, 0, 0, filename, layername, xorigin, yorigin, scale);
for (int i = 0; i < dxf.dims.count(); i++)
for (size_t i = 0; i < dxf.dims.size(); i++)
{
if (!name.isNull() && dxf.dims[i].name != name)
if (!name.empty() && dxf.dims[i].name != name)
continue;
DxfData::Dim *d = &dxf.dims[i];
@ -114,53 +116,56 @@ Value builtin_dxf_dim(const Context *ctx, const QVector<QString> &argnames, cons
return dxf_dim_cache[key] = Value((d->type & 64) ? d->coords[3][0] : d->coords[3][1]);
}
PRINTA("WARNING: Dimension `%1' in `%2', layer `%3' has unsupported type!", name, filename, layername);
PRINTF("WARNING: Dimension `%s' in `%s', layer `%s' has unsupported type!", name.c_str(), filename.c_str(), layername.c_str());
return Value();
}
PRINTA("WARNING: Can't find dimension `%1' in `%2', layer `%3'!", name, filename, layername);
PRINTF("WARNING: Can't find dimension `%s' in `%s', layer `%s'!", name.c_str(), filename.c_str(), layername.c_str());
return Value();
}
Value builtin_dxf_cross(const Context *ctx, const QVector<QString> &argnames, const QVector<Value> &args)
Value builtin_dxf_cross(const Context *ctx, const std::vector<std::string> &argnames, const std::vector<Value> &args)
{
QString filename;
QString layername;
std::string filename;
std::string layername;
double xorigin = 0;
double yorigin = 0;
double scale = 1;
for (int i = 0; i < argnames.count() && i < args.count(); i++) {
for (size_t i = 0; i < argnames.size() && i < args.size(); i++) {
if (argnames[i] == "file")
filename = ctx->get_absolute_path(QString::fromStdString(args[i].text));
filename = ctx->getAbsolutePath(args[i].text);
if (argnames[i] == "layer")
layername = QString::fromStdString(args[i].text);
layername = args[i].text;
if (argnames[i] == "origin")
args[i].getv2(xorigin, yorigin);
if (argnames[i] == "scale")
args[i].getnum(scale);
}
QFileInfo fileInfo(filename);
QFileInfo fileInfo(QString::fromStdString(filename));
QString key = filename + "|" + layername + "|" + QString::number(xorigin) + "|" + QString::number(yorigin) +
"|" + QString::number(scale) + "|" + QString::number(fileInfo.lastModified().toTime_t()) + "|" + QString::number(fileInfo.size());
std::stringstream keystream;
keystream << filename << "|" << layername << "|" << xorigin << "|" << yorigin
<< "|" << scale << "|" << fileInfo.lastModified().toTime_t()
<< "|" << fileInfo.size();
std::string key = keystream.str();
if (dxf_cross_cache.contains(key))
return dxf_cross_cache[key];
if (dxf_cross_cache.find(key) != dxf_cross_cache.end())
return dxf_cross_cache.find(key)->second;
DxfData dxf(36, 0, 0, filename, layername, xorigin, yorigin, scale);
double coords[4][2];
for (int i = 0, j = 0; i < dxf.paths.count(); i++) {
if (dxf.paths[i].points.count() != 2)
for (size_t i = 0, j = 0; i < dxf.paths.size(); i++) {
if (dxf.paths[i].indices.size() != 2)
continue;
coords[j][0] = (*dxf.paths[i].points[0])[0];
coords[j++][1] = (*dxf.paths[i].points[0])[1];
coords[j][0] = (*dxf.paths[i].points[1])[0];
coords[j++][1] = (*dxf.paths[i].points[1])[1];
coords[j][0] = dxf.points[dxf.paths[i].indices[0]][0];
coords[j++][1] = dxf.points[dxf.paths[i].indices[0]][1];
coords[j][0] = dxf.points[dxf.paths[i].indices[1]][0];
coords[j++][1] = dxf.points[dxf.paths[i].indices[1]][1];
if (j == 4) {
double x1 = coords[0][0], y1 = coords[0][1];
@ -182,7 +187,7 @@ Value builtin_dxf_cross(const Context *ctx, const QVector<QString> &argnames, co
}
}
PRINTA("WARNING: Can't find cross in `%1', layer `%2'!", filename, layername);
PRINTF("WARNING: Can't find cross in `%s', layer `%s'!", filename.c_str(), layername.c_str());
return Value();
}

View File

@ -1,10 +1,10 @@
#ifndef DXFDIM_H_
#define DXFDIM_H_
#include <QHash>
#include <boost/unordered_map.hpp>
#include "value.h"
extern QHash<QString,Value> dxf_cross_cache;
extern QHash<QString,Value> dxf_dim_cache;
extern boost::unordered_map<std::string,Value> dxf_dim_cache;
extern boost::unordered_map<std::string,Value> dxf_cross_cache;
#endif

View File

@ -39,11 +39,9 @@
#include "openscad.h" // get_fragments_from_r()
#include <sstream>
#include <boost/assign/std/vector.hpp>
using namespace boost::assign; // bring 'operator+=()' into scope
#include <QApplication>
#include <QTime>
#include <QProgressDialog>
#include <QDateTime>
#include <QFileInfo>
class DxfLinearExtrudeModule : public AbstractModule
@ -57,8 +55,9 @@ AbstractNode *DxfLinearExtrudeModule::evaluate(const Context *ctx, const ModuleI
{
DxfLinearExtrudeNode *node = new DxfLinearExtrudeNode(inst);
QVector<QString> argnames = QVector<QString>() << "file" << "layer" << "height" << "origin" << "scale" << "center" << "twist" << "slices";
QVector<Expression*> argexpr;
std::vector<std::string> argnames;
argnames += "file", "layer", "height", "origin", "scale", "center", "twist", "slices";
std::vector<Expression*> argexpr;
Context c(ctx);
c.args(argnames, argexpr, inst->argnames, inst->argvalues);
@ -77,10 +76,12 @@ AbstractNode *DxfLinearExtrudeModule::evaluate(const Context *ctx, const ModuleI
Value twist = c.lookup_variable("twist", true);
Value slices = c.lookup_variable("slices", true);
if (!file.text.empty())
node->filename = c.get_absolute_path(QString::fromStdString(file.text));
if (!file.text.empty()) {
PRINTF("DEPRECATED: Support for reading files in linear_extrude will be removed in future releases. Use a child import() instead.");
node->filename = c.getAbsolutePath(file.text);
}
node->layername = QString::fromStdString(layer.text);
node->layername = layer.text;
node->height = height.num;
node->convexity = (int)convexity.num;
origin.getv2(node->origin_x, node->origin_y);
@ -109,12 +110,9 @@ AbstractNode *DxfLinearExtrudeModule::evaluate(const Context *ctx, const ModuleI
node->has_twist = true;
}
if (node->filename.isEmpty()) {
foreach (ModuleInstantiation *v, inst->children) {
AbstractNode *n = v->evaluate(inst->ctx);
if (n)
node->children.push_back(n);
}
if (node->filename.empty()) {
std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren();
node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
}
return node;
@ -126,19 +124,16 @@ void register_builtin_dxf_linear_extrude()
builtin_modules["linear_extrude"] = new DxfLinearExtrudeModule();
}
PolySet *DxfLinearExtrudeNode::evaluate_polyset(render_mode_e mode,
PolySetEvaluator *evaluator) const
PolySet *DxfLinearExtrudeNode::evaluate_polyset(PolySetEvaluator *evaluator) const
{
if (!evaluator) {
PRINTF("WARNING: No suitable PolySetEvaluator found for %s module!", this->name().c_str());
PolySet *ps = new PolySet();
ps->is2d = true;
return ps;
return NULL;
}
print_messages_push();
PolySet *ps = evaluator->evaluatePolySet(*this, mode);
PolySet *ps = evaluator->evaluatePolySet(*this);
print_messages_pop();
@ -149,15 +144,17 @@ std::string DxfLinearExtrudeNode::toString() const
{
std::stringstream stream;
QString text;
stream << this->name() << "("
"file = \"" << this->filename << "\", "
"cache = \"" << QFileInfo(this->filename) << "\", "
"layer = \"" << this->layername << "\", "
stream << this->name() << "(";
if (!this->filename.empty()) { // Ignore deprecated parameters if empty
stream <<
"file = \"" << this->filename << "\", "
"cache = \"" << QFileInfo(QString::fromStdString(this->filename)) << "\", "
"layer = \"" << this->layername << "\", "
"origin = [ " << this->origin_x << " " << this->origin_y << " ], "
"scale = " << this->scale << ", ";
}
stream <<
"height = " << std::dec << this->height << ", "
"origin = [ " << this->origin_x << " " << this->origin_y << " ], "
"scale = " << this->scale << ", "
"center = " << (this->center?"true":"false") << ", "
"convexity = " << this->convexity;

View File

@ -3,7 +3,6 @@
#include "node.h"
#include "visitor.h"
#include <QString>
class DxfLinearExtrudeNode : public AbstractPolyNode
{
@ -24,8 +23,8 @@ public:
double fn, fs, fa, height, twist;
double origin_x, origin_y, scale;
bool center, has_twist;
QString filename, layername;
virtual PolySet *evaluate_polyset(render_mode_e mode, class PolySetEvaluator *) const;
std::string filename, layername;
virtual PolySet *evaluate_polyset(class PolySetEvaluator *) const;
};
#endif

View File

@ -37,11 +37,9 @@
#include "openscad.h" // get_fragments_from_r()
#include <sstream>
#include <boost/assign/std/vector.hpp>
using namespace boost::assign; // bring 'operator+=()' into scope
#include <QTime>
#include <QApplication>
#include <QProgressDialog>
#include <QDateTime>
#include <QFileInfo>
class DxfRotateExtrudeModule : public AbstractModule
@ -55,8 +53,9 @@ AbstractNode *DxfRotateExtrudeModule::evaluate(const Context *ctx, const ModuleI
{
DxfRotateExtrudeNode *node = new DxfRotateExtrudeNode(inst);
QVector<QString> argnames = QVector<QString>() << "file" << "layer" << "origin" << "scale";
QVector<Expression*> argexpr;
std::vector<std::string> argnames;
argnames += "file", "layer", "origin", "scale";
std::vector<Expression*> argexpr;
Context c(ctx);
c.args(argnames, argexpr, inst->argnames, inst->argvalues);
@ -71,10 +70,12 @@ AbstractNode *DxfRotateExtrudeModule::evaluate(const Context *ctx, const ModuleI
Value origin = c.lookup_variable("origin", true);
Value scale = c.lookup_variable("scale", true);
if (!file.text.empty())
node->filename = c.get_absolute_path(QString::fromStdString(file.text));
if (!file.text.empty()) {
PRINTF("DEPRECATED: Support for reading files in rotate_extrude will be removed in future releases. Use a child import() instead.");
node->filename = c.getAbsolutePath(file.text);
}
node->layername = QString::fromStdString(layer.text);
node->layername = layer.text;
node->convexity = (int)convexity.num;
origin.getv2(node->origin_x, node->origin_y);
node->scale = scale.num;
@ -85,12 +86,9 @@ AbstractNode *DxfRotateExtrudeModule::evaluate(const Context *ctx, const ModuleI
if (node->scale <= 0)
node->scale = 1;
if (node->filename.isEmpty()) {
foreach (ModuleInstantiation *v, inst->children) {
AbstractNode *n = v->evaluate(inst->ctx);
if (n)
node->children.push_back(n);
}
if (node->filename.empty()) {
std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren();
node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
}
return node;
@ -102,19 +100,16 @@ void register_builtin_dxf_rotate_extrude()
builtin_modules["rotate_extrude"] = new DxfRotateExtrudeModule();
}
PolySet *DxfRotateExtrudeNode::evaluate_polyset(render_mode_e mode,
PolySetEvaluator *evaluator) const
PolySet *DxfRotateExtrudeNode::evaluate_polyset(PolySetEvaluator *evaluator) const
{
if (!evaluator) {
PRINTF("WARNING: No suitable PolySetEvaluator found for %s module!", this->name().c_str());
PolySet *ps = new PolySet();
ps->is2d = true;
return ps;
return NULL;
}
print_messages_push();
PolySet *ps = evaluator->evaluatePolySet(*this, mode);
PolySet *ps = evaluator->evaluatePolySet(*this);
print_messages_pop();
@ -125,12 +120,16 @@ std::string DxfRotateExtrudeNode::toString() const
{
std::stringstream stream;
stream << this->name() << "("
"file = \"" << this->filename << "\", "
"cache = \"" << QFileInfo(this->filename) << "\", "
"layer = \"" << this->layername << "\", "
"origin = [ " << std::dec << this->origin_x << " " << this->origin_y << " ], "
"scale = " << this->scale << ", "
stream << this->name() << "(";
if (!this->filename.empty()) { // Ignore deprecated parameters if empty
stream <<
"file = \"" << this->filename << "\", "
"cache = \"" << QFileInfo(QString::fromStdString(this->filename)) << "\", "
"layer = \"" << this->layername << "\", "
"origin = [ " << std::dec << this->origin_x << " " << this->origin_y << " ], "
"scale = " << this->scale << ", ";
}
stream <<
"convexity = " << this->convexity << ", "
"$fn = " << this->fn << ", $fa = " << this->fa << ", $fs = " << this->fs << ")";

View File

@ -3,7 +3,6 @@
#include "node.h"
#include "visitor.h"
#include <QString>
class DxfRotateExtrudeNode : public AbstractPolyNode
{
@ -22,8 +21,8 @@ public:
int convexity;
double fn, fs, fa;
double origin_x, origin_y, scale;
QString filename, layername;
virtual PolySet *evaluate_polyset(render_mode_e mode, class PolySetEvaluator *) const;
std::string filename, layername;
virtual PolySet *evaluate_polyset(class PolySetEvaluator *) const;
};
#endif

View File

@ -93,7 +93,7 @@ void mark_inner_outer(QList<struct triangle> &tri, Grid2d<point_info_t> &point_i
}
}
void dxf_tesselate(PolySet *ps, DxfData *dxf, double rot, bool up, bool /* do_triangle_splitting */, double h)
void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, bool up, bool /* do_triangle_splitting */, double h)
{
CDT cdt;
@ -106,17 +106,17 @@ void dxf_tesselate(PolySet *ps, DxfData *dxf, double rot, bool up, bool /* do_tr
try {
// read path data and copy all relevant infos
for (int i = 0; i < dxf->paths.count(); i++)
for (size_t i = 0; i < dxf.paths.size(); i++)
{
if (!dxf->paths[i].is_closed)
if (!dxf.paths[i].is_closed)
continue;
Vertex_handle first, prev;
struct point_info_t *first_pi = NULL, *prev_pi = NULL;
for (int j = 1; j < dxf->paths[i].points.count(); j++)
for (size_t j = 1; j < dxf.paths[i].indices.size(); j++)
{
double x = (*dxf->paths[i].points[j])[0];
double y = (*dxf->paths[i].points[j])[1];
double x = dxf.points[dxf.paths[i].indices[j]][0];
double y = dxf.points[dxf.paths[i].indices[j]][1];
if (point_info.has(x, y)) {
// FIXME: How can the same path set contain the same point twice?
@ -127,7 +127,7 @@ void dxf_tesselate(PolySet *ps, DxfData *dxf, double rot, bool up, bool /* do_tr
}
struct point_info_t *pi = &point_info.align(x, y);
*pi = point_info_t(x, y, i, j, dxf->paths[i].points.count()-1);
*pi = point_info_t(x, y, i, j, dxf.paths[i].indices.size()-1);
Vertex_handle vh = cdt.insert(CDTPoint(x, y));
if (first_pi == NULL) {
@ -158,7 +158,7 @@ void dxf_tesselate(PolySet *ps, DxfData *dxf, double rot, bool up, bool /* do_tr
}
catch (CGAL::Assertion_exception e) {
PRINTF("CGAL error: %s", e.what());
PRINTF("CGAL error in dxf_tesselate(): %s", e.what());
CGAL::set_error_behaviour(old_behaviour);
return;
}
@ -306,17 +306,17 @@ void dxf_tesselate(PolySet *ps, DxfData *dxf, double rot, bool up, bool /* do_tr
}
if (path[0] == path[1] && point[0] == 1 && point[1] == 2)
dxf->paths[path[0]].is_inner = up;
dxf.paths[path[0]].is_inner = up;
if (path[0] == path[1] && point[0] == 2 && point[1] == 1)
dxf->paths[path[0]].is_inner = !up;
dxf.paths[path[0]].is_inner = !up;
if (path[1] == path[2] && point[1] == 1 && point[2] == 2)
dxf->paths[path[1]].is_inner = up;
dxf.paths[path[1]].is_inner = up;
if (path[1] == path[2] && point[1] == 2 && point[2] == 1)
dxf->paths[path[1]].is_inner = !up;
dxf.paths[path[1]].is_inner = !up;
if (path[2] == path[0] && point[2] == 1 && point[0] == 2)
dxf->paths[path[2]].is_inner = up;
dxf.paths[path[2]].is_inner = up;
if (path[2] == path[0] && point[2] == 2 && point[0] == 1)
dxf->paths[path[2]].is_inner = !up;
dxf.paths[path[2]].is_inner = !up;
}
}

View File

@ -193,7 +193,7 @@ static bool point_on_line(double *p1, double *p2, double *p3)
rot: CLOCKWISE rotation around positive Z axis
*/
void dxf_tesselate(PolySet *ps, DxfData *dxf, double rot, bool up, bool do_triangle_splitting, double h)
void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, bool up, bool do_triangle_splitting, double h)
{
GLUtesselator *tobj = gluNewTess();
@ -227,17 +227,17 @@ void dxf_tesselate(PolySet *ps, DxfData *dxf, double rot, bool up, bool do_trian
Grid3d< QPair<int,int> > point_to_path(GRID_COARSE);
for (int i = 0; i < dxf->paths.count(); i++) {
if (!dxf->paths[i].is_closed)
for (int i = 0; i < dxf.paths.size(); i++) {
if (!dxf.paths[i].is_closed)
continue;
gluTessBeginContour(tobj);
for (int j = 1; j < dxf->paths[i].points.count(); j++) {
point_to_path.data((*dxf->paths[i].points[j])[0],
(*dxf->paths[i].points[j])[1],
for (int j = 1; j < dxf.paths[i].indices.size(); j++) {
point_to_path.data(dxf.points[dxf.paths[i].indices[j]][0],
dxf.points[dxf.paths[i].indices[j]][1],
h) = QPair<int,int>(i, j);
vl.append(tess_vdata());
vl.last().v[0] = (*dxf->paths[i].points[j])[0];
vl.last().v[1] = (*dxf->paths[i].points[j])[1];
vl.last().v[0] = dxf.points[dxf.paths[i].indices[j]][0];
vl.last().v[1] = dxf.points[dxf.paths[i].indices[j]][1];
vl.last().v[2] = h;
gluTessVertex(tobj, vl.last().v, vl.last().v);
}
@ -248,7 +248,7 @@ void dxf_tesselate(PolySet *ps, DxfData *dxf, double rot, bool up, bool do_trian
gluDeleteTess(tobj);
#if 0
for (int i = 0; i < tess_tri.count(); i++) {
for (int i = 0; i < tess_tri.size(); i++) {
printf("~~~\n");
printf(" %f %f %f\n", tess_tri[i].p[0][0], tess_tri[i].p[0][1], tess_tri[i].p[0][2]);
printf(" %f %f %f\n", tess_tri[i].p[1][0], tess_tri[i].p[1][1], tess_tri[i].p[1][2]);
@ -258,7 +258,7 @@ void dxf_tesselate(PolySet *ps, DxfData *dxf, double rot, bool up, bool do_trian
// GLU tessing sometimes generates degenerated triangles. We must find and remove
// them so we can use the triangle array with CGAL..
for (int i = 0; i < tess_tri.count(); i++) {
for (int i = 0; i < tess_tri.size(); i++) {
if (point_on_line(tess_tri[i].p[0], tess_tri[i].p[1], tess_tri[i].p[2]) ||
point_on_line(tess_tri[i].p[1], tess_tri[i].p[2], tess_tri[i].p[0]) ||
point_on_line(tess_tri[i].p[2], tess_tri[i].p[0], tess_tri[i].p[1])) {
@ -279,7 +279,7 @@ void dxf_tesselate(PolySet *ps, DxfData *dxf, double rot, bool up, bool do_trian
bool added_triangles = true;
typedef QPair<int,int> QPair_ii;
QHash<int, QPair_ii> tri_by_atan2;
for (int i = 0; i < tess_tri.count(); i++)
for (int i = 0; i < tess_tri.size(); i++)
for (int j = 0; j < 3; j++) {
int ai = (int)round(atan2(fabs(tess_tri[i].p[(j+1)%3][0] - tess_tri[i].p[j][0]),
fabs(tess_tri[i].p[(j+1)%3][1] - tess_tri[i].p[j][1])) / 0.001);
@ -289,9 +289,9 @@ void dxf_tesselate(PolySet *ps, DxfData *dxf, double rot, bool up, bool do_trian
{
added_triangles = false;
#ifdef DEBUG_TRIANGLE_SPLITTING
printf("*** Triangle splitting (%d) ***\n", tess_tri.count()+1);
printf("*** Triangle splitting (%d) ***\n", tess_tri.size()+1);
#endif
for (int i = 0; i < tess_tri.count(); i++)
for (int i = 0; i < tess_tri.size(); i++)
for (int k = 0; k < 3; k++)
{
QHash<QPair_ii, QPair_ii> possible_neigh;
@ -303,7 +303,7 @@ void dxf_tesselate(PolySet *ps, DxfData *dxf, double rot, bool up, bool do_trian
possible_neigh[jl] = jl;
}
#ifdef DEBUG_TRIANGLE_SPLITTING
printf("%d/%d: %d\n", i, k, possible_neigh.count());
printf("%d/%d: %d\n", i, k, possible_neigh.size());
#endif
foreach (const QPair_ii &jl, possible_neigh) {
int j = jl.first;
@ -321,7 +321,7 @@ void dxf_tesselate(PolySet *ps, DxfData *dxf, double rot, bool up, bool do_trian
for (int m = 0; m < 2; m++) {
int ai = (int)round(atan2(fabs(tess_tri.last().p[(m+1)%3][0] - tess_tri.last().p[m][0]),
fabs(tess_tri.last().p[(m+1)%3][1] - tess_tri.last().p[m][1])) / 0.001 );
tri_by_atan2.insertMulti(ai, QPair<int,int>(tess_tri.count()-1, m));
tri_by_atan2.insertMulti(ai, QPair<int,int>(tess_tri.size()-1, m));
}
tess_tri[i].p[(k+1)%3] = tess_tri[j].p[l];
for (int m = 0; m < 2; m++) {
@ -337,7 +337,7 @@ void dxf_tesselate(PolySet *ps, DxfData *dxf, double rot, bool up, bool do_trian
}
#endif
for (int i = 0; i < tess_tri.count(); i++)
for (int i = 0; i < tess_tri.size(); i++)
{
#if 0
printf("---\n");
@ -370,19 +370,19 @@ void dxf_tesselate(PolySet *ps, DxfData *dxf, double rot, bool up, bool do_trian
int j2 = point_to_path.data(tess_tri[i].p[2][0], tess_tri[i].p[2][1], tess_tri[i].p[2][2]).second;
if (i0 == i1 && j0 == 1 && j1 == 2)
dxf->paths[i0].is_inner = !up;
dxf.paths[i0].is_inner = !up;
if (i0 == i1 && j0 == 2 && j1 == 1)
dxf->paths[i0].is_inner = up;
dxf.paths[i0].is_inner = up;
if (i1 == i2 && j1 == 1 && j2 == 2)
dxf->paths[i1].is_inner = !up;
dxf.paths[i1].is_inner = !up;
if (i1 == i2 && j1 == 2 && j2 == 1)
dxf->paths[i1].is_inner = up;
dxf.paths[i1].is_inner = up;
if (i2 == i0 && j2 == 1 && j0 == 2)
dxf->paths[i2].is_inner = !up;
dxf.paths[i2].is_inner = !up;
if (i2 == i0 && j2 == 2 && j0 == 1)
dxf->paths[i2].is_inner = up;
dxf.paths[i2].is_inner = up;
}
tess_tri.clear();

View File

@ -37,17 +37,17 @@
without tesselating. Vertex ordering of the resulting polygons
will follow the paths' is_inner flag.
*/
void dxf_border_to_ps(PolySet *ps, DxfData *dxf)
void dxf_border_to_ps(PolySet *ps, const DxfData &dxf)
{
for (int i = 0; i < dxf->paths.count(); i++) {
const DxfData::Path &pt = dxf->paths[i];
if (!pt.is_closed)
for (size_t i = 0; i < dxf.paths.size(); i++) {
const DxfData::Path &path = dxf.paths[i];
if (!path.is_closed)
continue;
ps->borders.push_back(PolySet::Polygon());
for (int j = 1; j < pt.points.count(); j++) {
double x = (*pt.points[j])[0], y = (*pt.points[j])[1], z = 0.0;
for (size_t j = 1; j < path.indices.size(); j++) {
double x = dxf.points[path.indices[j]][0], y = dxf.points[path.indices[j]][1], z = 0.0;
ps->grid.align(x, y, z);
if (pt.is_inner) {
if (path.is_inner) {
ps->borders.back().push_back(Vector3d(x, y, z));
} else {
ps->borders.back().insert(ps->borders.back().begin(), Vector3d(x, y, z));

View File

@ -3,7 +3,7 @@
class DxfData;
class PolySet;
void dxf_tesselate(PolySet *ps, DxfData *dxf, double rot, bool up, bool do_triangle_splitting, double h);
void dxf_border_to_ps(PolySet *ps, DxfData *dxf);
void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, bool up, bool do_triangle_splitting, double h);
void dxf_border_to_ps(PolySet *ps, const DxfData &dxf);
#endif

View File

@ -24,27 +24,27 @@
*
*/
#include "export.h"
#include "printutils.h"
#include "polyset.h"
#include "dxfdata.h"
#include <QApplication>
#include <QProgressDialog>
#include <QTextStream>
#include <errno.h>
#include <fstream>
#ifdef ENABLE_CGAL
#include "CGAL_Nef_polyhedron.h"
#include "cgal.h"
/*!
Saves the current 3D CGAL Nef polyhedron as STL to the given file.
The file must be open.
*/
void export_stl(CGAL_Nef_polyhedron *root_N, QTextStream &output, QProgressDialog *pd)
void export_stl(CGAL_Nef_polyhedron *root_N, std::ostream &output, QProgressDialog *pd)
{
CGAL_Polyhedron P;
root_N->p3.convert_to_Polyhedron(P);
root_N->p3->convert_to_Polyhedron(P);
typedef CGAL_Polyhedron::Vertex Vertex;
typedef CGAL_Polyhedron::Vertex_const_iterator VCI;
@ -53,6 +53,7 @@ void export_stl(CGAL_Nef_polyhedron *root_N, QTextStream &output, QProgressDialo
setlocale(LC_NUMERIC, "C"); // Ensure radix is . (not ,) in output
<<<<<<< HEAD
std::ofstream output(filename.toUtf8());
if (!output.is_open()) {
PRINTA("Can't open STL file \"%1\" for STL export: %2",
@ -61,6 +62,8 @@ void export_stl(CGAL_Nef_polyhedron *root_N, QTextStream &output, QProgressDialo
return;
}
=======
>>>>>>> upstream/visitor
output << "solid OpenSCAD_Model\n";
int facet_count = 0;
@ -119,19 +122,24 @@ void export_stl(CGAL_Nef_polyhedron *root_N, QTextStream &output, QProgressDialo
}
output << "endsolid OpenSCAD_Model\n";
<<<<<<< HEAD
output.close();
=======
>>>>>>> upstream/visitor
setlocale(LC_NUMERIC, ""); // Set default locale
}
void export_off(CGAL_Nef_polyhedron*, QTextStream&, QProgressDialog*)
void export_off(CGAL_Nef_polyhedron *root_N, std::ostream &output, QProgressDialog*)
{
PRINTF("WARNING: OFF import is not implemented yet.");
CGAL_Polyhedron P;
root_N->p3->convert_to_Polyhedron(P);
output << P;
}
/*!
Saves the current 2D CGAL Nef polyhedron as DXF to the given absolute filename.
*/
void export_dxf(CGAL_Nef_polyhedron *root_N, QTextStream &output, QProgressDialog *)
void export_dxf(CGAL_Nef_polyhedron *root_N, std::ostream &output, QProgressDialog *)
{
setlocale(LC_NUMERIC, "C"); // Ensure radix is . (not ,) in output
// Some importers (e.g. Inkscape) needs a BLOCKS section to be present
@ -146,12 +154,12 @@ void export_dxf(CGAL_Nef_polyhedron *root_N, QTextStream &output, QProgressDialo
<< " 2\n"
<< "ENTITIES\n";
DxfData dd(*root_N);
for (int i=0; i<dd.paths.size(); i++)
DxfData *dd =root_N->convertToDxfData();
for (size_t i=0; i<dd->paths.size(); i++)
{
for (int j=1; j<dd.paths[i].points.size(); j++) {
const Vector2d &p1 = *dd.paths[i].points[j-1];
const Vector2d &p2 = *dd.paths[i].points[j];
for (size_t j=1; j<dd->paths[i].indices.size(); j++) {
const Vector2d &p1 = dd->points[dd->paths[i].indices[j-1]];
const Vector2d &p2 = dd->points[dd->paths[i].indices[j]];
double x1 = p1[0];
double y1 = p1[1];
double x2 = p2[0];
@ -188,6 +196,7 @@ void export_dxf(CGAL_Nef_polyhedron *root_N, QTextStream &output, QProgressDialo
output << " 0\n"
<<"EOF\n";
delete dd;
setlocale(LC_NUMERIC, ""); // Set default locale
}

View File

@ -2,11 +2,13 @@
#define EXPORT_H_
#ifdef ENABLE_CGAL
#include "cgal.h"
void cgal_nef3_to_polyset(PolySet *ps, CGAL_Nef_polyhedron *root_N);
void export_stl(class CGAL_Nef_polyhedron *root_N, class QTextStream &output, class QProgressDialog *pd);
void export_off(CGAL_Nef_polyhedron *root_N, class QTextStream &output, QProgressDialog *pd);
void export_dxf(CGAL_Nef_polyhedron *root_N, class QTextStream &output, QProgressDialog *pd);
#include <iostream>
void cgal_nef3_to_polyset(class PolySet *ps, class CGAL_Nef_polyhedron *root_N);
void export_stl(CGAL_Nef_polyhedron *root_N, std::ostream &output, class QProgressDialog *pd);
void export_off(CGAL_Nef_polyhedron *root_N, std::ostream &output, QProgressDialog *pd);
void export_dxf(CGAL_Nef_polyhedron *root_N, std::ostream &output, QProgressDialog *pd);
#endif
#endif

View File

@ -29,74 +29,74 @@
#include "context.h"
#include <assert.h>
#include <sstream>
#include <algorithm>
#include "stl-utils.h"
Expression::Expression()
{
const_value = NULL;
this->const_value = NULL;
}
Expression::~Expression()
{
for (int i=0; i < children.size(); i++)
delete children[i];
if (const_value)
delete const_value;
std::for_each(this->children.begin(), this->children.end(), del_fun<Expression>());
delete this->const_value;
}
Value Expression::evaluate(const Context *context) const
{
if (type == "!")
return ! children[0]->evaluate(context);
if (type == "&&")
return children[0]->evaluate(context) && children[1]->evaluate(context);
if (type == "||")
return children[0]->evaluate(context) || children[1]->evaluate(context);
if (type == "*")
return children[0]->evaluate(context) * children[1]->evaluate(context);
if (type == "/")
return children[0]->evaluate(context) / children[1]->evaluate(context);
if (type == "%")
return children[0]->evaluate(context) % children[1]->evaluate(context);
if (type == "+")
return children[0]->evaluate(context) + children[1]->evaluate(context);
if (type == "-")
return children[0]->evaluate(context) - children[1]->evaluate(context);
if (type == "<")
return children[0]->evaluate(context) < children[1]->evaluate(context);
if (type == "<=")
return children[0]->evaluate(context) <= children[1]->evaluate(context);
if (type == "==")
return children[0]->evaluate(context) == children[1]->evaluate(context);
if (type == "!=")
return children[0]->evaluate(context) != children[1]->evaluate(context);
if (type == ">=")
return children[0]->evaluate(context) >= children[1]->evaluate(context);
if (type == ">")
return children[0]->evaluate(context) > children[1]->evaluate(context);
if (type == "?:") {
Value v = children[0]->evaluate(context);
if (this->type == "!")
return ! this->children[0]->evaluate(context);
if (this->type == "&&")
return this->children[0]->evaluate(context) && this->children[1]->evaluate(context);
if (this->type == "||")
return this->children[0]->evaluate(context) || this->children[1]->evaluate(context);
if (this->type == "*")
return this->children[0]->evaluate(context) * this->children[1]->evaluate(context);
if (this->type == "/")
return this->children[0]->evaluate(context) / this->children[1]->evaluate(context);
if (this->type == "%")
return this->children[0]->evaluate(context) % this->children[1]->evaluate(context);
if (this->type == "+")
return this->children[0]->evaluate(context) + this->children[1]->evaluate(context);
if (this->type == "-")
return this->children[0]->evaluate(context) - this->children[1]->evaluate(context);
if (this->type == "<")
return this->children[0]->evaluate(context) < this->children[1]->evaluate(context);
if (this->type == "<=")
return this->children[0]->evaluate(context) <= this->children[1]->evaluate(context);
if (this->type == "==")
return this->children[0]->evaluate(context) == this->children[1]->evaluate(context);
if (this->type == "!=")
return this->children[0]->evaluate(context) != this->children[1]->evaluate(context);
if (this->type == ">=")
return this->children[0]->evaluate(context) >= this->children[1]->evaluate(context);
if (this->type == ">")
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 children[v.b ? 1 : 2]->evaluate(context);
return this->children[v.b ? 1 : 2]->evaluate(context);
return Value();
}
if (type == "[]") {
Value v1 = children[0]->evaluate(context);
Value v2 = children[1]->evaluate(context);
if (this->type == "[]") {
Value v1 = this->children[0]->evaluate(context);
Value v2 = this->children[1]->evaluate(context);
if (v1.type == Value::VECTOR && v2.type == Value::NUMBER) {
int i = (int)(v2.num);
if (i >= 0 && i < v1.vec.size())
int i = int(v2.num);
if (i >= 0 && i < int(v1.vec.size()))
return *v1.vec[i];
}
return Value();
}
if (type == "I")
return children[0]->evaluate(context).inv();
if (type == "C")
return *const_value;
if (type == "R") {
Value v1 = children[0]->evaluate(context);
Value v2 = children[1]->evaluate(context);
Value v3 = children[2]->evaluate(context);
if (this->type == "I")
return this->children[0]->evaluate(context).inv();
if (this->type == "C")
return *this->const_value;
if (this->type == "R") {
Value v1 = this->children[0]->evaluate(context);
Value v2 = this->children[1]->evaluate(context);
Value v3 = this->children[2]->evaluate(context);
if (v1.type == Value::NUMBER && v2.type == Value::NUMBER && v3.type == Value::NUMBER) {
Value r = Value();
r.type = Value::RANGE;
@ -107,40 +107,40 @@ Value Expression::evaluate(const Context *context) const
}
return Value();
}
if (type == "V") {
if (this->type == "V") {
Value v;
v.type = Value::VECTOR;
for (int i = 0; i < children.size(); i++)
v.append(new Value(children[i]->evaluate(context)));
for (size_t i = 0; i < this->children.size(); i++)
v.append(new Value(this->children[i]->evaluate(context)));
return v;
}
if (type == "L")
return context->lookup_variable(var_name);
if (type == "N")
if (this->type == "L")
return context->lookup_variable(this->var_name);
if (this->type == "N")
{
Value v = children[0]->evaluate(context);
Value v = this->children[0]->evaluate(context);
if (v.type == Value::VECTOR && var_name == QString("x"))
if (v.type == Value::VECTOR && this->var_name == "x")
return *v.vec[0];
if (v.type == Value::VECTOR && var_name == QString("y"))
if (v.type == Value::VECTOR && this->var_name == "y")
return *v.vec[1];
if (v.type == Value::VECTOR && var_name == QString("z"))
if (v.type == Value::VECTOR && this->var_name == "z")
return *v.vec[2];
if (v.type == Value::RANGE && var_name == QString("begin"))
if (v.type == Value::RANGE && this->var_name == "begin")
return Value(v.range_begin);
if (v.type == Value::RANGE && var_name == QString("step"))
if (v.type == Value::RANGE && this->var_name == "step")
return Value(v.range_step);
if (v.type == Value::RANGE && var_name == QString("end"))
if (v.type == Value::RANGE && this->var_name == "end")
return Value(v.range_end);
return Value();
}
if (type == "F") {
QVector<Value> argvalues;
for (int i=0; i < children.size(); i++)
argvalues.append(children[i]->evaluate(context));
return context->evaluate_function(call_funcname, call_argnames, argvalues);
if (this->type == "F") {
std::vector<Value> argvalues;
for (size_t i=0; i < this->children.size(); i++)
argvalues.push_back(this->children[i]->evaluate(context));
return context->evaluate_function(this->call_funcname, this->call_argnames, argvalues);
}
abort();
}
@ -152,43 +152,43 @@ std::string Expression::toString() const
if (this->type == "*" || this->type == "/" || this->type == "%" || this->type == "+" ||
this->type == "-" || this->type == "<" || this->type == "<=" || this->type == "==" ||
this->type == "!=" || this->type == ">=" || this->type == ">") {
stream << "(" << *children[0] << " " << this->type << " " << *children[1] << ")";
stream << "(" << *this->children[0] << " " << this->type << " " << *this->children[1] << ")";
}
else if (this->type == "?:") {
stream << "(" << *children[0] << " ? " << this->type << " : " << *children[1] << ")";
stream << "(" << *this->children[0] << " ? " << this->type << " : " << *this->children[1] << ")";
}
else if (this->type == "[]") {
stream << "(" << *children[0] << "[" << *children[1] << "])";
stream << "(" << *this->children[0] << "[" << *this->children[1] << "])";
}
else if (this->type == "I") {
stream << "(-" << *children[0] << ")";
stream << "(-" << *this->children[0] << ")";
}
else if (this->type == "C") {
stream << *const_value;
stream << *this->const_value;
}
else if (this->type == "R") {
stream << "[" << *children[0] << " : " << *children[1] << " : " << children[2] << "]";
stream << "[" << *this->children[0] << " : " << *this->children[1] << " : " << this->children[2] << "]";
}
else if (this->type == "V") {
stream << "[";
for (int i=0; i < children.size(); i++) {
for (size_t i=0; i < this->children.size(); i++) {
if (i > 0) stream << ", ";
stream << *children[i];
stream << *this->children[i];
}
stream << "]";
}
else if (this->type == "L") {
stream << var_name;
stream << this->var_name;
}
else if (this->type == "N") {
stream << "(" << *children[0] << "." << var_name << ")";
stream << "(" << *this->children[0] << "." << this->var_name << ")";
}
else if (this->type == "F") {
stream << call_funcname << "(";
for (int i=0; i < children.size(); i++) {
stream << this->call_funcname << "(";
for (size_t i=0; i < this->children.size(); i++) {
if (i > 0) stream << ", ";
if (!call_argnames[i].isEmpty()) stream << call_argnames[i] << " = ";
stream << *children[i];
if (!this->call_argnames[i].empty()) stream << this->call_argnames[i] << " = ";
stream << *this->children[i];
}
stream << ")";
}

View File

@ -1,19 +1,19 @@
#ifndef EXPRESSION_H_
#define EXPRESSION_H_
#include <QVector>
#include <QString>
#include <string>
#include <vector>
class Expression
{
public:
QVector<Expression*> children;
std::vector<Expression*> children;
class Value *const_value;
QString var_name;
std::string var_name;
QString call_funcname;
QVector<QString> call_argnames;
std::string call_funcname;
std::vector<std::string> call_argnames;
// Boolean: ! && ||
// Operators: * / % + -
@ -28,7 +28,7 @@ public:
// Lookup Variable: L
// Lookup member per name: N
// Function call: F
QString type;
std::string type;
Expression();
~Expression();

View File

@ -32,29 +32,35 @@
#include <sstream>
#include <ctime>
#include "mathc99.h"
#include <algorithm>
#include "stl-utils.h"
#include <boost/foreach.hpp>
AbstractFunction::~AbstractFunction()
{
}
Value AbstractFunction::evaluate(const Context*, const QVector<QString>&, const QVector<Value>&) const
Value AbstractFunction::evaluate(const Context*, const std::vector<std::string>&, const std::vector<Value>&) const
{
return Value();
}
QString AbstractFunction::dump(QString indent, QString name) const
std::string AbstractFunction::dump(const std::string &indent, const std::string &name) const
{
return QString("%1abstract function %2();\n").arg(indent, name);
std::stringstream dump;
dump << indent << "abstract function " << name << "();\n";
return dump.str();
}
Function::~Function()
{
for (int i=0; i < argexpr.size(); i++)
delete argexpr[i];
std::for_each(this->argexpr.begin(), this->argexpr.end(), del_fun<Expression>());
delete expr;
}
Value Function::evaluate(const Context *ctx, const QVector<QString> &call_argnames, const QVector<Value> &call_argvalues) const
Value Function::evaluate(const Context *ctx,
const std::vector<std::string> &call_argnames,
const std::vector<Value> &call_argvalues) const
{
Context c(ctx);
c.args(argnames, argexpr, call_argnames, call_argvalues);
@ -63,34 +69,36 @@ Value Function::evaluate(const Context *ctx, const QVector<QString> &call_argnam
return Value();
}
QString Function::dump(QString indent, QString name) const
std::string Function::dump(const std::string &indent, const std::string &name) const
{
QString text = QString("%1function %2(").arg(indent, name);
for (int i=0; i < argnames.size(); i++) {
if (i > 0)
text += QString(", ");
text += argnames[i];
if (argexpr[i])
text += QString(" = ") + QString::fromStdString(argexpr[i]->toString());
std::stringstream dump;
dump << indent << "function " << name << "(";
for (size_t i=0; i < argnames.size(); i++) {
if (i > 0) dump << ", ";
dump << argnames[i];
if (argexpr[i]) dump << " = " << *argexpr[i];
}
text += QString(") = %1;\n").arg(QString::fromStdString(expr->toString()));
return text;
dump << ") = " << *expr << ";\n";
return dump.str();
}
QHash<QString, AbstractFunction*> builtin_functions;
typedef boost::unordered_map<std::string, AbstractFunction*> BuiltinContainer;
BuiltinContainer builtin_functions;
BuiltinFunction::~BuiltinFunction()
{
}
Value BuiltinFunction::evaluate(const Context *ctx, const QVector<QString> &call_argnames, const QVector<Value> &call_argvalues) const
Value BuiltinFunction::evaluate(const Context *ctx, const std::vector<std::string> &call_argnames, const std::vector<Value> &call_argvalues) const
{
return eval_func(ctx, call_argnames, call_argvalues);
}
QString BuiltinFunction::dump(QString indent, QString name) const
std::string BuiltinFunction::dump(const std::string &indent, const std::string &name) const
{
return QString("%1builtin function %2();\n").arg(indent, name);
std::stringstream dump;
dump << indent << "builtin function " << name << "();\n";
return dump.str();
}
static double deg2rad(double x)
@ -113,14 +121,14 @@ static double rad2deg(double x)
return x;
}
Value builtin_abs(const Context *, const QVector<QString>&, const QVector<Value> &args)
Value builtin_abs(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
{
if (args.size() == 1 && args[0].type == Value::NUMBER)
return Value(fabs(args[0].num));
return Value();
}
Value builtin_sign(const Context *, const QVector<QString>&, const QVector<Value> &args)
Value builtin_sign(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
{
if (args.size() == 1 && args[0].type == Value::NUMBER)
return Value((args[0].num<0) ? -1.0 : ((args[0].num>0) ? 1.0 : 0.0));
@ -137,7 +145,7 @@ double frand(double min, double max)
return (min>max) ? frand()*(min-max)+max : frand()*(max-min)+min;
}
Value builtin_rands(const Context *, const QVector<QString>&, const QVector<Value> &args)
Value builtin_rands(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
{
if (args.size() == 3 &&
args[0].type == Value::NUMBER &&
@ -172,11 +180,11 @@ Value builtin_rands(const Context *, const QVector<QString>&, const QVector<Valu
}
Value builtin_min(const Context *, const QVector<QString>&, const QVector<Value> &args)
Value builtin_min(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
{
if (args.size() >= 1 && args[0].type == Value::NUMBER) {
double val = args[0].num;
for (int i = 1; i < args.size(); i++)
for (size_t i = 1; i < args.size(); i++)
if (args[1].type == Value::NUMBER)
val = fmin(val, args[i].num);
return Value(val);
@ -184,11 +192,11 @@ Value builtin_min(const Context *, const QVector<QString>&, const QVector<Value>
return Value();
}
Value builtin_max(const Context *, const QVector<QString>&, const QVector<Value> &args)
Value builtin_max(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
{
if (args.size() >= 1 && args[0].type == Value::NUMBER) {
double val = args[0].num;
for (int i = 1; i < args.size(); i++)
for (size_t i = 1; i < args.size(); i++)
if (args[1].type == Value::NUMBER)
val = fmax(val, args[i].num);
return Value(val);
@ -196,98 +204,98 @@ Value builtin_max(const Context *, const QVector<QString>&, const QVector<Value>
return Value();
}
Value builtin_sin(const Context *, const QVector<QString>&, const QVector<Value> &args)
Value builtin_sin(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
{
if (args.size() == 1 && args[0].type == Value::NUMBER)
return Value(sin(deg2rad(args[0].num)));
return Value();
}
Value builtin_cos(const Context *, const QVector<QString>&, const QVector<Value> &args)
Value builtin_cos(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
{
if (args.size() == 1 && args[0].type == Value::NUMBER)
return Value(cos(deg2rad(args[0].num)));
return Value();
}
Value builtin_asin(const Context *, const QVector<QString>&, const QVector<Value> &args)
Value builtin_asin(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
{
if (args.size() == 1 && args[0].type == Value::NUMBER)
return Value(rad2deg(asin(args[0].num)));
return Value();
}
Value builtin_acos(const Context *, const QVector<QString>&, const QVector<Value> &args)
Value builtin_acos(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
{
if (args.size() == 1 && args[0].type == Value::NUMBER)
return Value(rad2deg(acos(args[0].num)));
return Value();
}
Value builtin_tan(const Context *, const QVector<QString>&, const QVector<Value> &args)
Value builtin_tan(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
{
if (args.size() == 1 && args[0].type == Value::NUMBER)
return Value(tan(deg2rad(args[0].num)));
return Value();
}
Value builtin_atan(const Context *, const QVector<QString>&, const QVector<Value> &args)
Value builtin_atan(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
{
if (args.size() == 1 && args[0].type == Value::NUMBER)
return Value(rad2deg(atan(args[0].num)));
return Value();
}
Value builtin_atan2(const Context *, const QVector<QString>&, const QVector<Value> &args)
Value builtin_atan2(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
{
if (args.size() == 2 && args[0].type == Value::NUMBER && args[1].type == Value::NUMBER)
return Value(rad2deg(atan2(args[0].num, args[1].num)));
return Value();
}
Value builtin_pow(const Context *, const QVector<QString>&, const QVector<Value> &args)
Value builtin_pow(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
{
if (args.size() == 2 && args[0].type == Value::NUMBER && args[1].type == Value::NUMBER)
return Value(pow(args[0].num, args[1].num));
return Value();
}
Value builtin_round(const Context *, const QVector<QString>&, const QVector<Value> &args)
Value builtin_round(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
{
if (args.size() == 1 && args[0].type == Value::NUMBER)
return Value(round(args[0].num));
return Value();
}
Value builtin_ceil(const Context *, const QVector<QString>&, const QVector<Value> &args)
Value builtin_ceil(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
{
if (args.size() == 1 && args[0].type == Value::NUMBER)
return Value(ceil(args[0].num));
return Value();
}
Value builtin_floor(const Context *, const QVector<QString>&, const QVector<Value> &args)
Value builtin_floor(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
{
if (args.size() == 1 && args[0].type == Value::NUMBER)
return Value(floor(args[0].num));
return Value();
}
Value builtin_sqrt(const Context *, const QVector<QString>&, const QVector<Value> &args)
Value builtin_sqrt(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
{
if (args.size() == 1 && args[0].type == Value::NUMBER)
return Value(sqrt(args[0].num));
return Value();
}
Value builtin_exp(const Context *, const QVector<QString>&, const QVector<Value> &args)
Value builtin_exp(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
{
if (args.size() == 1 && args[0].type == Value::NUMBER)
return Value(exp(args[0].num));
return Value();
}
Value builtin_log(const Context *, const QVector<QString>&, const QVector<Value> &args)
Value builtin_log(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
{
if (args.size() == 2 && args[0].type == Value::NUMBER && args[1].type == Value::NUMBER)
return Value(log(args[1].num) / log(args[0].num));
@ -296,31 +304,31 @@ Value builtin_log(const Context *, const QVector<QString>&, const QVector<Value>
return Value();
}
Value builtin_ln(const Context *, const QVector<QString>&, const QVector<Value> &args)
Value builtin_ln(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
{
if (args.size() == 1 && args[0].type == Value::NUMBER)
return Value(log(args[0].num));
return Value();
}
Value builtin_str(const Context *, const QVector<QString>&, const QVector<Value> &args)
Value builtin_str(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
{
std::stringstream stream;
for (int i = 0; i < args.size(); i++) {
for (size_t i = 0; i < args.size(); i++) {
stream << args[i];
}
return Value(stream.str());
}
Value builtin_lookup(const Context *, const QVector<QString>&, const QVector<Value> &args)
Value builtin_lookup(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
{
double p, low_p, low_v, high_p, high_v;
if (args.size() < 2 || !args[0].getnum(p) || args[1].vec.size() < 2 || args[1].vec[0]->vec.size() < 2)
return Value();
if (!args[1].vec[0]->getv2(low_p, low_v) || !args[1].vec[0]->getv2(high_p, high_v))
return Value();
for (int i = 1; i < args[1].vec.size(); i++) {
for (size_t i = 1; i < args[1].vec.size(); i++) {
double this_p, this_v;
if (args[1].vec[i]->getv2(this_p, this_v)) {
if (this_p <= p && (this_p > low_p || low_p > p)) {
@ -370,8 +378,7 @@ void initialize_builtin_functions()
void destroy_builtin_functions()
{
foreach (AbstractFunction *v, builtin_functions)
delete v;
BOOST_FOREACH(BuiltinContainer::value_type &f, builtin_functions) delete f.second;
//std::for_each(builtin_functions.begin(), builtin_functions.end(), del_fun<AbstractFunction>());
builtin_functions.clear();
}

View File

@ -2,43 +2,43 @@
#define FUNCTION_H_
#include "value.h"
#include <QString>
#include <QVector>
#include <string>
#include <vector>
class AbstractFunction
{
public:
virtual ~AbstractFunction();
virtual Value evaluate(const class Context *ctx, const QVector<QString> &call_argnames, const QVector<Value> &call_argvalues) const;
virtual QString dump(QString indent, QString name) const;
virtual Value evaluate(const class Context *ctx, const std::vector<std::string> &call_argnames, const std::vector<Value> &call_argvalues) const;
virtual std::string dump(const std::string &indent, const std::string &name) const;
};
class BuiltinFunction : public AbstractFunction
{
public:
typedef Value (*eval_func_t)(const Context *ctx, const QVector<QString> &argnames, const QVector<Value> &args);
typedef Value (*eval_func_t)(const Context *ctx, const std::vector<std::string> &argnames, const std::vector<Value> &args);
eval_func_t eval_func;
BuiltinFunction(eval_func_t f) : eval_func(f) { }
virtual ~BuiltinFunction();
virtual Value evaluate(const Context *ctx, const QVector<QString> &call_argnames, const QVector<Value> &call_argvalues) const;
virtual QString dump(QString indent, QString name) const;
virtual Value evaluate(const Context *ctx, const std::vector<std::string> &call_argnames, const std::vector<Value> &call_argvalues) const;
virtual std::string dump(const std::string &indent, const std::string &name) const;
};
class Function : public AbstractFunction
{
public:
QVector<QString> argnames;
QVector<class Expression*> argexpr;
std::vector<std::string> argnames;
std::vector<class Expression*> argexpr;
Expression *expr;
Function() { }
virtual ~Function();
virtual Value evaluate(const Context *ctx, const QVector<QString> &call_argnames, const QVector<Value> &call_argvalues) const;
virtual QString dump(QString indent, QString name) const;
virtual Value evaluate(const Context *ctx, const std::vector<std::string> &call_argnames, const std::vector<Value> &call_argvalues) const;
virtual std::string dump(const std::string &indent, const std::string &name) const;
};
#endif

View File

@ -63,7 +63,7 @@ void GLView::init()
this->viewer_distance = 500;
this->object_rot_x = 35;
this->object_rot_y = 0;
this->object_rot_z = 25;
this->object_rot_z = -25;
this->object_trans_x = 0;
this->object_trans_y = 0;
this->object_trans_z = 0;

42
src/handle_dep.cc Normal file
View File

@ -0,0 +1,42 @@
#include "handle_dep.h"
#include "myqhash.h"
#include <string>
#include <sstream>
#include <QString>
#include <QDir>
#include <QSet>
#include <stdlib.h> // for system()
QSet<std::string> dependencies;
const char *make_command = NULL;
void handle_dep(const std::string &filename)
{
if (filename[0] == '/')
dependencies.insert(filename);
else {
QString dep = QDir::currentPath() + QString("/") + QString::fromStdString(filename);
dependencies.insert(dep.toStdString());
}
if (!QFile(QString::fromStdString(filename)).exists() && make_command) {
std::stringstream buf;
buf << make_command << " '" << QString::fromStdString(filename).replace("'", "'\\''").toUtf8().data() << "'";
system(buf.str().c_str()); // FIXME: Handle error
}
}
bool write_deps(const std::string &filename, const std::string &output_file)
{
FILE *fp = fopen(filename.c_str(), "wt");
if (!fp) {
fprintf(stderr, "Can't open dependencies file `%s' for writing!\n", filename.c_str());
return false;
}
fprintf(fp, "%s:", output_file.c_str());
QSetIterator<std::string> i(dependencies);
while (i.hasNext())
fprintf(fp, " \\\n\t%s", i.next().c_str());
fprintf(fp, "\n");
fclose(fp);
return true;
}

10
src/handle_dep.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef HANDLE_DEP_H_
#define HANDLE_DEP_H_
#include <string>
extern const char *make_command;
void handle_dep(const std::string &filename);
bool write_deps(const std::string &filename, const std::string &output_file);
#endif

View File

@ -33,39 +33,40 @@
#include "dxfdata.h"
#include "dxftess.h"
#include "printutils.h"
#include "openscad.h" // handle_dep()
#include "handle_dep.h" // handle_dep()
#ifdef ENABLE_CGAL
#include "cgalutils.h"
#endif
#include <QFile>
#include <QRegExp>
#include <QStringList>
#include <sys/types.h>
#include <sys/stat.h>
#include <fstream>
#include <sstream>
#include <assert.h>
#include <boost/assign/std/vector.hpp>
using namespace boost::assign; // bring 'operator+=()' into scope
class ImportModule : public AbstractModule
{
public:
import_type_e type;
ImportModule(import_type_e type) : type(type) { }
ImportModule(import_type_e type = TYPE_UNKNOWN) : type(type) { }
virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
};
AbstractNode *ImportModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
{
ImportNode *node = new ImportNode(inst, type);
QVector<QString> argnames;
if (this->type == TYPE_DXF) {
argnames = QVector<QString>() << "file" << "layer" << "convexity" << "origin" << "scale";
} else {
argnames = QVector<QString>() << "file" << "convexity";
}
QVector<Expression*> argexpr;
std::vector<std::string> argnames;
argnames += "file", "layer", "convexity", "origin", "scale";
std::vector<Expression*> argexpr;
// Map old argnames to new argnames for compatibility
QVector<QString> inst_argnames = inst->argnames;
for (int i=0; i<inst_argnames.size(); i++) {
std::vector<std::string> inst_argnames = inst->argnames;
for (size_t i=0; i<inst_argnames.size(); i++) {
if (inst_argnames[i] == "filename")
inst_argnames[i] = "file";
if (inst_argnames[i] == "layername")
@ -75,14 +76,24 @@ AbstractNode *ImportModule::evaluate(const Context *ctx, const ModuleInstantiati
Context c(ctx);
c.args(argnames, argexpr, inst_argnames, inst->argvalues);
Value v = c.lookup_variable("file");
std::string filename = c.getAbsolutePath(v.text);
import_type_e actualtype = this->type;
if (actualtype == TYPE_UNKNOWN) {
QFileInfo fi(QString::fromStdString(filename));
if (fi.suffix().toLower() == "stl") actualtype = TYPE_STL;
else if (fi.suffix().toLower() == "off") actualtype = TYPE_OFF;
else if (fi.suffix().toLower() == "dxf") actualtype = TYPE_DXF;
}
ImportNode *node = new ImportNode(inst, actualtype);
node->fn = c.lookup_variable("$fn").num;
node->fs = c.lookup_variable("$fs").num;
node->fa = c.lookup_variable("$fa").num;
Value v = c.lookup_variable("file");
node->filename = c.get_absolute_path(QString::fromStdString(v.text));
// node->filename = c.get_absolute_path(QString::fromStdString(c.lookup_variable("file").text));
node->layername = QString::fromStdString(c.lookup_variable("layer", true).text);
node->filename = filename;
node->layername = c.lookup_variable("layer", true).text;
node->convexity = c.lookup_variable("convexity", true).num;
if (node->convexity <= 0)
@ -100,27 +111,20 @@ AbstractNode *ImportModule::evaluate(const Context *ctx, const ModuleInstantiati
return node;
}
void register_builtin_import()
PolySet *ImportNode::evaluate_polyset(class PolySetEvaluator *evaluator) const
{
builtin_modules["import_stl"] = new ImportModule(TYPE_STL);
builtin_modules["import_off"] = new ImportModule(TYPE_OFF);
builtin_modules["import_dxf"] = new ImportModule(TYPE_DXF);
}
PolySet *ImportNode::evaluate_polyset(render_mode_e, class PolySetEvaluator *) const
{
PolySet *p = new PolySet();
p->convexity = this->convexity;
PolySet *p = NULL;
if (this->type == TYPE_STL)
{
handle_dep(this->filename);
QFile f(this->filename);
QFile f(QString::fromStdString(this->filename));
if (!f.open(QIODevice::ReadOnly)) {
PRINTF("WARNING: Can't open import file `%s'.", this->filename.toAscii().data());
PRINTF("WARNING: Can't open import file `%s'.", this->filename.c_str());
return p;
}
p = new PolySet();
QByteArray data = f.read(5);
if (data.size() == 5 && QString(data) == QString("solid"))
{
@ -189,19 +193,34 @@ PolySet *ImportNode::evaluate_polyset(render_mode_e, class PolySetEvaluator *) c
}
}
if (this->type == TYPE_OFF)
else if (this->type == TYPE_OFF)
{
PRINTF("WARNING: OFF import is not implemented yet.");
#ifdef ENABLE_CGAL
CGAL_Polyhedron poly;
std::ifstream file(this->filename.c_str());
file >> poly;
file.close();
p = createPolySetFromPolyhedron(poly);
#else
PRINTF("WARNING: OFF import requires CGAL.");
#endif
}
if (this->type == TYPE_DXF)
else if (this->type == TYPE_DXF)
{
p = new PolySet();
DxfData dd(this->fn, this->fs, this->fa, this->filename, this->layername, this->origin_x, this->origin_y, this->scale);
p->is2d = true;
dxf_tesselate(p, &dd, 0, true, false, 0);
dxf_border_to_ps(p, &dd);
dxf_tesselate(p, dd, 0, true, false, 0);
dxf_border_to_ps(p, dd);
}
else
{
PRINTF("ERROR: Unsupported file format while trying to import file '%s'", this->filename.c_str());
}
if (p) p->convexity = this->convexity;
return p;
}
@ -212,49 +231,30 @@ std::string ImportNode::toString() const
QString text;
struct stat st;
memset(&st, 0, sizeof(struct stat));
stat(this->filename.toAscii().data(), &st);
stat(this->filename.c_str(), &st);
stream << this->name();
switch (this->type) {
case TYPE_STL:
stream << "(file = \"" << this->filename << "\", "
"cache = \"" << std::hex << (int)st.st_mtime << "." << (int)st.st_size << "\", "
"convexity = " << std::dec << this->convexity << ")";
break;
case TYPE_OFF:
stream << "(file = \"" << this->filename << "\", "
"cache = \"" << std::hex << (int)st.st_mtime << "." << (int)st.st_size << "\", "
"convexity = " << std::dec << this->convexity << ")";
break;
case TYPE_DXF:
stream << "(file = \"" << this->filename << "\", "
"cache = \"" << std::hex << (int)st.st_mtime << "." << (int)st.st_size << "\", "
"layer = \"" << this->layername << "\", "
"origin = [ " << std::dec << this->origin_x << " " << this->origin_y << " ], "
"scale = " << this->scale << ", "
"convexity = " << this->convexity << ", "
"$fn = " << this->fn << ", $fa = " << this->fa << ", $fs = " << this->fs << ")";
break;
default:
assert(false);
}
stream << "(file = \"" << this->filename << "\", "
"cache = \"" << std::hex << (int)st.st_mtime << "." << (int)st.st_size << "\", "
"layer = \"" << this->layername << "\", "
"origin = [ " << std::dec << this->origin_x << " " << this->origin_y << " ], "
"scale = " << this->scale << ", "
"convexity = " << this->convexity << ", "
"$fn = " << this->fn << ", $fa = " << this->fa << ", $fs = " << this->fs << ")";
return stream.str();
}
std::string ImportNode::name() const
{
switch (this->type) {
case TYPE_STL:
return "import_stl";
break;
case TYPE_OFF:
return "import_off";
break;
case TYPE_DXF:
return "import_dxf";
break;
default:
assert(false);
}
return "import";
}
void register_builtin_import()
{
builtin_modules["import_stl"] = new ImportModule(TYPE_STL);
builtin_modules["import_off"] = new ImportModule(TYPE_OFF);
builtin_modules["import_dxf"] = new ImportModule(TYPE_DXF);
builtin_modules["import"] = new ImportModule();
}

View File

@ -3,9 +3,9 @@
#include "node.h"
#include "visitor.h"
#include <QString>
enum import_type_e {
TYPE_UNKNOWN,
TYPE_STL,
TYPE_OFF,
TYPE_DXF
@ -22,12 +22,12 @@ public:
virtual std::string name() const;
import_type_e type;
QString filename;
QString layername;
std::string filename;
std::string layername;
int convexity;
double fn, fs, fa;
double origin_x, origin_y, scale;
virtual PolySet *evaluate_polyset(render_mode_e mode, class PolySetEvaluator *) const;
virtual PolySet *evaluate_polyset(class PolySetEvaluator *) const;
};
#endif

View File

@ -26,12 +26,14 @@
%{
#include "openscad.h"
#include "handle_dep.h"
#include "openscad.h" // librarydir
#include "printutils.h"
#include "parser_yacc.h"
#include <QStack>
#include <QFileInfo>
#include <QDir>
#include <assert.h>
//isatty for visual c++
#ifdef _MSC_VER
@ -70,6 +72,7 @@ extern const char *parser_source_path;
void includefile();
QDir sourcepath();
QStack<QDir> path_stack;
QStack<FILE*> openfiles;
QString filename;
QString filepath;
@ -102,7 +105,7 @@ use[ \t\r\n>]*"<"[^ \t\r\n>]+">" {
if (!finfo.exists()) {
finfo = QFileInfo(QDir(librarydir), filename);
}
handle_dep(finfo.absoluteFilePath());
handle_dep(finfo.absoluteFilePath().toStdString());
parserlval.text = strdup(finfo.absoluteFilePath().toLocal8Bit());
return TOK_USE;
}
@ -116,11 +119,12 @@ use[ \t\r\n>]*"<"[^ \t\r\n>]+">" {
}
PRINTF("DEPRECATED: Support for implicit include will be removed in future releases. Use `include <filename>' instead.");
handle_dep(finfo.absoluteFilePath());
handle_dep(finfo.absoluteFilePath().toStdString());
yyin = fopen(finfo.absoluteFilePath().toLocal8Bit(), "r");
if (!yyin) {
PRINTF("WARNING: Can't open input file `%s'.", filename);
} else {
openfiles.append(yyin);
yypush_buffer_state(yy_create_buffer( yyin, YY_BUF_SIZE ));
BEGIN(INITIAL);
}
@ -128,10 +132,12 @@ use[ \t\r\n>]*"<"[^ \t\r\n>]+">" {
}
<<EOF>> {
if(!path_stack.isEmpty())
if(!path_stack.empty())
path_stack.pop();
if (yyin && yyin != stdin)
fclose(yyin);
if (yyin && yyin != stdin) {
assert(!openfiles.empty());
fclose(openfiles.pop());
}
yypop_buffer_state();
if (!YY_CURRENT_BUFFER)
yyterminate();
@ -182,7 +188,7 @@ use[ \t\r\n>]*"<"[^ \t\r\n>]+">" {
QDir sourcepath()
{
if(!path_stack.isEmpty())
if(!path_stack.empty())
return path_stack.top();
return QDir(parser_source_path);
@ -206,15 +212,26 @@ void includefile()
finfo = QFileInfo(QDir(librarydir), filename);
}
handle_dep(finfo.absoluteFilePath());
handle_dep(finfo.absoluteFilePath().toStdString());
yyin = fopen(finfo.absoluteFilePath().toLocal8Bit(), "r");
if (!yyin) {
PRINTA("WARNING: Can't open input file `%1'.", filename);
path_stack.pop();
return;
}
openfiles.append(yyin);
filename.clear();
yypush_buffer_state(yy_create_buffer( yyin, YY_BUF_SIZE ));
}
/*!
In case of an error, this will make sure we clean up our custom data structures
and close all files.
*/
void lexerdestroy()
{
foreach (FILE *f, openfiles) fclose(f);
openfiles.clear();
path_stack.clear();
}

View File

@ -24,6 +24,7 @@
*
*/
#include "PolySetCache.h"
#include "MainWindow.h"
#include "openscad.h" // examplesdir
#include "Preferences.h"
@ -46,8 +47,6 @@
#ifdef USE_PROGRESSWIDGET
#include "ProgressWidget.h"
#endif
#include "CGALEvaluator.h"
#include "PolySetCGALEvaluator.h"
#include "ThrownTogetherRenderer.h"
#include <QMenu>
@ -77,14 +76,22 @@
#include "qlanguagefactory.h"
#endif
#include <fstream>
#include <algorithm>
#include <boost/foreach.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
using namespace boost::lambda;
#ifdef ENABLE_CGAL
#include "cgalrenderer.h"
#include "CGALCache.h"
#include "CGALEvaluator.h"
#include "PolySetCGALEvaluator.h"
#include "CGALRenderer.h"
#include "CGAL_Nef_polyhedron.h"
#include "cgal.h"
#endif // ENABLE_CGAL
@ -335,6 +342,7 @@ MainWindow::MainWindow(const QString &filename)
} else {
setFileName("");
}
updateRecentFileActions();
connect(editor->document(), SIGNAL(contentsChanged()), this, SLOT(animateUpdateDocChanged()));
#ifdef _QCODE_EDIT_
@ -486,6 +494,7 @@ MainWindow::openFile(const QString &new_filename)
setFileName(new_filename);
load();
updateRecentFiles();
}
void
@ -493,7 +502,7 @@ MainWindow::setFileName(const QString &filename)
{
if (filename.isEmpty()) {
this->fileName.clear();
this->root_ctx.document_path = currentdir;
this->root_ctx.setDocumentPath(currentdir.toStdString());
setWindowTitle("OpenSCAD - New Document[*]");
}
else {
@ -505,21 +514,29 @@ MainWindow::setFileName(const QString &filename)
QString infoFileName = fileinfo.absoluteFilePath();
if (!infoFileName.isEmpty()) {
this->fileName = infoFileName;
QSettings settings; // already set up properly via main.cpp
QStringList files = settings.value("recentFileList").toStringList();
files.removeAll(this->fileName);
files.prepend(this->fileName);
while (files.size() > maxRecentFiles)
files.removeLast();
settings.setValue("recentFileList", files);
} else {
this->fileName = fileinfo.fileName();
}
this->root_ctx.document_path = fileinfo.dir().absolutePath();
this->root_ctx.setDocumentPath(fileinfo.dir().absolutePath().toStdString());
QDir::setCurrent(fileinfo.dir().absolutePath());
}
}
void MainWindow::updateRecentFiles()
{
// Check that the canonical file path exists - only update recent files
// if it does. Should prevent empty list items on initial open etc.
QFileInfo fileinfo(this->fileName);
QString infoFileName = fileinfo.absoluteFilePath();
QSettings settings; // already set up properly via main.cpp
QStringList files = settings.value("recentFileList").toStringList();
files.removeAll(infoFileName);
files.prepend(infoFileName);
while (files.size() > maxRecentFiles) files.removeLast();
settings.setValue("recentFileList", files);
foreach(QWidget *widget, QApplication::topLevelWidgets()) {
MainWindow *mainWin = qobject_cast<MainWindow *>(widget);
if (mainWin) {
@ -528,6 +545,7 @@ MainWindow::setFileName(const QString &filename)
}
}
void MainWindow::updatedFps()
{
bool fps_ok;
@ -576,7 +594,7 @@ void MainWindow::load()
AbstractNode *MainWindow::find_root_tag(AbstractNode *n)
{
foreach(AbstractNode *v, n->children) {
BOOST_FOREACH (AbstractNode *v, n->children) {
if (v->modinst->tag_root) return v;
if (AbstractNode *vroot = find_root_tag(v)) return vroot;
}
@ -665,7 +683,7 @@ void MainWindow::compile(bool procevents)
// Parse
this->last_compiled_doc = editor->toPlainText();
this->root_module = parse((this->last_compiled_doc + "\n" +
commandline_commands).toAscii().data(),
QString::fromStdString(commandline_commands)).toAscii().data(),
this->fileName.isEmpty() ?
"" :
QFileInfo(this->fileName).absolutePath().toLocal8Bit(),
@ -725,18 +743,7 @@ fail:
if (parser_error_pos < 0) {
PRINT("ERROR: Compilation failed! (no top level object found)");
} else {
int line = 1;
QByteArray pb = this->last_compiled_doc.toAscii();
char *p = pb.data();
for (int i = 0; i < parser_error_pos; i++) {
if (p[i] == '\n')
line++;
if (p[i] == 0) {
line = -1;
break;
}
}
PRINTF("ERROR: Compilation failed! (parser error in line %d)", line);
PRINT("ERROR: Compilation failed!");
}
if (procevents)
QApplication::processEvents();
@ -774,9 +781,7 @@ void MainWindow::compileCSG(bool procevents)
progress_report_prep(root_node, report_func, pd);
try {
// FIXME: put cache somewhere else as it's pretty useless now
QHash<std::string, CGAL_Nef_polyhedron> cache;
CGALEvaluator cgalevaluator(cache, this->tree);
CGALEvaluator cgalevaluator(this->tree);
PolySetCGALEvaluator psevaluator(cgalevaluator);
CSGTermEvaluator csgrenderer(this->tree, &psevaluator);
root_raw_term = csgrenderer.evaluateCSGTerm(*root_node, highlight_terms, background_terms);
@ -785,6 +790,8 @@ void MainWindow::compileCSG(bool procevents)
if (procevents)
QApplication::processEvents();
}
PolySetCache::instance()->print();
CGALCache::instance()->print();
}
catch (ProgressCancelException e) {
PRINT("CSG generation cancelled.");
@ -859,6 +866,7 @@ void MainWindow::compileCSG(bool procevents)
PRINTF("WARNING: OpenCSG rendering has been disabled.");
}
else {
PRINTF("Normalized CSG tree has %d elements", root_chain->polysets.size());
this->opencsgRenderer = new OpenCSGRenderer(this->root_chain,
this->highlights_chain,
this->background_chain,
@ -893,7 +901,9 @@ void MainWindow::actionOpen()
{
QString new_filename = QFileDialog::getOpenFileName(this, "Open File", "", "OpenSCAD Designs (*.scad)");
#ifdef ENABLE_MDI
new MainWindow(new_filename);
if (!new_filename.isEmpty()) {
new MainWindow(new_filename);
}
#else
if (!new_filename.isEmpty()) {
if (!maybeSave())
@ -991,6 +1001,7 @@ void MainWindow::actionSave()
this->editor->setContentModified(false);
}
clearCurrentOutput();
updateRecentFiles();
}
}
@ -1212,10 +1223,10 @@ void MainWindow::actionRenderCGAL()
progress_report_prep(this->root_node, report_func, pd);
try {
// FIXME: put cache somewhere else as it's pretty useless now
QHash<std::string, CGAL_Nef_polyhedron> cache;
CGALEvaluator evaluator(cache, this->tree);
CGALEvaluator evaluator(this->tree);
this->root_N = new CGAL_Nef_polyhedron(evaluator.evaluateCGALMesh(*this->root_node));
PolySetCache::instance()->print();
CGALCache::instance()->print();
}
catch (ProgressCancelException e) {
PRINT("Rendering cancelled.");
@ -1232,57 +1243,62 @@ void MainWindow::actionRenderCGAL()
if (this->root_N->dim == 2) {
PRINTF(" Top level object is a 2D object:");
QApplication::processEvents();
PRINTF(" Empty: %6s", this->root_N->p2.is_empty() ? "yes" : "no");
PRINTF(" Empty: %6s", this->root_N->p2->is_empty() ? "yes" : "no");
QApplication::processEvents();
PRINTF(" Plane: %6s", this->root_N->p2.is_plane() ? "yes" : "no");
PRINTF(" Plane: %6s", this->root_N->p2->is_plane() ? "yes" : "no");
QApplication::processEvents();
PRINTF(" Vertices: %6d", (int)this->root_N->p2.explorer().number_of_vertices());
PRINTF(" Vertices: %6d", (int)this->root_N->p2->explorer().number_of_vertices());
QApplication::processEvents();
PRINTF(" Halfedges: %6d", (int)this->root_N->p2.explorer().number_of_halfedges());
PRINTF(" Halfedges: %6d", (int)this->root_N->p2->explorer().number_of_halfedges());
QApplication::processEvents();
PRINTF(" Edges: %6d", (int)this->root_N->p2.explorer().number_of_edges());
PRINTF(" Edges: %6d", (int)this->root_N->p2->explorer().number_of_edges());
QApplication::processEvents();
PRINTF(" Faces: %6d", (int)this->root_N->p2.explorer().number_of_faces());
PRINTF(" Faces: %6d", (int)this->root_N->p2->explorer().number_of_faces());
QApplication::processEvents();
PRINTF(" FaceCycles: %6d", (int)this->root_N->p2.explorer().number_of_face_cycles());
PRINTF(" FaceCycles: %6d", (int)this->root_N->p2->explorer().number_of_face_cycles());
QApplication::processEvents();
PRINTF(" ConnComp: %6d", (int)this->root_N->p2.explorer().number_of_connected_components());
PRINTF(" ConnComp: %6d", (int)this->root_N->p2->explorer().number_of_connected_components());
QApplication::processEvents();
}
if (this->root_N->dim == 3) {
PRINTF(" Top level object is a 3D object:");
PRINTF(" Simple: %6s", this->root_N->p3.is_simple() ? "yes" : "no");
PRINTF(" Simple: %6s", this->root_N->p3->is_simple() ? "yes" : "no");
QApplication::processEvents();
PRINTF(" Valid: %6s", this->root_N->p3.is_valid() ? "yes" : "no");
PRINTF(" Valid: %6s", this->root_N->p3->is_valid() ? "yes" : "no");
QApplication::processEvents();
PRINTF(" Vertices: %6d", (int)this->root_N->p3.number_of_vertices());
PRINTF(" Vertices: %6d", (int)this->root_N->p3->number_of_vertices());
QApplication::processEvents();
PRINTF(" Halfedges: %6d", (int)this->root_N->p3.number_of_halfedges());
PRINTF(" Halfedges: %6d", (int)this->root_N->p3->number_of_halfedges());
QApplication::processEvents();
PRINTF(" Edges: %6d", (int)this->root_N->p3.number_of_edges());
PRINTF(" Edges: %6d", (int)this->root_N->p3->number_of_edges());
QApplication::processEvents();
PRINTF(" Halffacets: %6d", (int)this->root_N->p3.number_of_halffacets());
PRINTF(" Halffacets: %6d", (int)this->root_N->p3->number_of_halffacets());
QApplication::processEvents();
PRINTF(" Facets: %6d", (int)this->root_N->p3.number_of_facets());
PRINTF(" Facets: %6d", (int)this->root_N->p3->number_of_facets());
QApplication::processEvents();
PRINTF(" Volumes: %6d", (int)this->root_N->p3.number_of_volumes());
PRINTF(" Volumes: %6d", (int)this->root_N->p3->number_of_volumes());
QApplication::processEvents();
}
int s = t.elapsed() / 1000;
PRINTF("Total rendering time: %d hours, %d minutes, %d seconds", s / (60*60), (s / 60) % 60, s % 60);
this->cgalRenderer = new CGALRenderer(*this->root_N);
// Go to CGAL view mode
if (viewActionCGALGrid->isChecked()) {
viewModeCGALGrid();
if (!this->root_N->empty()) {
this->cgalRenderer = new CGALRenderer(*this->root_N);
// Go to CGAL view mode
if (viewActionCGALGrid->isChecked()) {
viewModeCGALGrid();
}
else {
viewModeCGALSurface();
}
PRINT("Rendering finished.");
}
else {
viewModeCGALSurface();
PRINT("WARNING: No top level geometry to render");
}
PRINT("Rendering finished.");
}
#ifdef USE_PROGRESSWIDGET
@ -1303,7 +1319,7 @@ void MainWindow::actionDisplayAST()
e->setWindowTitle("AST Dump");
e->setReadOnly(true);
if (root_module) {
e->setPlainText(root_module->dump("", ""));
e->setPlainText(QString::fromStdString(root_module->dump("", "")));
} else {
e->setPlainText("No AST to dump. Please try compiling first...");
}
@ -1338,7 +1354,7 @@ void MainWindow::actionDisplayCSGProducts()
e->setTabStopWidth(30);
e->setWindowTitle("CSG Products Dump");
e->setReadOnly(true);
e->setPlainText(QString("\nCSG before normalization:\n%1\n\n\nCSG after normalization:\n%2\n\n\nCSG rendering chain:\n%3\n\n\nHighlights CSG rendering chain:\n%4\n\n\nBackground CSG rendering chain:\n%5\n").arg(root_raw_term ? root_raw_term->dump() : "N/A", root_norm_term ? root_norm_term->dump() : "N/A", root_chain ? root_chain->dump() : "N/A", highlights_chain ? highlights_chain->dump() : "N/A", background_chain ? background_chain->dump() : "N/A"));
e->setPlainText(QString("\nCSG before normalization:\n%1\n\n\nCSG after normalization:\n%2\n\n\nCSG rendering chain:\n%3\n\n\nHighlights CSG rendering chain:\n%4\n\n\nBackground CSG rendering chain:\n%5\n").arg(root_raw_term ? QString::fromStdString(root_raw_term->dump()) : "N/A", root_norm_term ? QString::fromStdString(root_norm_term->dump()) : "N/A", root_chain ? QString::fromStdString(root_chain->dump()) : "N/A", highlights_chain ? QString::fromStdString(highlights_chain->dump()) : "N/A", background_chain ? QString::fromStdString(background_chain->dump()) : "N/A"));
e->show();
e->resize(600, 400);
clearCurrentOutput();
@ -1367,7 +1383,7 @@ void MainWindow::actionExportSTLorOFF(bool)
return;
}
if (!this->root_N->p3.is_simple()) {
if (!this->root_N->p3->is_simple()) {
PRINT("Object isn't a valid 2-manifold! Modify your design..");
clearCurrentOutput();
return;
@ -1386,21 +1402,20 @@ void MainWindow::actionExportSTLorOFF(bool)
QProgressDialog *pd = new QProgressDialog(
stl_mode ? "Exporting object to STL file..." : "Exporting object to OFF file...",
QString(), 0, this->root_N->p3.number_of_facets() + 1);
QString(), 0, this->root_N->p3->number_of_facets() + 1);
pd->setValue(0);
pd->setAutoClose(false);
pd->show();
QApplication::processEvents();
QFile file(stl_filename);
if (!file.open(QIODevice::ReadWrite)) {
std::ofstream fstream(stl_filename.toUtf8());
if (!fstream.is_open()) {
PRINTA("Can't open file \"%1\" for export", stl_filename);
}
else {
QTextStream fstream(&file);
if (stl_mode) export_stl(this->root_N, fstream, pd);
else export_off(this->root_N, fstream, pd);
file.close();
fstream.close();
PRINTF("%s export finished.", stl_mode ? "STL" : "OFF");
}
@ -1447,14 +1462,13 @@ void MainWindow::actionExportDXF()
return;
}
QFile file(dxf_filename);
if (!file.open(QIODevice::ReadWrite)) {
PRINTA("Can't open file \"%1\" for export", dxf_filename);
std::ofstream fstream(dxf_filename.toUtf8());
if (!fstream.is_open()) {
PRINTA("Can't open file \"%s\" for export", dxf_filename);
}
else {
QTextStream fstream(&file);
export_dxf(this->root_N, fstream, NULL);
file.close();
fstream.close();
PRINTF("DXF export finished.");
}
@ -1482,12 +1496,9 @@ void MainWindow::actionExportImage()
void MainWindow::actionFlushCaches()
{
// FIXME: Polycache -> PolySetEvaluator
// FIXME: PolySetEvaluator->clearCache();
PolySetCache::instance()->clear();
#ifdef ENABLE_CGAL
// FIXME: Flush caches through whatever channels we have
// CGALEvaluator::evaluator()->getCache().clear();
// this->dumper->clearCache();
CGALCache::instance()->clear();
#endif
dxf_dim_cache.clear();
dxf_cross_cache.clear();
@ -1660,7 +1671,7 @@ void MainWindow::viewAngleDiagonal()
{
this->glview->object_rot_x = 35;
this->glview->object_rot_y = 0;
this->glview->object_rot_z = 25;
this->glview->object_rot_z = -25;
this->glview->updateGL();
}

7
src/memory.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef MEMORY_H_
#define MEMORY_H_
#include <boost/shared_ptr.hpp>
using boost::shared_ptr;
#endif

View File

@ -31,6 +31,8 @@
#include "function.h"
#include "builtin.h"
#include "printutils.h"
#include <boost/foreach.hpp>
#include <sstream>
AbstractModule::~AbstractModule()
{
@ -40,91 +42,102 @@ AbstractNode *AbstractModule::evaluate(const Context*, const ModuleInstantiation
{
AbstractNode *node = new AbstractNode(inst);
foreach (ModuleInstantiation *v, inst->children) {
AbstractNode *n = v->evaluate(inst->ctx);
if (n)
node->children.push_back(n);
}
node->children = inst->evaluateChildren();
return node;
}
QString AbstractModule::dump(QString indent, QString name) const
std::string AbstractModule::dump(const std::string &indent, const std::string &name) const
{
return QString("%1abstract module %2();\n").arg(indent, name);
std::stringstream dump;
dump << indent << "abstract module " << name << "();\n";
return dump.str();
}
ModuleInstantiation::~ModuleInstantiation()
{
foreach (Expression *v, argexpr)
delete v;
foreach (ModuleInstantiation *v, children)
delete v;
BOOST_FOREACH (Expression *v, argexpr) delete v;
BOOST_FOREACH (ModuleInstantiation *v, children) delete v;
}
IfElseModuleInstantiation::~IfElseModuleInstantiation()
{
foreach (ModuleInstantiation *v, else_children)
delete v;
BOOST_FOREACH (ModuleInstantiation *v, else_children) delete v;
}
QString ModuleInstantiation::dump(QString indent) const
std::string ModuleInstantiation::dump(const std::string &indent) const
{
QString text = indent;
if (!label.isEmpty())
text += label + QString(": ");
text += modname + QString("(");
for (int i=0; i < argnames.size(); i++) {
if (i > 0)
text += QString(", ");
if (!argnames[i].isEmpty())
text += argnames[i] + QString(" = ");
text += QString::fromStdString(argexpr[i]->toString());
std::stringstream dump;
dump << indent;
if (!label.empty()) dump << label <<": ";
dump << modname + "(";
for (size_t i=0; i < argnames.size(); i++) {
if (i > 0) dump << ", ";
if (!argnames[i].empty()) dump << argnames[i] << " = ";
dump << *argexpr[i];
}
if (children.size() == 0) {
text += QString(");\n");
dump << ");\n";
} else if (children.size() == 1) {
text += QString(")\n");
text += children[0]->dump(indent + QString("\t"));
dump << ")\n";
dump << children[0]->dump(indent + "\t");
} else {
text += QString(") {\n");
for (int i = 0; i < children.size(); i++) {
text += children[i]->dump(indent + QString("\t"));
dump << ") {\n";
for (size_t i = 0; i < children.size(); i++) {
dump << children[i]->dump(indent + "\t");
}
text += QString("%1}\n").arg(indent);
dump << indent << "}\n";
}
return text;
return dump.str();
}
AbstractNode *ModuleInstantiation::evaluate(const Context *ctx) const
{
AbstractNode *node = NULL;
if (this->ctx) {
PRINTA("WARNING: Ignoring recursive module instanciation of '%1'.", modname);
PRINTF("WARNING: Ignoring recursive module instantiation of '%s'.", modname.c_str());
} else {
ModuleInstantiation *that = (ModuleInstantiation*)this;
that->argvalues.clear();
foreach (Expression *v, that->argexpr) {
that->argvalues.append(v->evaluate(ctx));
BOOST_FOREACH (Expression *v, that->argexpr) {
that->argvalues.push_back(v->evaluate(ctx));
}
that->ctx = ctx;
node = ctx->evaluate_module(this);
node = ctx->evaluate_module(*this);
that->ctx = NULL;
that->argvalues.clear();
}
return node;
}
std::vector<AbstractNode*> ModuleInstantiation::evaluateChildren(const Context *ctx) const
{
if (!ctx) ctx = this->ctx;
std::vector<AbstractNode*> childnodes;
BOOST_FOREACH (ModuleInstantiation *v, this->children) {
AbstractNode *n = v->evaluate(ctx);
if (n != NULL) childnodes.push_back(n);
}
return childnodes;
}
std::vector<AbstractNode*> IfElseModuleInstantiation::evaluateElseChildren(const Context *ctx) const
{
if (!ctx) ctx = this->ctx;
std::vector<AbstractNode*> childnodes;
BOOST_FOREACH (ModuleInstantiation *v, this->else_children) {
AbstractNode *n = v->evaluate(this->ctx);
if (n != NULL) childnodes.push_back(n);
}
return childnodes;
}
Module::~Module()
{
foreach (Expression *v, assignments_expr)
delete v;
foreach (AbstractFunction *v, functions)
delete v;
foreach (AbstractModule *v, modules)
delete v;
foreach (ModuleInstantiation *v, children)
delete v;
BOOST_FOREACH (Expression *v, assignments_expr) delete v;
BOOST_FOREACH (FunctionContainer::value_type &f, functions) delete f.second;
BOOST_FOREACH (AbstractModuleContainer::value_type &m, modules) delete m.second;
BOOST_FOREACH (ModuleInstantiation *v, children) delete v;
}
AbstractNode *Module::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
@ -143,12 +156,12 @@ AbstractNode *Module::evaluate(const Context *ctx, const ModuleInstantiation *in
else
c.usedlibs_p = NULL;
for (int i = 0; i < assignments_var.size(); i++) {
for (size_t i = 0; i < assignments_var.size(); i++) {
c.set_variable(assignments_var[i], assignments_expr[i]->evaluate(&c));
}
AbstractNode *node = new AbstractNode(inst);
for (int i = 0; i < children.size(); i++) {
for (size_t i = 0; i < children.size(); i++) {
AbstractNode *n = children[i]->evaluate(&c);
if (n != NULL)
node->children.push_back(n);
@ -157,48 +170,39 @@ AbstractNode *Module::evaluate(const Context *ctx, const ModuleInstantiation *in
return node;
}
QString Module::dump(QString indent, QString name) const
std::string Module::dump(const std::string &indent, const std::string &name) const
{
QString text, tab;
if (!name.isEmpty()) {
text = QString("%1module %2(").arg(indent, name);
for (int i=0; i < argnames.size(); i++) {
if (i > 0)
text += QString(", ");
text += argnames[i];
if (argexpr[i])
text += QString(" = ") + QString::fromStdString(argexpr[i]->toString());
std::stringstream dump;
std::string tab;
if (!name.empty()) {
dump << indent << "module " << name << "(";
for (size_t i=0; i < argnames.size(); i++) {
if (i > 0) dump << ", ";
dump << argnames[i];
if (argexpr[i]) dump << " = " << *argexpr[i];
}
text += QString(") {\n");
dump << ") {\n";
tab = "\t";
}
{
QHashIterator<QString, AbstractFunction*> i(functions);
while (i.hasNext()) {
i.next();
text += i.value()->dump(indent + tab, i.key());
}
BOOST_FOREACH(const FunctionContainer::value_type &f, functions) {
dump << f.second->dump(indent + tab, f.first);
}
{
QHashIterator<QString, AbstractModule*> i(modules);
while (i.hasNext()) {
i.next();
text += i.value()->dump(indent + tab, i.key());
}
BOOST_FOREACH(const AbstractModuleContainer::value_type &m, modules) {
dump << m.second->dump(indent + tab, m.first);
}
for (int i = 0; i < assignments_var.size(); i++) {
text += QString("%1%2 = %3;\n").arg(indent + tab, assignments_var[i], QString::fromStdString(assignments_expr[i]->toString()));
for (size_t i = 0; i < assignments_var.size(); i++) {
dump << indent << tab << assignments_var[i] << " = " << *assignments_expr[i] << ";\n";
}
for (int i = 0; i < children.size(); i++) {
text += children[i]->dump(indent + tab);
for (size_t i = 0; i < children.size(); i++) {
dump << children[i]->dump(indent + tab);
}
if (!name.isEmpty()) {
text += QString("%1}\n").arg(indent);
if (!name.empty()) {
dump << indent << "}\n";
}
return text;
return dump.str();
}
QHash<QString, AbstractModule*> builtin_modules;
Module::AbstractModuleContainer builtin_modules;
void initialize_builtin_modules()
{
@ -206,6 +210,7 @@ void initialize_builtin_modules()
register_builtin_csgops();
register_builtin_transform();
register_builtin_color();
register_builtin_primitives();
register_builtin_surface();
register_builtin_control();
@ -219,7 +224,8 @@ void initialize_builtin_modules()
void destroy_builtin_modules()
{
foreach (AbstractModule *v, builtin_modules)
delete v;
BOOST_FOREACH(Module::AbstractModuleContainer::value_type &m, builtin_modules) {
delete m.second;
}
builtin_modules.clear();
}

View File

@ -1,20 +1,20 @@
#ifndef MODULE_H_
#define MODULE_H_
#include <QString>
#include <QVector>
#include <QHash>
#include <string>
#include <vector>
#include <boost/unordered_map.hpp>
#include "value.h"
class ModuleInstantiation
{
public:
QString label;
QString modname;
QVector<QString> argnames;
QVector<class Expression*> argexpr;
QVector<Value> argvalues;
QVector<ModuleInstantiation*> children;
std::string label;
std::string modname;
std::vector<std::string> argnames;
std::vector<class Expression*> argexpr;
std::vector<Value> argvalues;
std::vector<ModuleInstantiation*> children;
bool tag_root;
bool tag_highlight;
@ -24,15 +24,17 @@ public:
ModuleInstantiation() : tag_root(false), tag_highlight(false), tag_background(false), ctx(NULL) { }
virtual ~ModuleInstantiation();
QString dump(QString indent) const;
std::string dump(const std::string &indent) const;
class AbstractNode *evaluate(const Context *ctx) const;
std::vector<AbstractNode*> evaluateChildren(const Context *ctx = NULL) const;
};
class IfElseModuleInstantiation : public ModuleInstantiation {
public:
virtual ~IfElseModuleInstantiation();
std::vector<AbstractNode*> evaluateElseChildren(const Context *ctx = NULL) const;
QVector<ModuleInstantiation*> else_children;
std::vector<ModuleInstantiation*> else_children;
};
class AbstractModule
@ -40,37 +42,40 @@ class AbstractModule
public:
virtual ~AbstractModule();
virtual class AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
virtual QString dump(QString indent, QString name) const;
virtual std::string dump(const std::string &indent, const std::string &name) const;
};
class Module : public AbstractModule
{
public:
QHash< QString, Module*> usedlibs;
typedef boost::unordered_map<std::string, class Module*> ModuleContainer;
ModuleContainer usedlibs;
struct libs_cache_ent {
Module *mod;
QString cache_id, msg;
std::string cache_id, msg;
};
static QHash<QString, libs_cache_ent> libs_cache;
static Module *compile_library(QString filename);
static boost::unordered_map<std::string, libs_cache_ent> libs_cache;
static Module *compile_library(std::string filename);
QVector<QString> argnames;
QVector<Expression*> argexpr;
std::vector<std::string> argnames;
std::vector<Expression*> argexpr;
QVector<QString> assignments_var;
QVector<Expression*> assignments_expr;
std::vector<std::string> assignments_var;
std::vector<Expression*> assignments_expr;
QHash<QString, class AbstractFunction*> functions;
QHash<QString, AbstractModule*> modules;
typedef boost::unordered_map<std::string, class AbstractFunction*> FunctionContainer;
FunctionContainer functions;
typedef boost::unordered_map<std::string, AbstractModule*> AbstractModuleContainer;
AbstractModuleContainer modules;
QVector<ModuleInstantiation*> children;
std::vector<ModuleInstantiation*> children;
Module() { }
virtual ~Module();
virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
virtual QString dump(QString indent, QString name) const;
virtual std::string dump(const std::string &indent, const std::string &name) const;
};
#endif

View File

@ -36,6 +36,8 @@ public:
overloaded to provide specialization for e.g. CSG nodes, primitive nodes etc.
Used for human-readable output. */
virtual std::string name() const;
/*! Should return a PolySet of the given geometry. Returns NULL if smth. goes wrong */
virtual class PolySet *evaluate_polyset(class PolySetEvaluator *) const { return NULL; }
// FIXME: Make return value a reference
const std::vector<AbstractNode*> &getChildren() const {
@ -79,10 +81,6 @@ public:
RENDER_CGAL,
RENDER_OPENCSG
};
/*! Should return a PolySet of the given geometry. It's normal to return an
empty PolySet if smth. is wrong, but don't return NULL unless we change the calling
strategy for this method. */
virtual class PolySet *evaluate_polyset(render_mode_e mode, class PolySetEvaluator *evaluator) const = 0;
};
std::ostream &operator<<(std::ostream &stream, const AbstractNode &node);

View File

@ -25,9 +25,10 @@ public:
else return this->nullvalue;
}
void insert(const class AbstractNode &node, const std::string & value) {
/*! Returns a reference to the cached string copy */
const std::string &insert(const class AbstractNode &node, const std::string & value) {
if (this->cache.size() <= node.index()) this->cache.resize(node.index() + 1);
this->cache[node.index()] = value;
return this->cache[node.index()] = value;
}
void remove(const class AbstractNode &node) {

View File

@ -24,6 +24,7 @@
*
*/
#include "myqhash.h"
#include "openscad.h"
#include "MainWindow.h"
#include "node.h"
@ -33,16 +34,18 @@
#include "export.h"
#include "builtin.h"
#include "nodedumper.h"
#include "CGALEvaluator.h"
#include "PolySetCGALEvaluator.h"
#include "printutils.h"
#include "handle_dep.h"
#include <string>
#include <vector>
#include <fstream>
#ifdef ENABLE_CGAL
#include "cgal.h"
#include "CGAL_Nef_polyhedron.h"
#include <CGAL/assertions_behaviour.h>
#include "CGALEvaluator.h"
#include "PolySetCGALEvaluator.h"
#endif
#include <QApplication>
@ -52,6 +55,7 @@
#include <QSettings>
#include <QTextStream>
#include <boost/program_options.hpp>
#include <sstream>
#ifdef Q_WS_MAC
#include "EventFilter.h"
@ -80,9 +84,7 @@ static void version()
exit(1);
}
QString commandline_commands;
const char *make_command = NULL;
QSet<QString> dependencies;
std::string commandline_commands;
QString currentdir;
QString examplesdir;
QString librarydir;
@ -90,19 +92,6 @@ QString librarydir;
using std::string;
using std::vector;
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); // FIXME: Handle error
}
}
int main(int argc, char **argv)
{
int rc = 0;
@ -200,8 +189,8 @@ int main(int argc, char **argv)
const vector<string> &commands = vm["D"].as<vector<string> >();
for (vector<string>::const_iterator i = commands.begin(); i != commands.end(); i++) {
commandline_commands.append(i->c_str());
commandline_commands.append(";\n");
commandline_commands += *i;
commandline_commands += ";\n";
}
}
@ -259,10 +248,10 @@ int main(int argc, char **argv)
NodeCache nodecache;
NodeDumper dumper(nodecache);
Tree tree;
// FIXME: enforce some maximum cache size (old version had 100K vertices as limit)
QHash<std::string, CGAL_Nef_polyhedron> cache;
CGALEvaluator cgalevaluator(cache, tree);
#ifdef ENABLE_CGAL
CGALEvaluator cgalevaluator(tree);
PolySetCGALEvaluator psevaluator(cgalevaluator);
#endif
if (stl_output_file || off_output_file || dxf_output_file)
{
@ -298,15 +287,17 @@ int main(int argc, char **argv)
fprintf(stderr, "Can't open input file `%s'!\n", filename);
exit(1);
} else {
QString text;
std::stringstream text;
char buffer[513];
int ret;
while ((ret = fread(buffer, 1, 512, fp)) > 0) {
buffer[ret] = 0;
text += buffer;
text << buffer;
}
fclose(fp);
root_module = parse((text+commandline_commands).toAscii().data(), fileInfo.absolutePath().toLocal8Bit(), false);
text << commandline_commands;
root_module = parse(text.str().c_str(), fileInfo.absolutePath().toLocal8Bit(), false);
if (!root_module) exit(1);
}
QDir::setCurrent(fileInfo.absolutePath());
@ -320,19 +311,13 @@ int main(int argc, char **argv)
QDir::setCurrent(original_path.absolutePath());
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);
if (!write_deps(deps_output_file,
stl_output_file ? stl_output_file : off_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);
}
<<<<<<< HEAD
if (root_N.dim == 3 && !root_N.p3.is_simple()) {
fprintf(stderr, "Object isn't a valid 2-manifold! Modify your design.\n");
exit(1);
@ -340,28 +325,54 @@ int main(int argc, char **argv)
if (stl_output_file)
export_stl(&root_N, stl_output_file, NULL);
if (off_output_file) {
QFile file(stl_output_file);
if (!file.open(QIODevice::ReadWrite)) {
PRINTA("Can't open file \"%1\" for export", stl_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();
}
}
>>>>>>> upstream/visitor
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 {
QTextStream fstream(&file);
export_off(&root_N, fstream, NULL);
file.close();
fstream.close();
}
}
if (dxf_output_file) {
QFile file(stl_output_file);
if (!file.open(QIODevice::ReadWrite)) {
PRINTA("Can't open file \"%1\" for export", stl_output_file);
std::ofstream fstream(dxf_output_file);
if (!fstream.is_open()) {
PRINTF("Can't open file \"%s\" for export", dxf_output_file);
}
else {
QTextStream fstream(&file);
export_dxf(&root_N, fstream, NULL);
file.close();
fstream.close();
}
}

View File

@ -41,12 +41,11 @@
extern class AbstractModule *parse(const char *text, const char *path, int debug);
extern int get_fragments_from_r(double r, double fn, double fs, double fa);
#include <QString>
extern QString commandline_commands;
#include <string>
extern std::string commandline_commands;
extern int parser_error_pos;
extern void handle_dep(QString filename);
#include <QString>
// The CWD when application started. We shouldn't change CWD, but until we stop
// doing this, use currentdir to get the original CWD.
extern QString currentdir;

View File

@ -44,6 +44,8 @@
#include "value.h"
#include "function.h"
#include "printutils.h"
#include <sstream>
#include <boost/foreach.hpp>
int parser_error_pos = -1;
@ -54,18 +56,18 @@ int lexerget_lineno(void);
int lexerlex_destroy(void);
int lexerlex(void);
QVector<Module*> module_stack;
std::vector<Module*> module_stack;
Module *module;
class ArgContainer {
public:
QString argname;
public:
std::string argname;
Expression *argexpr;
};
class ArgsContainer {
public:
QVector<QString> argnames;
QVector<Expression*> argexpr;
std::vector<std::string> argnames;
std::vector<Expression*> argexpr;
};
%}
@ -144,29 +146,29 @@ statement:
'{' inner_input '}' |
module_instantiation {
if ($1) {
module->children.append($1);
module->children.push_back($1);
} else {
delete $1;
}
} |
TOK_ID '=' expr ';' {
bool add_new_assignment = true;
for (int i = 0; i < module->assignments_var.size(); i++) {
if (module->assignments_var[i] != QString($1))
for (size_t i = 0; i < module->assignments_var.size(); i++) {
if (module->assignments_var[i] != $1)
continue;
delete module->assignments_expr[i];
module->assignments_expr[i] = $3;
add_new_assignment = false;
}
if (add_new_assignment) {
module->assignments_var.append($1);
module->assignments_expr.append($3);
module->assignments_var.push_back($1);
module->assignments_expr.push_back($3);
free($1);
}
} |
TOK_MODULE TOK_ID '(' arguments_decl optional_commas ')' {
Module *p = module;
module_stack.append(module);
module_stack.push_back(module);
module = new Module();
p->modules[$2] = module;
module->argnames = $4->argnames;
@ -174,7 +176,7 @@ statement:
free($2);
delete $4;
} statement {
module = module_stack.last();
module = module_stack.back();
module_stack.pop_back();
} |
TOK_FUNCTION TOK_ID '(' arguments_decl optional_commas ')' '=' expr {
@ -192,7 +194,7 @@ children_instantiation:
module_instantiation {
$$ = new ModuleInstantiation();
if ($1) {
$$->children.append($1);
$$->children.push_back($1);
} else {
delete $1;
}
@ -205,13 +207,13 @@ if_statement:
TOK_IF '(' expr ')' children_instantiation {
$$ = new IfElseModuleInstantiation();
$$->modname = "if";
$$->argnames.append(QString());
$$->argexpr.append($3);
$$->argnames.push_back("");
$$->argexpr.push_back($3);
if ($$) {
$$->children = $5->children;
} else {
for (int i = 0; i < $5->children.count(); i++)
for (size_t i = 0; i < $5->children.size(); i++)
delete $5->children[i];
}
$5->children.clear();
@ -227,7 +229,7 @@ ifelse_statement:
if ($$) {
$$->else_children = $3->children;
} else {
for (int i = 0; i < $3->children.count(); i++)
for (size_t i = 0; i < $3->children.size(); i++)
delete $3->children[i];
}
$3->children.clear();
@ -243,7 +245,7 @@ module_instantiation:
if ($$) {
$$->children = $2->children;
} else {
for (int i = 0; i < $2->children.count(); i++)
for (size_t i = 0; i < $2->children.size(); i++)
delete $2->children[i];
}
$2->children.clear();
@ -261,7 +263,7 @@ module_instantiation_list:
$$ = $1;
if ($$) {
if ($2)
$$->children.append($2);
$$->children.push_back($2);
} else {
delete $2;
}
@ -270,7 +272,7 @@ module_instantiation_list:
single_module_instantiation:
TOK_ID '(' arguments_call ')' {
$$ = new ModuleInstantiation();
$$->modname = QString($1);
$$->modname = $1;
$$->argnames = $3->argnames;
$$->argexpr = $3->argexpr;
free($1);
@ -279,7 +281,7 @@ single_module_instantiation:
TOK_ID ':' single_module_instantiation {
$$ = $3;
if ($$)
$$->label = QString($1);
$$->label = $1;
free($1);
} |
'!' single_module_instantiation {
@ -321,14 +323,14 @@ expr:
TOK_ID {
$$ = new Expression();
$$->type = "L";
$$->var_name = QString($1);
$$->var_name = $1;
free($1);
} |
expr '.' TOK_ID {
$$ = new Expression();
$$->type = "N";
$$->children.append($1);
$$->var_name = QString($3);
$$->children.push_back($1);
$$->var_name = $3;
free($3);
} |
TOK_STRING {
@ -348,16 +350,16 @@ expr:
e_one->const_value = new Value(1.0);
$$ = new Expression();
$$->type = "R";
$$->children.append($2);
$$->children.append(e_one);
$$->children.append($4);
$$->children.push_back($2);
$$->children.push_back(e_one);
$$->children.push_back($4);
} |
'[' expr ':' expr ':' expr ']' {
$$ = new Expression();
$$->type = "R";
$$->children.append($2);
$$->children.append($4);
$$->children.append($6);
$$->children.push_back($2);
$$->children.push_back($4);
$$->children.push_back($6);
} |
'[' optional_commas ']' {
$$ = new Expression();
@ -371,80 +373,80 @@ expr:
expr '*' expr {
$$ = new Expression();
$$->type = "*";
$$->children.append($1);
$$->children.append($3);
$$->children.push_back($1);
$$->children.push_back($3);
} |
expr '/' expr {
$$ = new Expression();
$$->type = "/";
$$->children.append($1);
$$->children.append($3);
$$->children.push_back($1);
$$->children.push_back($3);
} |
expr '%' expr {
$$ = new Expression();
$$->type = "%";
$$->children.append($1);
$$->children.append($3);
$$->children.push_back($1);
$$->children.push_back($3);
} |
expr '+' expr {
$$ = new Expression();
$$->type = "+";
$$->children.append($1);
$$->children.append($3);
$$->children.push_back($1);
$$->children.push_back($3);
} |
expr '-' expr {
$$ = new Expression();
$$->type = "-";
$$->children.append($1);
$$->children.append($3);
$$->children.push_back($1);
$$->children.push_back($3);
} |
expr '<' expr {
$$ = new Expression();
$$->type = "<";
$$->children.append($1);
$$->children.append($3);
$$->children.push_back($1);
$$->children.push_back($3);
} |
expr LE expr {
$$ = new Expression();
$$->type = "<=";
$$->children.append($1);
$$->children.append($3);
$$->children.push_back($1);
$$->children.push_back($3);
} |
expr EQ expr {
$$ = new Expression();
$$->type = "==";
$$->children.append($1);
$$->children.append($3);
$$->children.push_back($1);
$$->children.push_back($3);
} |
expr NE expr {
$$ = new Expression();
$$->type = "!=";
$$->children.append($1);
$$->children.append($3);
$$->children.push_back($1);
$$->children.push_back($3);
} |
expr GE expr {
$$ = new Expression();
$$->type = ">=";
$$->children.append($1);
$$->children.append($3);
$$->children.push_back($1);
$$->children.push_back($3);
} |
expr '>' expr {
$$ = new Expression();
$$->type = ">";
$$->children.append($1);
$$->children.append($3);
$$->children.push_back($1);
$$->children.push_back($3);
} |
expr AND expr {
$$ = new Expression();
$$->type = "&&";
$$->children.append($1);
$$->children.append($3);
$$->children.push_back($1);
$$->children.push_back($3);
} |
expr OR expr {
$$ = new Expression();
$$->type = "||";
$$->children.append($1);
$$->children.append($3);
$$->children.push_back($1);
$$->children.push_back($3);
} |
'+' expr {
$$ = $2;
@ -452,12 +454,12 @@ expr:
'-' expr {
$$ = new Expression();
$$->type = "I";
$$->children.append($2);
$$->children.push_back($2);
} |
'!' expr {
$$ = new Expression();
$$->type = "!";
$$->children.append($2);
$$->children.push_back($2);
} |
'(' expr ')' {
$$ = $2;
@ -465,20 +467,20 @@ expr:
expr '?' expr ':' expr {
$$ = new Expression();
$$->type = "?:";
$$->children.append($1);
$$->children.append($3);
$$->children.append($5);
$$->children.push_back($1);
$$->children.push_back($3);
$$->children.push_back($5);
} |
expr '[' expr ']' {
$$ = new Expression();
$$->type = "[]";
$$->children.append($1);
$$->children.append($3);
$$->children.push_back($1);
$$->children.push_back($3);
} |
TOK_ID '(' arguments_call ')' {
$$ = new Expression();
$$->type = "F";
$$->call_funcname = QString($1);
$$->call_funcname = $1;
$$->call_argnames = $3->argnames;
$$->children = $3->argexpr;
free($1);
@ -492,11 +494,11 @@ vector_expr:
expr {
$$ = new Expression();
$$->type = 'V';
$$->children.append($1);
$$->children.push_back($1);
} |
vector_expr ',' optional_commas expr {
$$ = $1;
$$->children.append($4);
$$->children.push_back($4);
} ;
arguments_decl:
@ -505,27 +507,27 @@ arguments_decl:
} |
argument_decl {
$$ = new ArgsContainer();
$$->argnames.append($1->argname);
$$->argexpr.append($1->argexpr);
$$->argnames.push_back($1->argname);
$$->argexpr.push_back($1->argexpr);
delete $1;
} |
arguments_decl ',' optional_commas argument_decl {
$$ = $1;
$$->argnames.append($4->argname);
$$->argexpr.append($4->argexpr);
$$->argnames.push_back($4->argname);
$$->argexpr.push_back($4->argexpr);
delete $4;
} ;
argument_decl:
TOK_ID {
$$ = new ArgContainer();
$$->argname = QString($1);
$$->argname = $1;
$$->argexpr = NULL;
free($1);
} |
TOK_ID '=' expr {
$$ = new ArgContainer();
$$->argname = QString($1);
$$->argname = $1;
$$->argexpr = $3;
free($1);
} ;
@ -536,14 +538,14 @@ arguments_call:
} |
argument_call {
$$ = new ArgsContainer();
$$->argnames.append($1->argname);
$$->argexpr.append($1->argexpr);
$$->argnames.push_back($1->argname);
$$->argexpr.push_back($1->argexpr);
delete $1;
} |
arguments_call ',' optional_commas argument_call {
$$ = $1;
$$->argnames.append($4->argname);
$$->argexpr.append($4->argexpr);
$$->argnames.push_back($4->argname);
$$->argexpr.push_back($4->argexpr);
delete $4;
} ;
@ -554,7 +556,7 @@ argument_call:
} |
TOK_ID '=' expr {
$$ = new ArgContainer();
$$->argname = QString($1);
$$->argname = $1;
$$->argexpr = $3;
free($1);
} ;
@ -573,6 +575,7 @@ void yyerror (char const *s)
module = NULL;
}
extern void lexerdestroy();
extern FILE *lexerin;
extern const char *parser_input_buffer;
const char *parser_input_buffer;
@ -590,19 +593,17 @@ AbstractModule *parse(const char *text, const char *path, int debug)
parserdebug = debug;
parserparse();
lexerdestroy();
lexerlex_destroy();
if (!module)
return NULL;
QHashIterator<QString, Module*> i(module->usedlibs);
while (i.hasNext()) {
i.next();
module->usedlibs[i.key()] = Module::compile_library(i.key());
if (!module->usedlibs[i.key()]) {
PRINTF("WARNING: Failed to compile library `%s'.", i.key().toUtf8().data());
module->usedlibs.remove(i.key());
BOOST_FOREACH(Module::ModuleContainer::value_type &m, module->usedlibs) {
module->usedlibs[m.first] = Module::compile_library(m.first);
if (!module->usedlibs[m.first]) {
PRINTF("WARNING: Failed to compile library `%s'.", m.first.c_str());
module->usedlibs.erase(m.first);
}
}
@ -610,46 +611,47 @@ AbstractModule *parse(const char *text, const char *path, int debug)
return module;
}
QHash<QString, Module::libs_cache_ent> Module::libs_cache;
boost::unordered_map<std::string, Module::libs_cache_ent> Module::libs_cache;
Module *Module::compile_library(QString filename)
Module *Module::compile_library(std::string filename)
{
struct stat st;
memset(&st, 0, sizeof(struct stat));
stat(filename.toAscii().data(), &st);
stat(filename.c_str(), &st);
QString cache_id;
cache_id.sprintf("%x.%x", (int)st.st_mtime, (int)st.st_size);
std::stringstream idstream;
idstream << std::hex << st.st_mtime << "." << st.st_size;
std::string cache_id = idstream.str();
if (libs_cache.contains(filename) && libs_cache[filename].cache_id == cache_id) {
PRINT(libs_cache[filename].msg);
return &(*libs_cache[filename].mod);
if (libs_cache.find(filename) != libs_cache.end() && libs_cache[filename].cache_id == cache_id) {
PRINTF("%s", libs_cache[filename].msg.c_str());
return &(*libs_cache[filename].mod);
}
QFile f(filename);
QFile f(QString::fromStdString(filename));
if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) {
PRINTF("WARNING: Can't open library file `%s'.", filename.toUtf8().data());
PRINTF("WARNING: Can't open library file `%s'.", filename.c_str());
return NULL;
}
QString text = QTextStream(&f).readAll();
print_messages_push();
PRINTF("Compiling library `%s'.", filename.toUtf8().data());
libs_cache_ent e = { NULL, cache_id, QString("WARNING: Library `%1' tries to recursively use itself!").arg(filename) };
if (libs_cache.contains(filename))
PRINTF("Compiling library `%s'.", filename.c_str());
libs_cache_ent e = { NULL, cache_id, std::string("WARNING: Library `") + filename + "' tries to recursively use itself!" };
if (libs_cache.find(filename) != libs_cache.end())
delete libs_cache[filename].mod;
libs_cache[filename] = e;
Module *backup_mod = module;
Module *lib_mod = dynamic_cast<Module*>(parse(text.toLocal8Bit(), QFileInfo(filename).absoluteDir().absolutePath().toLocal8Bit(), 0));
Module *lib_mod = dynamic_cast<Module*>(parse(text.toLocal8Bit(), QFileInfo(QString::fromStdString(filename)).absoluteDir().absolutePath().toLocal8Bit(), 0));
module = backup_mod;
if (lib_mod) {
libs_cache[filename].mod = lib_mod;
libs_cache[filename].msg = print_messages_stack.last();
libs_cache[filename].msg = print_messages_stack.last().toStdString();
} else {
libs_cache.remove(filename);
libs_cache.erase(filename);
}
print_messages_pop();

View File

@ -36,28 +36,12 @@
#include <Eigen/LU>
#include <QColor>
PolySet::PolySet() : grid(GRID_FINE)
PolySet::PolySet() : grid(GRID_FINE), is2d(false), convexity(1)
{
is2d = false;
convexity = 1;
refcount = 1;
}
PolySet::~PolySet()
{
assert(refcount == 0);
}
PolySet* PolySet::link()
{
refcount++;
return this;
}
void PolySet::unlink()
{
if (--refcount == 0)
delete this;
}
void PolySet::append_poly()
@ -190,7 +174,7 @@ void PolySet::render_surface(colormode_e colormode, csgmode_e csgmode, double *m
glBegin(GL_TRIANGLES);
for (double z = -zbase/2; z < zbase; z += zbase)
{
for (int i = 0; i < polygons.size(); i++) {
for (size_t i = 0; i < polygons.size(); i++) {
const Polygon *poly = &polygons[i];
if (poly->size() == 3) {
if (z < 0) {
@ -209,14 +193,14 @@ void PolySet::render_surface(colormode_e colormode, csgmode_e csgmode, double *m
}
}
else {
Vector3d center;
for (int j = 0; j < poly->size(); j++) {
Vector3d center = Vector3d::Zero();
for (size_t j = 0; j < poly->size(); j++) {
center[0] += poly->at(j)[0];
center[1] += poly->at(j)[1];
}
center[0] /= poly->size();
center[1] /= poly->size();
for (int j = 1; j <= poly->size(); j++) {
for (size_t j = 1; j <= poly->size(); j++) {
if (z < 0) {
gl_draw_triangle(shaderinfo, center, poly->at(j % poly->size()), poly->at(j - 1),
false, true, false, z, mirrored);
@ -231,9 +215,9 @@ void PolySet::render_surface(colormode_e colormode, csgmode_e csgmode, double *m
const std::vector<Polygon> *borders_p = &borders;
if (borders_p->size() == 0)
borders_p = &polygons;
for (int i = 0; i < borders_p->size(); i++) {
for (size_t i = 0; i < borders_p->size(); i++) {
const Polygon *poly = &borders_p->at(i);
for (int j = 1; j <= poly->size(); j++) {
for (size_t j = 1; j <= poly->size(); j++) {
Vector3d p1 = poly->at(j - 1), p2 = poly->at(j - 1);
Vector3d p3 = poly->at(j % poly->size()), p4 = poly->at(j % poly->size());
p1[2] -= zbase/2, p2[2] += zbase/2;
@ -244,7 +228,7 @@ void PolySet::render_surface(colormode_e colormode, csgmode_e csgmode, double *m
}
glEnd();
} else {
for (int i = 0; i < polygons.size(); i++) {
for (size_t i = 0; i < polygons.size(); i++) {
const Polygon *poly = &polygons[i];
glBegin(GL_TRIANGLES);
if (poly->size() == 3) {
@ -255,8 +239,8 @@ void PolySet::render_surface(colormode_e colormode, csgmode_e csgmode, double *m
gl_draw_triangle(shaderinfo, poly->at(2), poly->at(3), poly->at(1), true, false, true, 0, mirrored);
}
else {
Vector3d center;
for (int j = 0; j < poly->size(); j++) {
Vector3d center = Vector3d::Zero();
for (size_t j = 0; j < poly->size(); j++) {
center[0] += poly->at(j)[0];
center[1] += poly->at(j)[1];
center[2] += poly->at(j)[2];
@ -264,7 +248,7 @@ void PolySet::render_surface(colormode_e colormode, csgmode_e csgmode, double *m
center[0] /= poly->size();
center[1] /= poly->size();
center[2] /= poly->size();
for (int j = 1; j <= poly->size(); j++) {
for (size_t j = 1; j <= poly->size(); j++) {
gl_draw_triangle(shaderinfo, center, poly->at(j - 1), poly->at(j % poly->size()), false, true, false, 0, mirrored);
}
}
@ -287,20 +271,20 @@ void PolySet::render_edges(colormode_e colormode, csgmode_e csgmode) const
double zbase = csgmode;
for (double z = -zbase/2; z < zbase; z += zbase)
{
for (int i = 0; i < borders.size(); i++) {
for (size_t i = 0; i < borders.size(); i++) {
const Polygon *poly = &borders[i];
glBegin(GL_LINE_LOOP);
for (int j = 0; j < poly->size(); j++) {
for (size_t j = 0; j < poly->size(); j++) {
const Vector3d &p = poly->at(j);
glVertex3d(p[0], p[1], z);
}
glEnd();
}
}
for (int i = 0; i < borders.size(); i++) {
for (size_t i = 0; i < borders.size(); i++) {
const Polygon *poly = &borders[i];
glBegin(GL_LINES);
for (int j = 0; j < poly->size(); j++) {
for (size_t j = 0; j < poly->size(); j++) {
const Vector3d &p = poly->at(j);
glVertex3d(p[0], p[1], -zbase/2);
glVertex3d(p[0], p[1], +zbase/2);
@ -308,10 +292,10 @@ void PolySet::render_edges(colormode_e colormode, csgmode_e csgmode) const
glEnd();
}
} else {
for (int i = 0; i < polygons.size(); i++) {
for (size_t i = 0; i < polygons.size(); i++) {
const Polygon *poly = &polygons[i];
glBegin(GL_LINE_LOOP);
for (int j = 0; j < poly->size(); j++) {
for (size_t j = 0; j < poly->size(); j++) {
const Vector3d &p = poly->at(j);
glVertex3d(p[0], p[1], p[2]);
}
@ -323,13 +307,14 @@ void PolySet::render_edges(colormode_e colormode, csgmode_e csgmode) const
BoundingBox PolySet::getBoundingBox() const
{
BoundingBox bbox;
for (int i = 0; i < polygons.size(); i++) {
for (size_t i = 0; i < polygons.size(); i++) {
const Polygon &poly = polygons[i];
for (int j = 0; j < poly.size(); j++) {
for (size_t j = 0; j < poly.size(); j++) {
const Vector3d &p = poly[j];
bbox.extend(p);
}
}
<<<<<<< HEAD
};
CGAL_Nef_polyhedron PolySet::render_cgal_nef_polyhedron() const
@ -607,4 +592,7 @@ CGAL_Nef_polyhedron PolySet::render_cgal_nef_polyhedron() const
CGAL::set_error_behaviour(old_behaviour);
}
return CGAL_Nef_polyhedron();
=======
return bbox;
>>>>>>> upstream/visitor
}

View File

@ -24,6 +24,7 @@ public:
PolySet();
~PolySet();
bool empty() const { return polygons.size() == 0; }
void append_poly();
void append_vertex(double x, double y, double z = 0.0);
void insert_vertex(double x, double y, double z = 0.0);
@ -50,10 +51,6 @@ public:
void render_surface(colormode_e colormode, csgmode_e csgmode, double *m, GLint *shaderinfo = NULL) const;
void render_edges(colormode_e colormode, csgmode_e csgmode) const;
int refcount;
PolySet *link();
void unlink();
};
#endif

View File

@ -36,6 +36,8 @@
#include "visitor.h"
#include <sstream>
#include <assert.h>
#include <boost/assign/std/vector.hpp>
using namespace boost::assign; // bring 'operator+=()' into scope
#define F_MINIMUM 0.01
@ -100,7 +102,7 @@ public:
primitive_type_e type;
int convexity;
Value points, paths, triangles;
virtual PolySet *evaluate_polyset(render_mode_e mode, class PolySetEvaluator *) const;
virtual PolySet *evaluate_polyset(class PolySetEvaluator *) const;
};
AbstractNode *PrimitiveModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
@ -110,30 +112,30 @@ AbstractNode *PrimitiveModule::evaluate(const Context *ctx, const ModuleInstanti
node->center = false;
node->x = node->y = node->z = node->h = node->r1 = node->r2 = 1;
QVector<QString> argnames;
QVector<Expression*> argexpr;
std::vector<std::string> argnames;
std::vector<Expression*> argexpr;
switch (this->type) {
case CUBE:
argnames = QVector<QString>() << "size" << "center";
argnames += "size", "center";
break;
case SPHERE:
argnames = QVector<QString>() << "r";
argnames += "r";
break;
case CYLINDER:
argnames = QVector<QString>() << "h" << "r1" << "r2" << "center";
argnames += "h", "r1", "r2", "center";
break;
case POLYHEDRON:
argnames = QVector<QString>() << "points" << "triangles" << "convexity";
argnames += "points", "triangles", "convexity";
break;
case SQUARE:
argnames = QVector<QString>() << "size" << "center";
argnames += "size", "center";
break;
case CIRCLE:
argnames = QVector<QString>() << "r";
argnames += "r";
break;
case POLYGON:
argnames = QVector<QString>() << "points" << "paths" << "convexity";
argnames += "points", "paths", "convexity";
break;
default:
assert(false && "PrimitiveModule::evaluate(): Unknown node type");
@ -180,8 +182,7 @@ AbstractNode *PrimitiveModule::evaluate(const Context *ctx, const ModuleInstanti
Value r, r1, r2;
r1 = c.lookup_variable("r1");
r2 = c.lookup_variable("r2");
if (r1.type != Value::NUMBER && r2.type != Value::NUMBER)
r = c.lookup_variable("r", true); // silence warning since r has no default value
r = c.lookup_variable("r", true); // silence warning since r has no default value
Value center = c.lookup_variable("center");
if (h.type == Value::NUMBER) {
node->h = h.num;
@ -272,7 +273,7 @@ static void generate_circle(point2d *circle, double r, int fragments)
}
}
PolySet *PrimitiveNode::evaluate_polyset(render_mode_e, class PolySetEvaluator *) const
PolySet *PrimitiveNode::evaluate_polyset(class PolySetEvaluator *) const
{
PolySet *p = new PolySet();
@ -464,7 +465,7 @@ sphere_next_r2:
{
p->append_poly();
for (size_t j=0; j<this->triangles.vec[i]->vec.size(); j++) {
int pt = this->triangles.vec[i]->vec[j]->num;
size_t pt = this->triangles.vec[i]->vec[j]->num;
if (pt < this->points.vec.size()) {
double px, py, pz;
if (this->points.vec[pt]->getv3(px, py, pz))
@ -517,50 +518,48 @@ sphere_next_r2:
double x,y;
if (!this->points.vec[i]->getv2(x, y)) {
PRINTF("ERROR: Unable to convert point at index %d to a vec2 of numbers", i);
p->unlink();
delete p;
return NULL;
}
dd.points.append(Vector2d(x, y));
dd.points.push_back(Vector2d(x, y));
}
if (this->paths.vec.size() == 0)
{
dd.paths.append(DxfData::Path());
dd.paths.push_back(DxfData::Path());
for (size_t i=0; i<this->points.vec.size(); i++) {
assert(i < dd.points.size()); // FIXME: Not needed, but this used to be an 'if'
Vector2d *p = &dd.points[i];
dd.paths.last().points.append(p);
dd.paths.back().indices.push_back(i);
}
if (dd.paths.last().points.size() > 0) {
dd.paths.last().points.append(dd.paths.last().points.first());
dd.paths.last().is_closed = true;
if (dd.paths.back().indices.size() > 0) {
dd.paths.back().indices.push_back(dd.paths.back().indices.front());
dd.paths.back().is_closed = true;
}
}
else
{
for (size_t i=0; i<this->paths.vec.size(); i++)
{
dd.paths.append(DxfData::Path());
dd.paths.push_back(DxfData::Path());
for (size_t j=0; j<this->paths.vec[i]->vec.size(); j++) {
int idx = this->paths.vec[i]->vec[j]->num;
if (idx < dd.points.size()) {
Vector2d *p = &dd.points[idx];
dd.paths.last().points.append(p);
dd.paths.back().indices.push_back(idx);
}
}
if (dd.paths.last().points.isEmpty()) {
dd.paths.removeLast();
if (dd.paths.back().indices.empty()) {
dd.paths.pop_back();
} else {
dd.paths.last().points.append(dd.paths.last().points.first());
dd.paths.last().is_closed = true;
dd.paths.back().indices.push_back(dd.paths.back().indices.front());
dd.paths.back().is_closed = true;
}
}
}
p->is2d = true;
p->convexity = convexity;
dxf_tesselate(p, &dd, 0, true, false, 0);
dxf_border_to_ps(p, &dd);
dxf_tesselate(p, dd, 0, true, false, 0);
dxf_border_to_ps(p, dd);
}
return p;

Some files were not shown because too many files have changed in this diff Show More