mirror of https://github.com/vitalif/openscad
merge
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.ccstl_dim
commit
f5f06c8e97
|
@ -0,0 +1,3 @@
|
|||
[submodule "libraries/MCAD"]
|
||||
path = libraries/MCAD
|
||||
url = git@github.com:openscad/MCAD.git
|
|
@ -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
|
||||
================
|
||||
|
|
36
boost.pri
36
boost.pri
|
@ -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.
Binary file not shown.
Binary file not shown.
31
doc/TODO.txt
31
doc/TODO.txt
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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])
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 60490ebd2c722d70e06a5c12fb55d85b6f1aa1cc
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
45
openscad.pro
45
openscad.pro
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.."
|
||||
|
||||
|
|
|
@ -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"`
|
||||
|
|
|
@ -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
|
|
@ -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/..
|
||||
|
|
|
@ -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());
|
||||
}
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -92,6 +92,7 @@ private slots:
|
|||
void actionOpen();
|
||||
void actionOpenRecent();
|
||||
void actionOpenExample();
|
||||
void updateRecentFiles();
|
||||
void clearRecentFiles();
|
||||
void updateRecentFileActions();
|
||||
void actionSave();
|
||||
|
|
|
@ -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>());
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
29
src/Tree.cc
29
src/Tree.cc
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
46
src/cgal.cc
46
src/cgal.cc
|
@ -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;
|
||||
}
|
83
src/cgal.h
83
src/cgal.h
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
@ -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
|
|
@ -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();
|
||||
}
|
|
@ -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
|
188
src/context.cc
188
src/context.cc
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
226
src/dxfdata.cc
226
src/dxfdata.cc
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 << ")";
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
12
src/export.h
12
src/export.h
|
@ -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
|
||||
|
|
162
src/expr.cc
162
src/expr.cc
|
@ -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 << ")";
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
105
src/func.cc
105
src/func.cc
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
142
src/import.cc
142
src/import.cc
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
33
src/lexer.l
33
src/lexer.l
|
@ -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();
|
||||
}
|
||||
|
|
161
src/mainwin.cc
161
src/mainwin.cc
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef MEMORY_H_
|
||||
#define MEMORY_H_
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
using boost::shared_ptr;
|
||||
|
||||
#endif
|
164
src/module.cc
164
src/module.cc
|
@ -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();
|
||||
}
|
||||
|
|
53
src/module.h
53
src/module.h
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
107
src/openscad.cc
107
src/openscad.cc
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
204
src/parser.y
204
src/parser.y
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue