mirror of https://github.com/vitalif/openscad
Merge remote-tracking branch 'origin/master' into c++11
Conflicts: openscad.promaster
commit
a41c8716ec
|
@ -13,10 +13,11 @@ parser_yacc.h
|
||||||
/tmp
|
/tmp
|
||||||
/OpenSCAD.app
|
/OpenSCAD.app
|
||||||
*/#*#
|
*/#*#
|
||||||
|
/locale/*/*/*.mo
|
||||||
|
/locale/POTFILES
|
||||||
/nbproject
|
/nbproject
|
||||||
|
/openscad.pro.user
|
||||||
/openscad
|
/openscad
|
||||||
/mingw32
|
|
||||||
/mingw64
|
|
||||||
/tests/openscad_nogui
|
/tests/openscad_nogui
|
||||||
testdata/scad/features/import_dxf-tests.scad
|
testdata/scad/features/import_dxf-tests.scad
|
||||||
testdata/scad/features/import_stl-tests.scad
|
testdata/scad/features/import_stl-tests.scad
|
||||||
|
@ -25,4 +26,4 @@ testdata/scad/misc/use-tests.scad
|
||||||
/mingw32
|
/mingw32
|
||||||
/mingw64
|
/mingw64
|
||||||
**/project.xcworkspace
|
**/project.xcworkspace
|
||||||
**/xcuserdata
|
**/xcuserdata
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
[![Travis CI](https://api.travis-ci.org/openscad/openscad.png)](https://travis-ci.org/openscad/openscad)
|
[![Travis CI](https://api.travis-ci.org/openscad/openscad.png)](https://travis-ci.org/openscad/openscad)
|
||||||
[![Coverity Status](https://scan.coverity.com/projects/2510/badge.svg)](https://scan.coverity.com/projects/2510)
|
[![Coverity Status](https://scan.coverity.com/projects/2510/badge.svg)](https://scan.coverity.com/projects/2510)
|
||||||
|
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/openscad/openscad/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
|
||||||
|
|
||||||
# What is OpenSCAD?
|
# What is OpenSCAD?
|
||||||
[![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=openscad&url=http://openscad.org&title=OpenSCAD&language=&tags=github&category=software)
|
[![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=openscad&url=http://openscad.org&title=OpenSCAD&language=&tags=github&category=software)
|
||||||
|
@ -212,15 +213,16 @@ complete, build OpenSCAD and package it to an installer:
|
||||||
If you wish you can only build the openscad.exe binary:
|
If you wish you can only build the openscad.exe binary:
|
||||||
|
|
||||||
cd mingw32
|
cd mingw32
|
||||||
qmake .. CONFIG+=mingw-cross-env
|
qmake ../openscad.pro CONFIG+=mingw-cross-env
|
||||||
make
|
make
|
||||||
|
|
||||||
For a 64-bit Windows cross-build, replace 32 with 64 in the above instructions.
|
For a 64-bit Windows cross-build, replace 32 with 64 in the above instructions.
|
||||||
|
|
||||||
### Compilation
|
### Compilation
|
||||||
|
|
||||||
First, run 'qmake' from Qt4 to generate a Makefile. On some systems you need to
|
First, run 'qmake openscad.pro' from Qt4 to generate a Makefile. On some systems
|
||||||
run 'qmake4', 'qmake-qt4' or something alike to run the qt4 version of the tool.
|
you need to run 'qmake4', 'qmake-qt4' or something alike to run the qt4 version
|
||||||
|
of the tool.
|
||||||
|
|
||||||
Then run make. Finally you might run 'make install' as root or simply copy the
|
Then run make. Finally you might run 'make install' as root or simply copy the
|
||||||
'openscad' binary (OpenSCAD.app on Mac OS X) to the bin directory of your choice.
|
'openscad' binary (OpenSCAD.app on Mac OS X) to the bin directory of your choice.
|
||||||
|
|
12
boost.pri
12
boost.pri
|
@ -11,15 +11,21 @@ boost {
|
||||||
|
|
||||||
# See https://svn.boost.org/trac/boost/ticket/6219
|
# See https://svn.boost.org/trac/boost/ticket/6219
|
||||||
macx: DEFINES += __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES=0
|
macx: DEFINES += __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES=0
|
||||||
|
|
||||||
|
# MXE cross build
|
||||||
CONFIG(mingw-cross-env) {
|
CONFIG(mingw-cross-env) {
|
||||||
DEFINES += BOOST_STATIC
|
DEFINES += BOOST_STATIC
|
||||||
DEFINES += BOOST_THREAD_USE_LIB
|
DEFINES += BOOST_THREAD_USE_LIB
|
||||||
DEFINES += Boost_USE_STATIC_LIBS
|
DEFINES += Boost_USE_STATIC_LIBS
|
||||||
BOOST_LINK_FLAGS = -lboost_thread_win32-mt -lboost_program_options-mt -lboost_filesystem-mt -lboost_system-mt -lboost_regex-mt -lboost_chrono-mt
|
BOOST_LINK_FLAGS = -lboost_thread_win32-mt -lboost_program_options-mt -lboost_filesystem-mt -lboost_system-mt -lboost_regex-mt -lboost_chrono-mt
|
||||||
}
|
}
|
||||||
|
|
||||||
isEmpty(BOOST_LINK_FLAGS):win* {
|
# MSYS2
|
||||||
BOOST_LINK_FLAGS = -llibboost_thread-vc90-mt-s-1_46_1 -llibboost_program_options-vc90-mt-s-1_46_1 -llibboost_filesystem-vc90-mt-s-1_46_1 -llibboost_system-vc90-mt-s-1_46_1 -llibboost_regex-vc90-mt-s-1_46_1
|
isEmpty(BOOST_LINK_FLAGS):win32-g++ {
|
||||||
|
DEFINES += BOOST_STATIC
|
||||||
|
DEFINES += BOOST_THREAD_USE_LIB
|
||||||
|
DEFINES += Boost_USE_STATIC_LIBS
|
||||||
|
BOOST_LINK_FLAGS = -lboost_thread-mt -lboost_program_options-mt -lboost_filesystem-mt -lboost_system-mt -lboost_regex-mt
|
||||||
}
|
}
|
||||||
|
|
||||||
# check for OPENSCAD_LIBDIR + multithread
|
# check for OPENSCAD_LIBDIR + multithread
|
||||||
|
|
10
cgal.pri
10
cgal.pri
|
@ -6,7 +6,6 @@ cgal {
|
||||||
CGAL_DIR = $$(CGALDIR)
|
CGAL_DIR = $$(CGALDIR)
|
||||||
!isEmpty(CGAL_DIR) {
|
!isEmpty(CGAL_DIR) {
|
||||||
QMAKE_INCDIR += $$CGAL_DIR/include
|
QMAKE_INCDIR += $$CGAL_DIR/include
|
||||||
win*: QMAKE_INCDIR += $$CGAL_DIR/auxiliary/gmp/include
|
|
||||||
QMAKE_LIBDIR += $$CGAL_DIR/lib
|
QMAKE_LIBDIR += $$CGAL_DIR/lib
|
||||||
message("CGAL location: $$CGAL_DIR")
|
message("CGAL location: $$CGAL_DIR")
|
||||||
}
|
}
|
||||||
|
@ -19,14 +18,13 @@ cgal {
|
||||||
*-g++* {
|
*-g++* {
|
||||||
QMAKE_CXXFLAGS += -frounding-math
|
QMAKE_CXXFLAGS += -frounding-math
|
||||||
}
|
}
|
||||||
LIBS += $$CGAL_DIR/auxiliary/gmp/lib/libmpfr-4.lib -lCGAL-vc110-mt-gd
|
|
||||||
} else {
|
} else {
|
||||||
LIBS += -lgmp -lmpfr -lCGAL
|
|
||||||
QMAKE_CXXFLAGS += -frounding-math
|
QMAKE_CXXFLAGS += -frounding-math
|
||||||
}
|
}
|
||||||
|
LIBS += -lCGAL -lmpfr -lgmp
|
||||||
}
|
}
|
||||||
|
|
||||||
*clang* {
|
*clang* {
|
||||||
QMAKE_CXXFLAGS -= -frounding-math
|
QMAKE_CXXFLAGS -= -frounding-math
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
This folder contains some CGAL test programs to easier develop and debug CGAL-based components.
|
||||||
|
|
||||||
|
## polyhole-tessellator
|
||||||
|
|
||||||
|
Tessellate an almost planar 3D polygon with holes into a vector of double precision 3D triangles.
|
||||||
|
|
|
@ -0,0 +1,198 @@
|
||||||
|
solid OpenSCAD_Model
|
||||||
|
facet normal -1 0 0
|
||||||
|
outer loop
|
||||||
|
vertex 0 10 0
|
||||||
|
vertex 0 0 0
|
||||||
|
vertex 0 0 10
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal -1 -0 -0
|
||||||
|
outer loop
|
||||||
|
vertex 0 10 10
|
||||||
|
vertex 0 10 0
|
||||||
|
vertex 0 0 10
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 -1 0
|
||||||
|
outer loop
|
||||||
|
vertex 0 0 10
|
||||||
|
vertex 0 0 0
|
||||||
|
vertex 10 0 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal -0 -1 -0
|
||||||
|
outer loop
|
||||||
|
vertex 10 0 10
|
||||||
|
vertex 0 0 10
|
||||||
|
vertex 10 0 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal -0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 5 10 0
|
||||||
|
vertex 0 0 0
|
||||||
|
vertex 0 10 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 5 15 0
|
||||||
|
vertex 15 15 0
|
||||||
|
vertex 5 10 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 -0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 5 10 0
|
||||||
|
vertex 10 5 0
|
||||||
|
vertex 0 0 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 -0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 15 15 0
|
||||||
|
vertex 15 5 0
|
||||||
|
vertex 10 5 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 -0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 10 5 0
|
||||||
|
vertex 10 0 0
|
||||||
|
vertex 0 0 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 15 15 0
|
||||||
|
vertex 10 5 0
|
||||||
|
vertex 5 10 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 1 0
|
||||||
|
outer loop
|
||||||
|
vertex 5 10 0
|
||||||
|
vertex 0 10 0
|
||||||
|
vertex 0 10 10
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 1 0
|
||||||
|
outer loop
|
||||||
|
vertex 5 10 10
|
||||||
|
vertex 5 10 0
|
||||||
|
vertex 0 10 10
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 10 5 10
|
||||||
|
vertex 0 0 10
|
||||||
|
vertex 10 0 10
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 -0 1
|
||||||
|
outer loop
|
||||||
|
vertex 15 5 10
|
||||||
|
vertex 15 15 10
|
||||||
|
vertex 10 5 10
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 10 5 10
|
||||||
|
vertex 5 10 10
|
||||||
|
vertex 0 0 10
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 15 15 10
|
||||||
|
vertex 5 15 10
|
||||||
|
vertex 5 10 10
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 5 10 10
|
||||||
|
vertex 0 10 10
|
||||||
|
vertex 0 0 10
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 15 15 10
|
||||||
|
vertex 5 10 10
|
||||||
|
vertex 10 5 10
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 1 0 0
|
||||||
|
outer loop
|
||||||
|
vertex 10 0 10
|
||||||
|
vertex 10 0 0
|
||||||
|
vertex 10 5 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 1 0 0
|
||||||
|
outer loop
|
||||||
|
vertex 10 5 10
|
||||||
|
vertex 10 0 10
|
||||||
|
vertex 10 5 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal -1 0 0
|
||||||
|
outer loop
|
||||||
|
vertex 5 15 0
|
||||||
|
vertex 5 10 0
|
||||||
|
vertex 5 10 10
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal -1 -0 -0
|
||||||
|
outer loop
|
||||||
|
vertex 5 15 10
|
||||||
|
vertex 5 15 0
|
||||||
|
vertex 5 10 10
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 -1 0
|
||||||
|
outer loop
|
||||||
|
vertex 10 5 10
|
||||||
|
vertex 10 5 0
|
||||||
|
vertex 15 5 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal -0 -1 -0
|
||||||
|
outer loop
|
||||||
|
vertex 15 5 10
|
||||||
|
vertex 10 5 10
|
||||||
|
vertex 15 5 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 1 0
|
||||||
|
outer loop
|
||||||
|
vertex 15 15 0
|
||||||
|
vertex 5 15 0
|
||||||
|
vertex 5 15 10
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 1 0
|
||||||
|
outer loop
|
||||||
|
vertex 15 15 10
|
||||||
|
vertex 15 15 0
|
||||||
|
vertex 5 15 10
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 1 0 0
|
||||||
|
outer loop
|
||||||
|
vertex 15 5 10
|
||||||
|
vertex 15 5 0
|
||||||
|
vertex 15 15 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 1 0 0
|
||||||
|
outer loop
|
||||||
|
vertex 15 15 10
|
||||||
|
vertex 15 5 10
|
||||||
|
vertex 15 15 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
endsolid OpenSCAD_Model
|
|
@ -0,0 +1,4 @@
|
||||||
|
6, -25, 29.285714285714285
|
||||||
|
6, -26.732050855686023, 29.020513307787397
|
||||||
|
6, -26.732050855686026, 29.020513307787397
|
||||||
|
6, -26, 29.132600433972414
|
|
@ -0,0 +1,10 @@
|
||||||
|
0,0,0
|
||||||
|
2,0,0
|
||||||
|
2,2,0
|
||||||
|
0,2,0
|
||||||
|
|
||||||
|
0.5,0.5,0
|
||||||
|
1.5,0.5,0
|
||||||
|
1.5,1.5,0
|
||||||
|
0.5,1.5,0
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
0,0,0
|
||||||
|
2,0,0
|
||||||
|
2,2,0
|
|
@ -0,0 +1,667 @@
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
#include <boost/regex.hpp>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <locale.h>
|
||||||
|
|
||||||
|
#include "cgalutils.h"
|
||||||
|
#include "export.h"
|
||||||
|
#include "polyset.h"
|
||||||
|
#include "CGAL_Nef_polyhedron.h"
|
||||||
|
|
||||||
|
using namespace CGALUtils;
|
||||||
|
|
||||||
|
// Nef polyhedron are using CGAL_Kernel3 (Cartesian<Gmpq>)
|
||||||
|
// Triangulation will use Epick
|
||||||
|
typedef CGAL::Epick K;
|
||||||
|
typedef CGAL::Polyhedron_3<K> PolyhedronK;
|
||||||
|
|
||||||
|
#include <boost/assign/std/vector.hpp>
|
||||||
|
#include <boost/assign/list_of.hpp>
|
||||||
|
using namespace boost::assign; // bring 'operator+=()' into scope
|
||||||
|
std::vector<Color4f> colors = boost::assign::list_of
|
||||||
|
(Color4f(240, 248, 255))
|
||||||
|
(Color4f(250, 235, 215))
|
||||||
|
(Color4f(0, 255, 255))
|
||||||
|
(Color4f(127, 255, 212))
|
||||||
|
(Color4f(240, 255, 255))
|
||||||
|
(Color4f(245, 245, 220))
|
||||||
|
(Color4f(255, 228, 196))
|
||||||
|
(Color4f(0, 0, 0))
|
||||||
|
(Color4f(255, 235, 205))
|
||||||
|
(Color4f(0, 0, 255))
|
||||||
|
(Color4f(138, 43, 226))
|
||||||
|
(Color4f(165, 42, 42))
|
||||||
|
(Color4f(222, 184, 135))
|
||||||
|
(Color4f(95, 158, 160))
|
||||||
|
(Color4f(127, 255, 0))
|
||||||
|
(Color4f(210, 105, 30))
|
||||||
|
(Color4f(255, 127, 80))
|
||||||
|
(Color4f(100, 149, 237))
|
||||||
|
(Color4f(255, 248, 220))
|
||||||
|
(Color4f(220, 20, 60))
|
||||||
|
(Color4f(0, 255, 255))
|
||||||
|
(Color4f(0, 0, 139))
|
||||||
|
(Color4f(0, 139, 139))
|
||||||
|
(Color4f(184, 134, 11))
|
||||||
|
(Color4f(169, 169, 169))
|
||||||
|
(Color4f(0, 100, 0))
|
||||||
|
(Color4f(169, 169, 169))
|
||||||
|
(Color4f(189, 183, 107))
|
||||||
|
(Color4f(139, 0, 139))
|
||||||
|
(Color4f(85, 107, 47))
|
||||||
|
(Color4f(255, 140, 0))
|
||||||
|
(Color4f(153, 50, 204))
|
||||||
|
(Color4f(139, 0, 0))
|
||||||
|
(Color4f(233, 150, 122))
|
||||||
|
(Color4f(143, 188, 143))
|
||||||
|
(Color4f(72, 61, 139))
|
||||||
|
(Color4f(47, 79, 79))
|
||||||
|
(Color4f(47, 79, 79))
|
||||||
|
(Color4f(0, 206, 209))
|
||||||
|
(Color4f(148, 0, 211))
|
||||||
|
(Color4f(255, 20, 147))
|
||||||
|
(Color4f(0, 191, 255))
|
||||||
|
(Color4f(105, 105, 105))
|
||||||
|
(Color4f(105, 105, 105))
|
||||||
|
(Color4f(30, 144, 255))
|
||||||
|
(Color4f(178, 34, 34))
|
||||||
|
(Color4f(255, 250, 240))
|
||||||
|
(Color4f(34, 139, 34))
|
||||||
|
(Color4f(255, 0, 255))
|
||||||
|
(Color4f(220, 220, 220))
|
||||||
|
(Color4f(248, 248, 255))
|
||||||
|
(Color4f(255, 215, 0))
|
||||||
|
(Color4f(218, 165, 32))
|
||||||
|
(Color4f(128, 128, 128))
|
||||||
|
(Color4f(0, 128, 0))
|
||||||
|
(Color4f(173, 255, 47))
|
||||||
|
(Color4f(128, 128, 128))
|
||||||
|
(Color4f(240, 255, 240))
|
||||||
|
(Color4f(255, 105, 180))
|
||||||
|
(Color4f(205, 92, 92))
|
||||||
|
(Color4f(75, 0, 130))
|
||||||
|
(Color4f(255, 255, 240))
|
||||||
|
(Color4f(240, 230, 140))
|
||||||
|
(Color4f(230, 230, 250))
|
||||||
|
(Color4f(255, 240, 245))
|
||||||
|
(Color4f(124, 252, 0))
|
||||||
|
(Color4f(255, 250, 205))
|
||||||
|
(Color4f(173, 216, 230))
|
||||||
|
(Color4f(240, 128, 128))
|
||||||
|
(Color4f(224, 255, 255))
|
||||||
|
(Color4f(250, 250, 210))
|
||||||
|
(Color4f(211, 211, 211))
|
||||||
|
(Color4f(144, 238, 144))
|
||||||
|
(Color4f(211, 211, 211))
|
||||||
|
(Color4f(255, 182, 193))
|
||||||
|
(Color4f(255, 160, 122))
|
||||||
|
(Color4f(32, 178, 170))
|
||||||
|
(Color4f(135, 206, 250))
|
||||||
|
(Color4f(119, 136, 153))
|
||||||
|
(Color4f(119, 136, 153))
|
||||||
|
(Color4f(176, 196, 222))
|
||||||
|
(Color4f(255, 255, 224))
|
||||||
|
(Color4f(0, 255, 0))
|
||||||
|
(Color4f(50, 205, 50))
|
||||||
|
(Color4f(250, 240, 230))
|
||||||
|
(Color4f(255, 0, 255))
|
||||||
|
(Color4f(128, 0, 0))
|
||||||
|
(Color4f(102, 205, 170))
|
||||||
|
(Color4f(0, 0, 205))
|
||||||
|
(Color4f(186, 85, 211))
|
||||||
|
(Color4f(147, 112, 219))
|
||||||
|
(Color4f(60, 179, 113))
|
||||||
|
(Color4f(123, 104, 238))
|
||||||
|
(Color4f(0, 250, 154))
|
||||||
|
(Color4f(72, 209, 204))
|
||||||
|
(Color4f(199, 21, 133))
|
||||||
|
(Color4f(25, 25, 112))
|
||||||
|
(Color4f(245, 255, 250))
|
||||||
|
(Color4f(255, 228, 225))
|
||||||
|
(Color4f(255, 228, 181))
|
||||||
|
(Color4f(255, 222, 173))
|
||||||
|
(Color4f(0, 0, 128))
|
||||||
|
(Color4f(253, 245, 230))
|
||||||
|
(Color4f(128, 128, 0))
|
||||||
|
(Color4f(107, 142, 35))
|
||||||
|
(Color4f(255, 165, 0))
|
||||||
|
(Color4f(255, 69, 0))
|
||||||
|
(Color4f(218, 112, 214))
|
||||||
|
(Color4f(238, 232, 170))
|
||||||
|
(Color4f(152, 251, 152))
|
||||||
|
(Color4f(175, 238, 238))
|
||||||
|
(Color4f(219, 112, 147))
|
||||||
|
(Color4f(255, 239, 213))
|
||||||
|
(Color4f(255, 218, 185))
|
||||||
|
(Color4f(205, 133, 63))
|
||||||
|
(Color4f(255, 192, 203))
|
||||||
|
(Color4f(221, 160, 221))
|
||||||
|
(Color4f(176, 224, 230))
|
||||||
|
(Color4f(128, 0, 128))
|
||||||
|
(Color4f(255, 0, 0))
|
||||||
|
(Color4f(188, 143, 143))
|
||||||
|
(Color4f(65, 105, 225))
|
||||||
|
(Color4f(139, 69, 19))
|
||||||
|
(Color4f(250, 128, 114))
|
||||||
|
(Color4f(244, 164, 96))
|
||||||
|
(Color4f(46, 139, 87))
|
||||||
|
(Color4f(255, 245, 238))
|
||||||
|
(Color4f(160, 82, 45))
|
||||||
|
(Color4f(192, 192, 192))
|
||||||
|
(Color4f(135, 206, 235))
|
||||||
|
(Color4f(106, 90, 205))
|
||||||
|
(Color4f(112, 128, 144))
|
||||||
|
(Color4f(112, 128, 144))
|
||||||
|
(Color4f(255, 250, 250))
|
||||||
|
(Color4f(0, 255, 127))
|
||||||
|
(Color4f(70, 130, 180))
|
||||||
|
(Color4f(210, 180, 140))
|
||||||
|
(Color4f(0, 128, 128))
|
||||||
|
(Color4f(216, 191, 216))
|
||||||
|
(Color4f(255, 99, 71))
|
||||||
|
(Color4f(0, 0, 0, 0))
|
||||||
|
(Color4f(64, 224, 208))
|
||||||
|
(Color4f(238, 130, 238))
|
||||||
|
(Color4f(245, 222, 179))
|
||||||
|
(Color4f(255, 255, 255))
|
||||||
|
(Color4f(245, 245, 245))
|
||||||
|
(Color4f(255, 255, 0))
|
||||||
|
(Color4f(154, 205, 50));
|
||||||
|
|
||||||
|
#include <boost/unordered_set.hpp>
|
||||||
|
#include <CGAL/convex_hull_3.h>
|
||||||
|
template<typename Polyhedron>
|
||||||
|
bool is_weakly_convex(Polyhedron const& p) {
|
||||||
|
for (typename Polyhedron::Edge_const_iterator i = p.edges_begin(); i != p.edges_end(); ++i) {
|
||||||
|
typename Polyhedron::Plane_3 p(i->opposite()->vertex()->point(), i->vertex()->point(), i->next()->vertex()->point());
|
||||||
|
if (p.has_on_positive_side(i->opposite()->next()->vertex()->point()) &&
|
||||||
|
CGAL::squared_distance(p, i->opposite()->next()->vertex()->point()) > 1e-8) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Also make sure that there is only one shell:
|
||||||
|
boost::unordered_set<typename Polyhedron::Facet_const_handle, typename CGAL::Handle_hash_function> visited;
|
||||||
|
// c++11
|
||||||
|
// visited.reserve(p.size_of_facets());
|
||||||
|
|
||||||
|
std::queue<typename Polyhedron::Facet_const_handle> to_explore;
|
||||||
|
to_explore.push(p.facets_begin()); // One arbitrary facet
|
||||||
|
visited.insert(to_explore.front());
|
||||||
|
|
||||||
|
while (!to_explore.empty()) {
|
||||||
|
typename Polyhedron::Facet_const_handle f = to_explore.front();
|
||||||
|
to_explore.pop();
|
||||||
|
typename Polyhedron::Facet::Halfedge_around_facet_const_circulator he, end;
|
||||||
|
end = he = f->facet_begin();
|
||||||
|
CGAL_For_all(he,end) {
|
||||||
|
typename Polyhedron::Facet_const_handle o = he->opposite()->facet();
|
||||||
|
|
||||||
|
if (!visited.count(o)) {
|
||||||
|
visited.insert(o);
|
||||||
|
to_explore.push(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return visited.size() == p.size_of_facets();
|
||||||
|
}
|
||||||
|
|
||||||
|
class Shell_explorer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::vector<K::Point_3> vertices;
|
||||||
|
|
||||||
|
Shell_explorer() {}
|
||||||
|
void visit(CGAL_Nef_polyhedron3::Vertex_const_handle v) {
|
||||||
|
vertices.push_back(K::Point_3(to_double(v->point()[0]),
|
||||||
|
to_double(v->point()[1]),
|
||||||
|
to_double(v->point()[2])));
|
||||||
|
}
|
||||||
|
void visit(CGAL_Nef_polyhedron3::Halfedge_const_handle ) {}
|
||||||
|
void visit(CGAL_Nef_polyhedron3::Halffacet_const_handle ) {}
|
||||||
|
void visit(CGAL_Nef_polyhedron3::SHalfedge_const_handle ) {}
|
||||||
|
void visit(CGAL_Nef_polyhedron3::SHalfloop_const_handle ) {}
|
||||||
|
void visit(CGAL_Nef_polyhedron3::SFace_const_handle ) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Output>
|
||||||
|
void decompose(const CGAL_Nef_polyhedron3 *N, Output out_iter)
|
||||||
|
{
|
||||||
|
int parts = 0;
|
||||||
|
assert(N);
|
||||||
|
CGAL_Polyhedron poly;
|
||||||
|
if (N->is_simple()) {
|
||||||
|
nefworkaround::convert_to_Polyhedron<CGAL_Kernel3>(*N, poly);
|
||||||
|
}
|
||||||
|
if (is_weakly_convex(poly)) {
|
||||||
|
PRINTD("Minkowski: Object is convex and Nef");
|
||||||
|
PolyhedronK poly2;
|
||||||
|
CGALUtils::copyPolyhedron(poly, poly2);
|
||||||
|
*out_iter++ = poly2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PRINTD("Minkowski: Object is nonconvex Nef, decomposing...");
|
||||||
|
CGAL_Nef_polyhedron3 decomposed_nef = *N;
|
||||||
|
CGAL::convex_decomposition_3(decomposed_nef);
|
||||||
|
|
||||||
|
// the first volume is the outer volume, which ignored in the decomposition
|
||||||
|
CGAL_Nef_polyhedron3::Volume_const_iterator ci = ++decomposed_nef.volumes_begin();
|
||||||
|
// Convert each convex volume to a Polyhedron
|
||||||
|
for(; ci != decomposed_nef.volumes_end(); ++ci) {
|
||||||
|
if(ci->mark()) {
|
||||||
|
// CGAL_Polyhedron poly;
|
||||||
|
// decomposed_nef.convert_inner_shell_to_polyhedron(ci->shells_begin(), poly);
|
||||||
|
// P.push_back(poly);
|
||||||
|
|
||||||
|
|
||||||
|
auto s = CGAL_Nef_polyhedron3::SFace_const_handle(ci->shells_begin());
|
||||||
|
|
||||||
|
CGAL_Nef_polyhedron3::SFace_const_iterator sf = ci->shells_begin();
|
||||||
|
Shell_explorer SE;
|
||||||
|
decomposed_nef.visit_shell_objects(CGAL_Nef_polyhedron3::SFace_const_handle(sf),SE);
|
||||||
|
|
||||||
|
PolyhedronK poly;
|
||||||
|
CGAL::convex_hull_3(SE.vertices.begin(), SE.vertices.end(), poly);
|
||||||
|
*out_iter++ = poly;
|
||||||
|
parts++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINTDB("Minkowski: decomposed into %d convex parts", parts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Geometry const * minkowskitest(const Geometry::ChildList &children)
|
||||||
|
{
|
||||||
|
CGAL::Timer t,t_tot;
|
||||||
|
assert(children.size() >= 2);
|
||||||
|
// Iterate over children, perform pairwise minkowski on children:
|
||||||
|
// operands = [ch, ch+1]
|
||||||
|
Geometry::ChildList::const_iterator minkowski_ch_it = children.begin();
|
||||||
|
t_tot.start();
|
||||||
|
Geometry const *operands[2] = {minkowski_ch_it->second.get(), NULL};
|
||||||
|
try {
|
||||||
|
while (++minkowski_ch_it != children.end()) {
|
||||||
|
operands[1] = minkowski_ch_it->second.get();
|
||||||
|
|
||||||
|
std::vector<PolyhedronK> convexP[2]; // Stores decomposed operands
|
||||||
|
std::list<PolyhedronK> result_parts;
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
shared_ptr<const CGAL_Nef_polyhedron> N;
|
||||||
|
if (const PolySet *ps = dynamic_cast<const PolySet *>(operands[i])) {
|
||||||
|
if (ps->is_convex()) {
|
||||||
|
PRINTDB("Minkowski: child %d is convex and PolySet", i);
|
||||||
|
PolyhedronK poly;
|
||||||
|
CGALUtils::createPolyhedronFromPolySet(*ps, poly);
|
||||||
|
convexP[i].push_back(poly);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PRINTDB("Minkowski: child %d is nonconvex PolySet, transforming to Nef", i);
|
||||||
|
N.reset(createNefPolyhedronFromGeometry(*ps));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (const CGAL_Nef_polyhedron *n = dynamic_cast<const CGAL_Nef_polyhedron *>(operands[i])) {
|
||||||
|
CGAL_Polyhedron poly;
|
||||||
|
if (n->p3->is_simple()) {
|
||||||
|
nefworkaround::convert_to_Polyhedron<CGAL_Kernel3>(*n->p3, poly);
|
||||||
|
// FIXME: Can we calculate weakly_convex on a PolyhedronK instead?
|
||||||
|
if (is_weakly_convex(poly)) {
|
||||||
|
PRINTDB("Minkowski: child %d is convex and Nef", i);
|
||||||
|
PolyhedronK poly2;
|
||||||
|
CGALUtils::copyPolyhedron(poly, poly2);
|
||||||
|
convexP[i].push_back(poly2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PRINTDB("Minkowski: child %d is nonconvex Nef",i);
|
||||||
|
N.reset(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else throw 0; // We cannot handle this, fall back to CGAL's minkowski
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not convex...
|
||||||
|
if (N && N->p3) {
|
||||||
|
PRINTD("Decomposing...");
|
||||||
|
decompose(N->p3.get(), std::back_inserter(convexP[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINTD("Hulling convex parts...");
|
||||||
|
std::vector<K::Point_3> points[2];
|
||||||
|
std::vector<K::Point_3> minkowski_points;
|
||||||
|
|
||||||
|
// For each permutation of convex operands..
|
||||||
|
BOOST_FOREACH(const PolyhedronK &p0, convexP[0]) {
|
||||||
|
BOOST_FOREACH(const PolyhedronK &p1, convexP[1]) {
|
||||||
|
t.start();
|
||||||
|
|
||||||
|
// Create minkowski pointcloud
|
||||||
|
minkowski_points.clear();
|
||||||
|
minkowski_points.reserve(p0.size_of_vertices() * p0.size_of_vertices());
|
||||||
|
BOOST_FOREACH(const K::Point_3 &p0p, std::make_pair(p0.points_begin(), p0.points_end())) {
|
||||||
|
BOOST_FOREACH(const K::Point_3 &p1p, std::make_pair(p1.points_begin(), p1.points_end())) {
|
||||||
|
minkowski_points.push_back(p0p+(p1p-CGAL::ORIGIN));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.stop();
|
||||||
|
|
||||||
|
// Ignore empty volumes
|
||||||
|
if (minkowski_points.size() <= 3) continue;
|
||||||
|
|
||||||
|
// Hull point cloud
|
||||||
|
PolyhedronK result;
|
||||||
|
PRINTDB("Minkowski: Point cloud creation (%d ⨉ %d -> %d) took %f ms",
|
||||||
|
points[0].size() % points[1].size() % minkowski_points.size() % (t.time()*1000));
|
||||||
|
t.reset();
|
||||||
|
t.start();
|
||||||
|
CGAL::convex_hull_3(minkowski_points.begin(), minkowski_points.end(), result);
|
||||||
|
|
||||||
|
std::vector<K::Point_3> strict_points;
|
||||||
|
strict_points.reserve(minkowski_points.size());
|
||||||
|
|
||||||
|
for (PolyhedronK::Vertex_iterator i = result.vertices_begin(); i != result.vertices_end(); ++i) {
|
||||||
|
K::Point_3 const &p = i->point();
|
||||||
|
|
||||||
|
PolyhedronK::Vertex::Halfedge_handle h,e;
|
||||||
|
h = i->halfedge();
|
||||||
|
e = h;
|
||||||
|
bool collinear = false;
|
||||||
|
bool coplanar = true;
|
||||||
|
|
||||||
|
do {
|
||||||
|
K::Point_3 const& q = h->opposite()->vertex()->point();
|
||||||
|
if (coplanar && !CGAL::coplanar(p,q,
|
||||||
|
h->next_on_vertex()->opposite()->vertex()->point(),
|
||||||
|
h->next_on_vertex()->next_on_vertex()->opposite()->vertex()->point())) {
|
||||||
|
coplanar = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (PolyhedronK::Vertex::Halfedge_handle j = h->next_on_vertex();
|
||||||
|
j != h && !collinear && ! coplanar;
|
||||||
|
j = j->next_on_vertex()) {
|
||||||
|
|
||||||
|
K::Point_3 const& r = j->opposite()->vertex()->point();
|
||||||
|
if (CGAL::collinear(p,q,r)) {
|
||||||
|
collinear = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h = h->next_on_vertex();
|
||||||
|
} while (h != e && !collinear);
|
||||||
|
|
||||||
|
if (!collinear && !coplanar) strict_points.push_back(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.clear();
|
||||||
|
CGAL::convex_hull_3(strict_points.begin(), strict_points.end(), result);
|
||||||
|
|
||||||
|
t.stop();
|
||||||
|
PRINTDB("Minkowski: Computing convex hull took %f s", t.time());
|
||||||
|
t.reset();
|
||||||
|
|
||||||
|
result_parts.push_back(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minkowski_ch_it != boost::next(children.begin())) delete operands[0];
|
||||||
|
|
||||||
|
if (result_parts.size() == 1) {
|
||||||
|
PolySet *ps = new PolySet(3,true);
|
||||||
|
createPolySetFromPolyhedron(*result_parts.begin(), *ps);
|
||||||
|
operands[0] = ps;
|
||||||
|
} else if (!result_parts.empty()) {
|
||||||
|
t.start();
|
||||||
|
PRINTDB("Minkowski: Computing union of %d parts",result_parts.size());
|
||||||
|
Geometry::ChildList fake_children;
|
||||||
|
for (std::list<PolyhedronK>::iterator i = result_parts.begin(); i != result_parts.end(); ++i) {
|
||||||
|
PolySet ps(3,true);
|
||||||
|
createPolySetFromPolyhedron(*i, ps);
|
||||||
|
fake_children.push_back(std::make_pair((const AbstractNode*)NULL,
|
||||||
|
shared_ptr<const Geometry>(createNefPolyhedronFromGeometry(ps))));
|
||||||
|
}
|
||||||
|
CGAL_Nef_polyhedron *N = CGALUtils::applyOperator(fake_children, OPENSCAD_UNION);
|
||||||
|
t.stop();
|
||||||
|
if (N) PRINTDB("Minkowski: Union done: %f s",t.time());
|
||||||
|
else PRINTDB("Minkowski: Union failed: %f s",t.time());
|
||||||
|
t.reset();
|
||||||
|
operands[0] = N;
|
||||||
|
} else {
|
||||||
|
operands[0] = new CGAL_Nef_polyhedron();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t_tot.stop();
|
||||||
|
PRINTDB("Minkowski: Total execution time %f s", t_tot.time());
|
||||||
|
t_tot.reset();
|
||||||
|
return operands[0];
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
// If anything throws we simply fall back to Nef Minkowski
|
||||||
|
PRINTD("Minkowski: Falling back to Nef Minkowski");
|
||||||
|
|
||||||
|
CGAL_Nef_polyhedron *N = applyOperator(children, OPENSCAD_MINKOWSKI);
|
||||||
|
return N;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define STL_FACET_NUMBYTES 4*3*4+2
|
||||||
|
// as there is no 'float32_t' standard, we assume the systems 'float'
|
||||||
|
// is a 'binary32' aka 'single' standard IEEE 32-bit floating point type
|
||||||
|
union stl_facet {
|
||||||
|
uint8_t data8[ STL_FACET_NUMBYTES ];
|
||||||
|
uint32_t data32[4*3];
|
||||||
|
struct facet_data {
|
||||||
|
float i, j, k;
|
||||||
|
float x1, y1, z1;
|
||||||
|
float x2, y2, z2;
|
||||||
|
float x3, y3, z3;
|
||||||
|
uint16_t attribute_byte_count;
|
||||||
|
} data;
|
||||||
|
};
|
||||||
|
|
||||||
|
void uint32_byte_swap( uint32_t &x )
|
||||||
|
{
|
||||||
|
#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 3
|
||||||
|
x = __builtin_bswap32( x );
|
||||||
|
#elif defined(__clang__)
|
||||||
|
x = __builtin_bswap32( x );
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
x = _byteswap_ulong( x );
|
||||||
|
#else
|
||||||
|
uint32_t b1 = ( 0x000000FF & x ) << 24;
|
||||||
|
uint32_t b2 = ( 0x0000FF00 & x ) << 8;
|
||||||
|
uint32_t b3 = ( 0x00FF0000 & x ) >> 8;
|
||||||
|
uint32_t b4 = ( 0xFF000000 & x ) >> 24;
|
||||||
|
x = b1 | b2 | b3 | b4;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_stl_facet( std::ifstream &f, stl_facet &facet )
|
||||||
|
{
|
||||||
|
f.read( (char*)facet.data8, STL_FACET_NUMBYTES );
|
||||||
|
#ifdef BOOST_BIG_ENDIAN
|
||||||
|
for ( int i = 0; i < 12; i++ ) {
|
||||||
|
uint32_byte_swap( facet.data32[ i ] );
|
||||||
|
}
|
||||||
|
// we ignore attribute byte count
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
PolySet *import_stl(const std::string &filename)
|
||||||
|
{
|
||||||
|
PolySet *p = new PolySet(3);
|
||||||
|
|
||||||
|
// Open file and position at the end
|
||||||
|
std::ifstream f(filename.c_str(), std::ios::in | std::ios::binary | std::ios::ate);
|
||||||
|
if (!f.good()) {
|
||||||
|
PRINTB("WARNING: Can't open import file '%s'.", filename);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::regex ex_sfe("solid|facet|endloop");
|
||||||
|
boost::regex ex_outer("outer loop");
|
||||||
|
boost::regex ex_vertex("vertex");
|
||||||
|
boost::regex ex_vertices("\\s*vertex\\s+([^\\s]+)\\s+([^\\s]+)\\s+([^\\s]+)");
|
||||||
|
|
||||||
|
bool binary = false;
|
||||||
|
std::streampos file_size = f.tellg();
|
||||||
|
f.seekg(80);
|
||||||
|
if (f.good() && !f.eof()) {
|
||||||
|
uint32_t facenum = 0;
|
||||||
|
f.read((char *)&facenum, sizeof(uint32_t));
|
||||||
|
#ifdef BOOST_BIG_ENDIAN
|
||||||
|
uint32_byte_swap( facenum );
|
||||||
|
#endif
|
||||||
|
if (file_size == static_cast<std::streamoff>(80 + 4 + 50*facenum)) {
|
||||||
|
binary = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.seekg(0);
|
||||||
|
|
||||||
|
char data[5];
|
||||||
|
f.read(data, 5);
|
||||||
|
if (!binary && !f.eof() && f.good() && !memcmp(data, "solid", 5)) {
|
||||||
|
int i = 0;
|
||||||
|
double vdata[3][3];
|
||||||
|
std::string line;
|
||||||
|
std::getline(f, line);
|
||||||
|
while (!f.eof()) {
|
||||||
|
std::getline(f, line);
|
||||||
|
boost::trim(line);
|
||||||
|
if (boost::regex_search(line, ex_sfe)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (boost::regex_search(line, ex_outer)) {
|
||||||
|
i = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
boost::smatch results;
|
||||||
|
if (boost::regex_search(line, results, ex_vertices)) {
|
||||||
|
try {
|
||||||
|
for (int v=0;v<3;v++) {
|
||||||
|
vdata[i][v] = boost::lexical_cast<double>(results[v+1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const boost::bad_lexical_cast &blc) {
|
||||||
|
PRINTB("WARNING: Can't parse vertex line '%s'.", line);
|
||||||
|
i = 10;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (++i == 3) {
|
||||||
|
p->append_poly();
|
||||||
|
p->append_vertex(vdata[0][0], vdata[0][1], vdata[0][2]);
|
||||||
|
p->append_vertex(vdata[1][0], vdata[1][1], vdata[1][2]);
|
||||||
|
p->append_vertex(vdata[2][0], vdata[2][1], vdata[2][2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (binary && !f.eof() && f.good())
|
||||||
|
{
|
||||||
|
f.ignore(80-5+4);
|
||||||
|
while (1) {
|
||||||
|
stl_facet facet;
|
||||||
|
read_stl_facet( f, facet );
|
||||||
|
if (f.eof()) break;
|
||||||
|
p->append_poly();
|
||||||
|
p->append_vertex(facet.data.x1, facet.data.y1, facet.data.z1);
|
||||||
|
p->append_vertex(facet.data.x2, facet.data.y2, facet.data.z2);
|
||||||
|
p->append_vertex(facet.data.x3, facet.data.y3, facet.data.z3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
file format:
|
||||||
|
1. polygon coordinates (x,y,z) are comma separated (+/- spaces) and
|
||||||
|
each coordinate is on a separate line
|
||||||
|
2. each polygon is separated by one or more blank lines
|
||||||
|
*/
|
||||||
|
bool import_polygon(PolyholeK &polyhole, const std::string &filename)
|
||||||
|
{
|
||||||
|
std::ifstream ifs(filename.c_str());
|
||||||
|
if (!ifs) return false;
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
PolygonK polygon;
|
||||||
|
while (std::getline(ifs, line)) {
|
||||||
|
std::stringstream ss(line);
|
||||||
|
double X = 0.0, Y = 0.0, Z = 0.0;
|
||||||
|
if (!(ss >> X)) {
|
||||||
|
//ie blank lines => flag start of next polygon
|
||||||
|
if (polygon.size() > 0) polyhole.push_back(polygon);
|
||||||
|
polygon.clear();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
char c = ss.peek();
|
||||||
|
while (c == ' ') {ss.read(&c, 1); c = ss.peek();} //gobble spaces before comma
|
||||||
|
if (c == ',') {ss.read(&c, 1); c = ss.peek();} //gobble comma
|
||||||
|
while (c == ' ') {ss.read(&c, 1); c = ss.peek();} //gobble spaces after comma
|
||||||
|
if (!(ss >> Y)) {
|
||||||
|
std::cerr << "Y error\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
c = ss.peek();
|
||||||
|
while (c == ' ') {ss.read(&c, 1); c = ss.peek();} //gobble spaces before comma
|
||||||
|
if (c == ',') {ss.read(&c, 1); c = ss.peek();} //gobble comma
|
||||||
|
while (c == ' ') {ss.read(&c, 1); c = ss.peek();} //gobble spaces after comma
|
||||||
|
if (!(ss >> Z)) {
|
||||||
|
std::cerr << "Z error\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
polygon.push_back(Vertex3K(X, Y, Z));
|
||||||
|
}
|
||||||
|
if (polygon.size() > 0) polyhole.push_back(polygon);
|
||||||
|
ifs.close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
|
||||||
|
OpenSCAD::debug = "decompose";
|
||||||
|
|
||||||
|
PolySet *ps = NULL;
|
||||||
|
if (argc == 2) {
|
||||||
|
if (!(ps = import_stl(argv[1]))) {
|
||||||
|
std::cerr << "Error importing STL " << argv[1] << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
std::cerr << "Imported " << ps->numPolygons() << " polygons" << std::endl;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::cerr << "Usage: " << argv[0] << " <file.stl> <file.stl>" << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Geometry::ChildList children;
|
||||||
|
|
||||||
|
CGAL_Nef_polyhedron *N = createNefPolyhedronFromGeometry(*ps);
|
||||||
|
|
||||||
|
std::vector<PolyhedronK> result;
|
||||||
|
decompose(N->p3.get(), std::back_inserter(result));
|
||||||
|
|
||||||
|
std::cerr << "Decomposed into " << result.size() << " convex parts" << std::endl;
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
BOOST_FOREACH(const PolyhedronK &P, result) {
|
||||||
|
PolySet result_ps(3);
|
||||||
|
if (CGALUtils::createPolySetFromPolyhedron(P, result_ps)) {
|
||||||
|
std::cerr << "Error converting to PolySet\n";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "out" << idx++ << ".stl";
|
||||||
|
exportFileByName(&result_ps, OPENSCAD_STL, ss.str().c_str(), ss.str().c_str());
|
||||||
|
std::cout << "color([" << colors[idx%147][0] << "," << colors[idx%147][1] << "," << colors[idx%147][2] << "]) " << "import(\"" << ss.str() << "\");\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cerr << "Done." << std::endl;
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
CONFIG += debug
|
||||||
|
CONFIG -= qt
|
||||||
|
debug: DEFINES += DEBUG
|
||||||
|
|
||||||
|
TEMPLATE = app
|
||||||
|
|
||||||
|
INCLUDEPATH += ../src
|
||||||
|
DEPENDPATH += ../src
|
||||||
|
|
||||||
|
# Handle custom library location.
|
||||||
|
# Used when manually installing 3rd party libraries
|
||||||
|
isEmpty(OPENSCAD_LIBDIR) OPENSCAD_LIBDIR = $$(OPENSCAD_LIBRARIES)
|
||||||
|
macx:isEmpty(OPENSCAD_LIBDIR) {
|
||||||
|
exists(/opt/local):exists(/usr/local/Cellar) {
|
||||||
|
error("It seems you might have libraries in both /opt/local and /usr/local. Please specify which one to use with qmake OPENSCAD_LIBDIR=<prefix>")
|
||||||
|
} else {
|
||||||
|
exists(/opt/local) {
|
||||||
|
#Default to MacPorts on Mac OS X
|
||||||
|
message("Automatically searching for libraries in /opt/local. To override, use qmake OPENSCAD_LIBDIR=<prefix>")
|
||||||
|
OPENSCAD_LIBDIR = /opt/local
|
||||||
|
} else:exists(/usr/local/Cellar) {
|
||||||
|
message("Automatically searching for libraries in /usr/local. To override, use qmake OPENSCAD_LIBDIR=<prefix>")
|
||||||
|
OPENSCAD_LIBDIR = /usr/local
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
!isEmpty(OPENSCAD_LIBDIR) {
|
||||||
|
QMAKE_INCDIR = $$OPENSCAD_LIBDIR/include
|
||||||
|
QMAKE_LIBDIR = $$OPENSCAD_LIBDIR/lib
|
||||||
|
}
|
||||||
|
|
||||||
|
TARGET = decompose
|
||||||
|
mac {
|
||||||
|
CONFIG -= app_bundle
|
||||||
|
}
|
||||||
|
|
||||||
|
macx {
|
||||||
|
# Mac needs special care to link against the correct C++ library
|
||||||
|
# We attempt to auto-detect it by inspecting Boost
|
||||||
|
dirs = $${BOOSTDIR} $${QMAKE_LIBDIR}
|
||||||
|
for(dir, dirs) {
|
||||||
|
system(grep -q __112basic_string $${dir}/libboost_thread* >& /dev/null) {
|
||||||
|
message("Detected libc++-linked boost in $${dir}")
|
||||||
|
CONFIG += libc++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
libc++ {
|
||||||
|
QMAKE_CXXFLAGS += -stdlib=libc++
|
||||||
|
QMAKE_LFLAGS += -stdlib=libc++
|
||||||
|
QMAKE_OBJECTIVE_CFLAGS += -stdlib=libc++
|
||||||
|
# libc++ on requires Mac OS X 10.7+
|
||||||
|
QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.7
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# See Dec 2011 OpenSCAD mailing list, re: CGAL/GCC bugs.
|
||||||
|
*g++* {
|
||||||
|
QMAKE_CXXFLAGS *= -fno-strict-aliasing
|
||||||
|
QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-local-typedefs # ignored before 4.8
|
||||||
|
}
|
||||||
|
|
||||||
|
*clang* {
|
||||||
|
# http://llvm.org/bugs/show_bug.cgi?id=9182
|
||||||
|
QMAKE_CXXFLAGS_WARN_ON += -Wno-overloaded-virtual
|
||||||
|
# disable enormous amount of warnings about CGAL / boost / etc
|
||||||
|
QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-parameter
|
||||||
|
QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-variable
|
||||||
|
QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-function
|
||||||
|
QMAKE_CXXFLAGS_WARN_ON += -Wno-c++11-extensions
|
||||||
|
# might want to actually turn this on once in a while
|
||||||
|
QMAKE_CXXFLAGS_WARN_ON += -Wno-sign-compare
|
||||||
|
}
|
||||||
|
|
||||||
|
# Application configuration
|
||||||
|
CONFIG += cgal
|
||||||
|
CONFIG += boost
|
||||||
|
CONFIG += eigen
|
||||||
|
CONFIG += gettext
|
||||||
|
|
||||||
|
mac: {
|
||||||
|
LIBS += -framework OpenGL
|
||||||
|
}
|
||||||
|
|
||||||
|
include(../common.pri)
|
||||||
|
|
||||||
|
HEADERS += ../src/cgal.h \
|
||||||
|
../src/cgalutils.h \
|
||||||
|
../src/linalg.h \
|
||||||
|
../src/polyset.h \
|
||||||
|
../src/polyset-utils.h \
|
||||||
|
../src/printutils.h
|
||||||
|
|
||||||
|
SOURCES += decompose.cpp \
|
||||||
|
../src/polygon2d.cc \
|
||||||
|
../src/polygon2d-CGAL.cc \
|
||||||
|
../src/CGAL_Nef_polyhedron.cc \
|
||||||
|
../src/CGAL_Nef_polyhedron_DxfData.cc \
|
||||||
|
../src/cgalutils.cc \
|
||||||
|
../src/cgalutils-tess.cc \
|
||||||
|
../src/cgalutils-polyhedron.cc \
|
||||||
|
../src/polyset.cc \
|
||||||
|
../src/svg.cc \
|
||||||
|
../src/node.cc \
|
||||||
|
../src/export.cc \
|
||||||
|
../src/polyset-utils.cc \
|
||||||
|
../src/progress.cc \
|
||||||
|
../src/printutils.cc
|
|
@ -0,0 +1,140 @@
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <locale.h>
|
||||||
|
|
||||||
|
#include "cgalutils.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Nef polyhedron are using CGAL_Kernel3 (Cartesian<Gmpq>)
|
||||||
|
// Triangulation will use Epick
|
||||||
|
|
||||||
|
static void export_stl(const Polygons &triangles, std::ostream &output)
|
||||||
|
{
|
||||||
|
setlocale(LC_NUMERIC, "C"); // Ensure radix is . (not ,) in output
|
||||||
|
output << "solid OpenSCAD_Model\n";
|
||||||
|
BOOST_FOREACH(const Polygon &p, triangles) {
|
||||||
|
assert(p.size() == 3); // STL only allows triangles
|
||||||
|
std::stringstream stream;
|
||||||
|
stream << p[0][0] << " " << p[0][1] << " " << p[0][2];
|
||||||
|
std::string vs1 = stream.str();
|
||||||
|
stream.str("");
|
||||||
|
stream << p[1][0] << " " << p[1][1] << " " << p[1][2];
|
||||||
|
std::string vs2 = stream.str();
|
||||||
|
stream.str("");
|
||||||
|
stream << p[2][0] << " " << p[2][1] << " " << p[2][2];
|
||||||
|
std::string vs3 = stream.str();
|
||||||
|
if (vs1 != vs2 && vs1 != vs3 && vs2 != vs3) {
|
||||||
|
// The above condition ensures that there are 3 distinct vertices, but
|
||||||
|
// they may be collinear. If they are, the unit normal is meaningless
|
||||||
|
// so the default value of "1 0 0" can be used. If the vertices are not
|
||||||
|
// collinear then the unit normal must be calculated from the
|
||||||
|
// components.
|
||||||
|
Vector3d normal = (p[1] - p[0]).cross(p[2] - p[0]);
|
||||||
|
normal.normalize();
|
||||||
|
output << " facet normal " << normal[0] << " " << normal[1] << " " << normal[2] << "\n";
|
||||||
|
output << " outer loop\n";
|
||||||
|
|
||||||
|
BOOST_FOREACH(const Vector3d &v, p) {
|
||||||
|
output << " vertex " << v[0] << " " << v[1] << " " << v[2] << "\n";
|
||||||
|
}
|
||||||
|
output << " endloop\n";
|
||||||
|
output << " endfacet\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output << "endsolid OpenSCAD_Model\n";
|
||||||
|
setlocale(LC_NUMERIC, ""); // Set default locale
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
file format:
|
||||||
|
1. polygon coordinates (x,y,z) are comma separated (+/- spaces) and
|
||||||
|
each coordinate is on a separate line
|
||||||
|
2. each polygon is separated by one or more blank lines
|
||||||
|
*/
|
||||||
|
bool import_polygon(PolyholeK &polyhole, const std::string &filename)
|
||||||
|
{
|
||||||
|
std::ifstream ifs(filename.c_str());
|
||||||
|
if (!ifs) return false;
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
PolygonK polygon;
|
||||||
|
while (std::getline(ifs, line)) {
|
||||||
|
std::stringstream ss(line);
|
||||||
|
double X = 0.0, Y = 0.0, Z = 0.0;
|
||||||
|
if (!(ss >> X)) {
|
||||||
|
//ie blank lines => flag start of next polygon
|
||||||
|
if (polygon.size() > 0) polyhole.push_back(polygon);
|
||||||
|
polygon.clear();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
char c = ss.peek();
|
||||||
|
while (c == ' ') {ss.read(&c, 1); c = ss.peek();} //gobble spaces before comma
|
||||||
|
if (c == ',') {ss.read(&c, 1); c = ss.peek();} //gobble comma
|
||||||
|
while (c == ' ') {ss.read(&c, 1); c = ss.peek();} //gobble spaces after comma
|
||||||
|
if (!(ss >> Y)) {
|
||||||
|
std::cerr << "Y error\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
c = ss.peek();
|
||||||
|
while (c == ' ') {ss.read(&c, 1); c = ss.peek();} //gobble spaces before comma
|
||||||
|
if (c == ',') {ss.read(&c, 1); c = ss.peek();} //gobble comma
|
||||||
|
while (c == ' ') {ss.read(&c, 1); c = ss.peek();} //gobble spaces after comma
|
||||||
|
if (!(ss >> Z)) {
|
||||||
|
std::cerr << "Z error\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
polygon.push_back(Vertex3K(X, Y, Z));
|
||||||
|
}
|
||||||
|
if (polygon.size() > 0) polyhole.push_back(polygon);
|
||||||
|
ifs.close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
PolyholeK polyhole;
|
||||||
|
K::Vector_3 *normal = NULL;
|
||||||
|
if (argc >= 2) {
|
||||||
|
if (!import_polygon(polyhole, argv[1])) {
|
||||||
|
std::cerr << "Error importing polygon" << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
std::cerr << "Imported " << polyhole.size() << " polygons" << std::endl;
|
||||||
|
|
||||||
|
if (argc == 3) {
|
||||||
|
std::vector<std::string> strs;
|
||||||
|
std::vector<double> normalvec;
|
||||||
|
std::string arg(argv[2]);
|
||||||
|
boost::split(strs, arg, boost::is_any_of(","));
|
||||||
|
assert(strs.size() == 3);
|
||||||
|
BOOST_FOREACH(const std::string &s, strs) normalvec.push_back(boost::lexical_cast<double>(s));
|
||||||
|
normal = new K::Vector_3(normalvec[0], normalvec[1], normalvec[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//construct two non-intersecting nested polygons
|
||||||
|
PolygonK polygon1;
|
||||||
|
polygon1.push_back(Vertex3K(0,0,0));
|
||||||
|
polygon1.push_back(Vertex3K(2,0,0));
|
||||||
|
polygon1.push_back(Vertex3K(2,2,0));
|
||||||
|
polygon1.push_back(Vertex3K(0,2,0));
|
||||||
|
PolygonK polygon2;
|
||||||
|
polygon2.push_back(Vertex3K(0.5,0.5,0));
|
||||||
|
polygon2.push_back(Vertex3K(1.5,0.5,0));
|
||||||
|
polygon2.push_back(Vertex3K(1.5,1.5,0));
|
||||||
|
polygon2.push_back(Vertex3K(0.5,1.5,0));
|
||||||
|
polyhole.push_back(polygon1);
|
||||||
|
polyhole.push_back(polygon2);
|
||||||
|
}
|
||||||
|
|
||||||
|
Polygons triangles;
|
||||||
|
bool ok = CGALUtils::tessellatePolygonWithHoles(polyhole, triangles, normal);
|
||||||
|
std::cerr << "Tessellated into " << triangles.size() << " triangles" << std::endl;
|
||||||
|
|
||||||
|
export_stl(triangles, std::cout);
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
debug: DEFINES += DEBUG
|
||||||
|
|
||||||
|
TEMPLATE = app
|
||||||
|
|
||||||
|
INCLUDEPATH += ../src
|
||||||
|
DEPENDPATH += ../src
|
||||||
|
|
||||||
|
# Handle custom library location.
|
||||||
|
# Used when manually installing 3rd party libraries
|
||||||
|
isEmpty(OPENSCAD_LIBDIR) OPENSCAD_LIBDIR = $$(OPENSCAD_LIBRARIES)
|
||||||
|
macx:isEmpty(OPENSCAD_LIBDIR) {
|
||||||
|
exists(/opt/local):exists(/usr/local/Cellar) {
|
||||||
|
error("It seems you might have libraries in both /opt/local and /usr/local. Please specify which one to use with qmake OPENSCAD_LIBDIR=<prefix>")
|
||||||
|
} else {
|
||||||
|
exists(/opt/local) {
|
||||||
|
#Default to MacPorts on Mac OS X
|
||||||
|
message("Automatically searching for libraries in /opt/local. To override, use qmake OPENSCAD_LIBDIR=<prefix>")
|
||||||
|
OPENSCAD_LIBDIR = /opt/local
|
||||||
|
} else:exists(/usr/local/Cellar) {
|
||||||
|
message("Automatically searching for libraries in /usr/local. To override, use qmake OPENSCAD_LIBDIR=<prefix>")
|
||||||
|
OPENSCAD_LIBDIR = /usr/local
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
!isEmpty(OPENSCAD_LIBDIR) {
|
||||||
|
QMAKE_INCDIR = $$OPENSCAD_LIBDIR/include
|
||||||
|
QMAKE_LIBDIR = $$OPENSCAD_LIBDIR/lib
|
||||||
|
}
|
||||||
|
|
||||||
|
TARGET = polyhole-tessellator
|
||||||
|
mac {
|
||||||
|
CONFIG -= app_bundle
|
||||||
|
}
|
||||||
|
|
||||||
|
macx {
|
||||||
|
# Mac needs special care to link against the correct C++ library
|
||||||
|
# We attempt to auto-detect it by inspecting Boost
|
||||||
|
dirs = $${BOOSTDIR} $${QMAKE_LIBDIR}
|
||||||
|
for(dir, dirs) {
|
||||||
|
system(grep -q __112basic_string $${dir}/libboost_thread* >& /dev/null) {
|
||||||
|
message("Detected libc++-linked boost in $${dir}")
|
||||||
|
CONFIG += libc++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
libc++ {
|
||||||
|
QMAKE_CXXFLAGS += -stdlib=libc++
|
||||||
|
QMAKE_LFLAGS += -stdlib=libc++
|
||||||
|
QMAKE_OBJECTIVE_CFLAGS += -stdlib=libc++
|
||||||
|
# libc++ on requires Mac OS X 10.7+
|
||||||
|
QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.7
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# See Dec 2011 OpenSCAD mailing list, re: CGAL/GCC bugs.
|
||||||
|
*g++* {
|
||||||
|
QMAKE_CXXFLAGS *= -fno-strict-aliasing
|
||||||
|
QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-local-typedefs # ignored before 4.8
|
||||||
|
}
|
||||||
|
|
||||||
|
*clang* {
|
||||||
|
# http://llvm.org/bugs/show_bug.cgi?id=9182
|
||||||
|
QMAKE_CXXFLAGS_WARN_ON += -Wno-overloaded-virtual
|
||||||
|
# disable enormous amount of warnings about CGAL / boost / etc
|
||||||
|
QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-parameter
|
||||||
|
QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-variable
|
||||||
|
QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-function
|
||||||
|
QMAKE_CXXFLAGS_WARN_ON += -Wno-c++11-extensions
|
||||||
|
# might want to actually turn this on once in a while
|
||||||
|
QMAKE_CXXFLAGS_WARN_ON += -Wno-format-security
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Application configuration
|
||||||
|
CONFIG += cgal
|
||||||
|
CONFIG += boost
|
||||||
|
CONFIG += eigen
|
||||||
|
CONFIG += gettext
|
||||||
|
|
||||||
|
include(../common.pri)
|
||||||
|
|
||||||
|
HEADERS += ../src/cgal.h \
|
||||||
|
../src/cgalutils.h \
|
||||||
|
../src/linalg.h \
|
||||||
|
../src/printutils.h
|
||||||
|
|
||||||
|
SOURCES += polyhole-tessellator.cpp \
|
||||||
|
../src/cgalutils-tess.cc \
|
||||||
|
../src/printutils.cc
|
|
@ -1,31 +1,36 @@
|
||||||
{
|
{
|
||||||
"name" : "For Dark Background",
|
"name" : "For Dark Background",
|
||||||
"index" : 1100,
|
"index" : 1100,
|
||||||
"paper" : "#272822",
|
"paper" : "#222222",
|
||||||
"text" : "#ffffff",
|
"text" : "#e0e0e0",
|
||||||
"caret" : {
|
"caret" : {
|
||||||
"width" : 2,
|
"width" : 2,
|
||||||
"foreground" : "#ffff00",
|
"foreground" : "#ffff00",
|
||||||
"line-background" : "#68e1687f"
|
"line-background" : "#303030"
|
||||||
},
|
},
|
||||||
"colors" : {
|
"colors" : {
|
||||||
"keyword1" : "#f12971",
|
"keyword1" : "#90ee90",
|
||||||
"keyword2" : "#56dbf0",
|
"keyword2" : "#56dbf0",
|
||||||
"keyword3" : "#56d8f0",
|
"keyword3" : "#add8e6",
|
||||||
"comment" : "#ccdf32",
|
"comment" : "#808080",
|
||||||
"number" : "#af7dff",
|
"commentline" : "#808080",
|
||||||
|
"commentdoc" : "#808080",
|
||||||
|
"commentdockeyword" : "#808080",
|
||||||
|
"number" : "#ff0000",
|
||||||
"string" : "#e6db74",
|
"string" : "#e6db74",
|
||||||
"operator" : "#d8d8d8",
|
"operator" : "#e8b609",
|
||||||
"commentline" : "#e6db74",
|
"whitespace-foreground" : "#e0e0e0",
|
||||||
"selection-foreground" : "#ffff00",
|
"selection-foreground" : "#ffffff",
|
||||||
"selection-background" : "#a0a0ff",
|
"selection-background" : "#4a90d9",
|
||||||
"margin-background" : "#14141496",
|
"margin-background" : "#272822",
|
||||||
"margin-foreground" : "#fff",
|
"margin-foreground" : "#e0e0e0",
|
||||||
"matched-brace-background" : "#333",
|
"matched-brace-background" : "#505050",
|
||||||
"matched-brace-foreground" : "#fff",
|
"matched-brace-foreground" : "#ffffff",
|
||||||
"unmatched-brace-background" : "#333",
|
"unmatched-brace-background" : "#dc322f",
|
||||||
"unmatched-brace-foreground" : "#fff",
|
"unmatched-brace-foreground" : "#fdf6e3",
|
||||||
"error-marker" : "#ff0000",
|
"error-marker" : "#ff0000",
|
||||||
|
"error-indicator" : "#60ff0000",
|
||||||
|
"error-indicator-outline" : "#ff000000",
|
||||||
"edge" : "#ffffff"
|
"edge" : "#ffffff"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,31 +1,36 @@
|
||||||
{
|
{
|
||||||
"name" : "For Light Background",
|
"name" : "For Light Background",
|
||||||
"index" : 1000,
|
"index" : 1000,
|
||||||
"paper" : "#fff",
|
"paper" : "#ffffff",
|
||||||
"text" : "#272822",
|
"text" : "#272822",
|
||||||
"caret" : {
|
"caret" : {
|
||||||
"width" : 2,
|
"width" : 2,
|
||||||
"foreground" : "#000000",
|
"foreground" : "#000000",
|
||||||
"line-background" : "#ffe4e4"
|
"line-background" : "#f8f8f8"
|
||||||
},
|
},
|
||||||
"colors" : {
|
"colors" : {
|
||||||
"keyword1" : "Green",
|
"keyword1" : "Green",
|
||||||
"keyword2" : "Green",
|
"keyword2" : "Green",
|
||||||
"keyword3" : "DarkBlue",
|
"keyword3" : "DarkBlue",
|
||||||
"comment" : "DarkCyan",
|
"comment" : "DarkCyan",
|
||||||
|
"commentline" : "DarkCyan",
|
||||||
|
"commentdoc" : "DarkCyan",
|
||||||
|
"commentdockeyword" : "DarkCyan",
|
||||||
"number" : "DarkRed",
|
"number" : "DarkRed",
|
||||||
"string" : "DarkMagenta",
|
"string" : "DarkMagenta",
|
||||||
"operator" : "Blue",
|
"operator" : "Blue",
|
||||||
"commentline" : "DarkCyan",
|
"whitespace-foreground" : "#272822",
|
||||||
"selection-foreground" : "#ffff00",
|
"selection-foreground" : "#ffffff",
|
||||||
"selection-background" : "#a0a0ff",
|
"selection-background" : "#4a90d9",
|
||||||
"margin-background" : "#ccc",
|
"margin-background" : "#f8f8f8",
|
||||||
"margin-foreground" : "#111",
|
"margin-foreground" : "#000000",
|
||||||
"matched-brace-background" : "#333",
|
"matched-brace-background" : "#c7f6cb",
|
||||||
"matched-brace-foreground" : "#fff",
|
"matched-brace-foreground" : "Blue",
|
||||||
"unmatched-brace-background" : "#333",
|
"unmatched-brace-background" : "#ffcdcc",
|
||||||
"unmatched-brace-foreground" : "#fff",
|
"unmatched-brace-foreground" : "Blue",
|
||||||
"error-marker" : "#ff0000",
|
"error-marker" : "#ff0000",
|
||||||
|
"error-indicator" : "#60ff0000",
|
||||||
|
"error-indicator-outline" : "#ff000000",
|
||||||
"edge" : "#ffffff"
|
"edge" : "#ffffff"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,27 +5,32 @@
|
||||||
"text" : "#f8f8f2",
|
"text" : "#f8f8f2",
|
||||||
"caret" : {
|
"caret" : {
|
||||||
"width" : 2,
|
"width" : 2,
|
||||||
"foreground" : "#ffff00",
|
"foreground" : "#f8f8f2",
|
||||||
"line-background" : "#3e3d32"
|
"line-background" : "#49483e"
|
||||||
},
|
},
|
||||||
"colors" : {
|
"colors" : {
|
||||||
"keyword1" : "#66c3b3",
|
"keyword1" : "#f92672",
|
||||||
"keyword2" : "#79abff",
|
"keyword2" : "#a6e22e",
|
||||||
"keyword3" : "#ffffff",
|
"keyword3" : "#66d9ef",
|
||||||
"comment" : "#ccdf32",
|
"comment" : "#75715e",
|
||||||
"number" : "#7fb347",
|
|
||||||
"string" : "#e6db74",
|
|
||||||
"operator" : "#d8d8d8",
|
|
||||||
"commentline" : "#75715e",
|
"commentline" : "#75715e",
|
||||||
"selection-foreground" : "#ffff00",
|
"commentdoc" : "#75715e",
|
||||||
"selection-background" : "#a0a0ff",
|
"commentdockeyword" : "#7b9a3c",
|
||||||
"margin-background" : "#757575",
|
"number" : "#ae81ff",
|
||||||
|
"string" : "#e6db74",
|
||||||
|
"operator" : "#f8f8f2",
|
||||||
|
"whitespace-foreground" : "#f8f8f2",
|
||||||
|
"selection-foreground" : "#272822",
|
||||||
|
"selection-background" : "#f8f8f2",
|
||||||
|
"margin-background" : "#3e3d32",
|
||||||
"margin-foreground" : "#f8f8f2",
|
"margin-foreground" : "#f8f8f2",
|
||||||
"matched-brace-background" : "#333",
|
"matched-brace-background" : "#606060",
|
||||||
"matched-brace-foreground" : "#fff",
|
"matched-brace-foreground" : "#ffff00",
|
||||||
"unmatched-brace-background" : "#333",
|
"unmatched-brace-background" : "#b06060",
|
||||||
"unmatched-brace-foreground" : "#fff",
|
"unmatched-brace-foreground" : "#ffff00",
|
||||||
"error-marker" : "#ff0000",
|
"error-marker" : "#ff0000",
|
||||||
|
"error-indicator" : "#80ffe0e0",
|
||||||
|
"error-indicator-outline" : "#ff000000",
|
||||||
"edge" : "#ffffff"
|
"edge" : "#ffffff"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
{
|
||||||
|
"name" : "Solarized (dark)",
|
||||||
|
"index" : 1310,
|
||||||
|
"paper" : "#002b36",
|
||||||
|
"text" : "#839496",
|
||||||
|
"caret" : {
|
||||||
|
"width" : 2,
|
||||||
|
"foreground" : "#fff070",
|
||||||
|
"line-background" : "#073642"
|
||||||
|
},
|
||||||
|
"colors" : {
|
||||||
|
"keyword1" : "#268ad1",
|
||||||
|
"keyword2" : "#2aa198",
|
||||||
|
"keyword3" : "#859900",
|
||||||
|
"comment" : "#657b83",
|
||||||
|
"commentline" : "#657b83",
|
||||||
|
"commentdoc" : "#657b83",
|
||||||
|
"commentdockeyword" : "#6c71c4",
|
||||||
|
"number" : "#d33682",
|
||||||
|
"string" : "#b58900",
|
||||||
|
"operator" : "#cb4b16",
|
||||||
|
"whitespace-foreground" : "#839496",
|
||||||
|
"selection-foreground" : "#fdf6e3",
|
||||||
|
"selection-background" : "#657b83",
|
||||||
|
"margin-background" : "#002b36",
|
||||||
|
"margin-foreground" : "#839496",
|
||||||
|
"matched-brace-background" : "#0c4e22",
|
||||||
|
"matched-brace-foreground" : "#fff070",
|
||||||
|
"unmatched-brace-background" : "#92211f",
|
||||||
|
"unmatched-brace-foreground" : "#fff070",
|
||||||
|
"error-marker" : "#ff0000",
|
||||||
|
"error-indicator" : "#90ff8080",
|
||||||
|
"error-indicator-outline" : "#ff000000",
|
||||||
|
"edge" : "#d33682"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
{
|
||||||
|
"name" : "Solarized (light)",
|
||||||
|
"index" : 1300,
|
||||||
|
"paper" : "#fdf6e3",
|
||||||
|
"text" : "#657b83",
|
||||||
|
"caret" : {
|
||||||
|
"width" : 2,
|
||||||
|
"foreground" : "#000000",
|
||||||
|
"line-background" : "#eee8d5"
|
||||||
|
},
|
||||||
|
"colors" : {
|
||||||
|
"keyword1" : "#268ad1",
|
||||||
|
"keyword2" : "#2aa198",
|
||||||
|
"keyword3" : "#859900",
|
||||||
|
"comment" : "#93a1a1",
|
||||||
|
"commentline" : "#93a1a1",
|
||||||
|
"commentdoc" : "#93a1a1",
|
||||||
|
"commentdockeyword" : "#6c71c4",
|
||||||
|
"number" : "#d33682",
|
||||||
|
"string" : "#b58900",
|
||||||
|
"operator" : "#cb4b16",
|
||||||
|
"whitespace-foreground" : "#657b83",
|
||||||
|
"selection-foreground" : "#fdf6e3",
|
||||||
|
"selection-background" : "#657b83",
|
||||||
|
"margin-background" : "#eee8d5",
|
||||||
|
"margin-foreground" : "#657b83",
|
||||||
|
"matched-brace-background" : "#c7f6cb",
|
||||||
|
"matched-brace-foreground" : "#cb4b16",
|
||||||
|
"unmatched-brace-background" : "#ffcdcc",
|
||||||
|
"unmatched-brace-foreground" : "#cb4b16",
|
||||||
|
"error-marker" : "#ff0000",
|
||||||
|
"error-indicator" : "#80ff0000",
|
||||||
|
"error-indicator-outline" : "#ff000000",
|
||||||
|
"edge" : "#d33682"
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,31 +0,0 @@
|
||||||
{
|
|
||||||
"name" : "Solarized",
|
|
||||||
"index" : 1300,
|
|
||||||
"paper" : "#fdf6e3",
|
|
||||||
"text" : "#657b83",
|
|
||||||
"caret" : {
|
|
||||||
"width" : 2,
|
|
||||||
"foreground" : "#0000ff",
|
|
||||||
"line-background" : "#eeead5"
|
|
||||||
},
|
|
||||||
"colors" : {
|
|
||||||
"keyword1" : "#268ad1",
|
|
||||||
"keyword2" : "#6c71c4",
|
|
||||||
"keyword3" : "#b58800",
|
|
||||||
"comment" : "#b58900",
|
|
||||||
"number" : "#cb4b16",
|
|
||||||
"string" : "#2aa198",
|
|
||||||
"operator" : "#859900",
|
|
||||||
"commentline" : "#b58800",
|
|
||||||
"selection-foreground" : "#fdf6e3",
|
|
||||||
"selection-background" : "#657b83",
|
|
||||||
"margin-background" : "#eee8d5",
|
|
||||||
"margin-foreground" : "#93a1a1",
|
|
||||||
"matched-brace-background" : "#333",
|
|
||||||
"matched-brace-foreground" : "#fff",
|
|
||||||
"unmatched-brace-background" : "#333",
|
|
||||||
"unmatched-brace-foreground" : "#fff",
|
|
||||||
"error-marker" : "#ff0000",
|
|
||||||
"edge" : "#ffffff"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
{
|
||||||
|
"name" : "Tomorrow Night",
|
||||||
|
"index" : 1600,
|
||||||
|
"paper" : "#1d1f21",
|
||||||
|
"text" : "#c5c8c6",
|
||||||
|
"caret" : {
|
||||||
|
"width" : 2,
|
||||||
|
"foreground" : "#ffffff",
|
||||||
|
"line-background" : "#282a2e"
|
||||||
|
},
|
||||||
|
"colors" : {
|
||||||
|
"keyword1" : "#de935f",
|
||||||
|
"keyword2" : "#b294bb",
|
||||||
|
"keyword3" : "#81a2be",
|
||||||
|
"comment" : "#969896",
|
||||||
|
"commentline" : "#969896",
|
||||||
|
"commentdoc" : "#969896",
|
||||||
|
"commentdockeyword" : "#f0c674",
|
||||||
|
"number" : "#cc6666",
|
||||||
|
"string" : "#b5bd68",
|
||||||
|
"operator" : "#8abeb7",
|
||||||
|
"whitespace-foreground" : "#c5c8c6",
|
||||||
|
"selection-foreground" : "#373b41",
|
||||||
|
"selection-background" : "#c5c8c6",
|
||||||
|
"margin-background" : "#1d1f21",
|
||||||
|
"margin-foreground" : "#969896",
|
||||||
|
"matched-brace-background" : "#50545c",
|
||||||
|
"matched-brace-foreground" : "#e2e6e3",
|
||||||
|
"unmatched-brace-background" : "#8a1111",
|
||||||
|
"unmatched-brace-foreground" : "#e2e6e3",
|
||||||
|
"error-marker" : "#ff0000",
|
||||||
|
"error-indicator" : "#80ff0000",
|
||||||
|
"error-indicator-outline" : "#ff000000",
|
||||||
|
"edge" : "#d33682"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
{
|
||||||
|
"name" : "Tomorrow",
|
||||||
|
"index" : 1500,
|
||||||
|
"paper" : "#f8f8f8",
|
||||||
|
"text" : "#4d4d4c",
|
||||||
|
"caret" : {
|
||||||
|
"width" : 2,
|
||||||
|
"foreground" : "#000000",
|
||||||
|
"line-background" : "#efefef"
|
||||||
|
},
|
||||||
|
"colors" : {
|
||||||
|
"keyword1" : "#f5871f",
|
||||||
|
"keyword2" : "#8959a8",
|
||||||
|
"keyword3" : "#4271ae",
|
||||||
|
"comment" : "#8e908c",
|
||||||
|
"commentline" : "#8e908c",
|
||||||
|
"commentdoc" : "#8e908c",
|
||||||
|
"commentdockeyword" : "#eab700",
|
||||||
|
"number" : "#c82829",
|
||||||
|
"string" : "#718c00",
|
||||||
|
"operator" : "#3e999f",
|
||||||
|
"whitespace-foreground" : "#4d4d4c",
|
||||||
|
"selection-foreground" : "#4d4d4c",
|
||||||
|
"selection-background" : "#d6d6d6",
|
||||||
|
"margin-background" : "#f8f8f8",
|
||||||
|
"margin-foreground" : "#4d4d4c",
|
||||||
|
"matched-brace-background" : "#c7f6cb",
|
||||||
|
"matched-brace-foreground" : "#4d4d4c",
|
||||||
|
"unmatched-brace-background" : "#ffcdcc",
|
||||||
|
"unmatched-brace-foreground" : "#4d4d4c",
|
||||||
|
"error-marker" : "#ff0000",
|
||||||
|
"error-indicator" : "#80ff0000",
|
||||||
|
"error-indicator-outline" : "#ff000000",
|
||||||
|
"edge" : "#d33682"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
{
|
||||||
|
"name" : "Visual Studio",
|
||||||
|
"index" : 1400,
|
||||||
|
"paper" : "#ffffff",
|
||||||
|
"text" : "#101010",
|
||||||
|
"caret" : {
|
||||||
|
"width" : 2,
|
||||||
|
"foreground" : "#000000",
|
||||||
|
"line-background" : "#eeeeee"
|
||||||
|
},
|
||||||
|
"colors" : {
|
||||||
|
"keyword1" : "blue",
|
||||||
|
"keyword2" : "blue",
|
||||||
|
"keyword3" : "#2B91AF",
|
||||||
|
"comment" : "DarkGreen",
|
||||||
|
"commentline" : "DarkGreen",
|
||||||
|
"commentdoc" : "#DarkGreen",
|
||||||
|
"commentdockeyword" : "#DarkGreen",
|
||||||
|
"number" : "DarkRed",
|
||||||
|
"string" : "#A31515",
|
||||||
|
"operator" : "Blue",
|
||||||
|
"whitespace-foreground" : "#101010",
|
||||||
|
"selection-foreground" : "black",
|
||||||
|
"selection-background" : "lightblue",
|
||||||
|
"margin-background" : "white",
|
||||||
|
"margin-foreground" : "#2B91AF",
|
||||||
|
"matched-brace-background" : "darkgrey",
|
||||||
|
"matched-brace-foreground" : "black",
|
||||||
|
"unmatched-brace-background" : "red",
|
||||||
|
"unmatched-brace-foreground" : "#ffffff",
|
||||||
|
"error-marker" : "#ff0000",
|
||||||
|
"error-indicator" : "#60ff0000",
|
||||||
|
"error-indicator-outline" : "#ff000000",
|
||||||
|
"edge" : "#ffffff"
|
||||||
|
},
|
||||||
|
"keywords" : {
|
||||||
|
"keyword-set1" : "if else let for module function true false undef include use",
|
||||||
|
"keyword-set2" : "abs sign rands min max sin cos asin acos tan atan atan2 round ceil floor pow sqrt exp len log ln str chr concat lookup search version version_num norm cross parent_module dxf_dim dxf_cross",
|
||||||
|
"keyword-set3" : "cube sphere cylinder polyhedron square circle polygon text minkowski hull resize child echo union difference intersection linear_extrude rotate_extrude import group projection render surface scale rotate mirror translate multmatrix color offset"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
Color Schemes
|
||||||
|
=============
|
||||||
|
|
||||||
|
Solarized
|
||||||
|
---------
|
||||||
|
|
||||||
|
http://ethanschoonover.com/solarized
|
||||||
|
|
||||||
|
Monokai
|
||||||
|
-------
|
||||||
|
|
||||||
|
http://www.monokai.nl/blog/2006/07/15/textmate-color-theme/
|
||||||
|
|
||||||
|
Tomorrow / Tomorrow Night
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
https://github.com/chriskempson/tomorrow-theme
|
||||||
|
|
||||||
|
Editor:
|
||||||
|
|
||||||
|
keyword1 Orange
|
||||||
|
keyword2 Purple
|
||||||
|
keyword3 Blue
|
||||||
|
comment Comment
|
||||||
|
commentline Comment
|
||||||
|
commentdoc Comment
|
||||||
|
commentdockeyword Yellow
|
||||||
|
number Red
|
||||||
|
string Green
|
||||||
|
operator Aqua
|
||||||
|
selection-foreground Foreground
|
||||||
|
selection-background Selection
|
||||||
|
|
||||||
|
Render:
|
||||||
|
|
||||||
|
opencsg-face-front Blue
|
||||||
|
opencsg-face-back Orange
|
||||||
|
cgal-face-front Aqua
|
||||||
|
cgal-face-back Yellow
|
||||||
|
cgal-face-2d Green
|
||||||
|
cgal-edge-front Foreground
|
||||||
|
cgal-edge-back Foreground
|
||||||
|
cgal-edge-2d Red
|
||||||
|
crosshair Purple
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"name" : "Tomorrow Night",
|
||||||
|
"index" : 1900,
|
||||||
|
"show-in-gui" : true,
|
||||||
|
|
||||||
|
"colors" : {
|
||||||
|
"background" : "#1d1f21",
|
||||||
|
"opencsg-face-front" : "#81a2be",
|
||||||
|
"opencsg-face-back" : "#de935f",
|
||||||
|
"cgal-face-front" : "#8abeb7",
|
||||||
|
"cgal-face-back" : "#f0c674",
|
||||||
|
"cgal-face-2d" : "#b5bd68",
|
||||||
|
"cgal-edge-front" : "#c5c8c6",
|
||||||
|
"cgal-edge-back" : "#c5c8c6",
|
||||||
|
"cgal-edge-2d" : "#cc6666",
|
||||||
|
"crosshair" : "#b294bb"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"name" : "Tomorrow",
|
||||||
|
"index" : 1800,
|
||||||
|
"show-in-gui" : true,
|
||||||
|
|
||||||
|
"colors" : {
|
||||||
|
"background" : "#f8f8f8",
|
||||||
|
"opencsg-face-front" : "#4271ae",
|
||||||
|
"opencsg-face-back" : "#f5871f",
|
||||||
|
"cgal-face-front" : "#3e999f",
|
||||||
|
"cgal-face-back" : "#eab700",
|
||||||
|
"cgal-face-2d" : "#718c00",
|
||||||
|
"cgal-edge-front" : "#4d4d4c",
|
||||||
|
"cgal-edge-back" : "#4d4d4c",
|
||||||
|
"cgal-edge-2d" : "#c82829",
|
||||||
|
"crosshair" : "#8959a8"
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ include(glew.pri)
|
||||||
include(eigen.pri)
|
include(eigen.pri)
|
||||||
include(boost.pri)
|
include(boost.pri)
|
||||||
include(glib-2.0.pri)
|
include(glib-2.0.pri)
|
||||||
|
include(gettext.pri)
|
||||||
include(sparkle.pri)
|
include(sparkle.pri)
|
||||||
include(harfbuzz.pri)
|
include(harfbuzz.pri)
|
||||||
include(freetype.pri)
|
include(freetype.pri)
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
OpenSCAD human language translation
|
||||||
|
===================================
|
||||||
|
|
||||||
|
We use the GNU gettext system, both for c++ code as well as QT's .ui files.
|
||||||
|
The latter is accomplished by the '-tr' feature of QT's uic to insert
|
||||||
|
a gettext wrapper into the ui_xxxxx.h files.
|
||||||
|
|
||||||
|
For somewhat similar designs, see the source code of projects like celestia,
|
||||||
|
stellarium, licq, merkaartor, etc (although they typically use cmake).
|
||||||
|
|
||||||
|
Currently the build system does not auto-update anything. The .mo files must
|
||||||
|
be generated by running the gettext tools: xgettext, msgmerge, and msgfmt.
|
||||||
|
There is a script included, translation-update.sh, that automates this process.
|
||||||
|
|
||||||
|
File layout:
|
||||||
|
============
|
||||||
|
|
||||||
|
./locale/*.po - .po files, one per language
|
||||||
|
./locale/openscad.pot - .pot template, generated by xgettext
|
||||||
|
./locale/POTFILES - list of source files with translatable strings (generated)
|
||||||
|
./locale/LINGUAS - list of language codes for which .po files exist
|
||||||
|
./src/qtgettext.h - wrapper code between QT and GNU gettext
|
||||||
|
./scripts/translation-update.sh - simple unix helper script
|
||||||
|
./locale/xx/LC_MESSAGES/openscad.mo - 'binaries' of .po files, built by script
|
||||||
|
|
||||||
|
To translate the strings:
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Use a text editor or special program (poedit or lokalize) to edit the .po file.
|
||||||
|
( See http://en.opensuse.org/SDB:Localization_work_with_po_files )
|
||||||
|
Then submit your new .po file as an OpenSCAD github issue or pull request:
|
||||||
|
|
||||||
|
https://github.com/openscad/openscad/issues/
|
||||||
|
|
||||||
|
In the future there might be a site to allow translations in a browser:
|
||||||
|
|
||||||
|
https://translations.launchpad.net/openscad
|
||||||
|
|
||||||
|
If all else fails, email the OpenSCAD mailing list with your new .po
|
||||||
|
file attached.
|
||||||
|
|
||||||
|
To make source code changes:
|
||||||
|
============================
|
||||||
|
|
||||||
|
In .cc files, #include "printutils.h" and change each "text" into
|
||||||
|
_("text"). In .ui files, #include "qtgettext.h" first in the .h file
|
||||||
|
(see MainWindow.h). Then clean and rebuild to recreate the ui_xxxx.h
|
||||||
|
files.
|
||||||
|
|
||||||
|
$ make clean && qmake && make
|
||||||
|
|
||||||
|
Then run the script to scan the source files, and regenerate .pot & .po files.
|
||||||
|
|
||||||
|
$ ./scripts/translation-update.sh
|
||||||
|
|
||||||
|
This will create new .po files with any new untranslated strings you
|
||||||
|
added to the source code. These .po files can be distributed to
|
||||||
|
translators for translation. After the translated .po file is obtained,
|
||||||
|
overwrite the old .po and run the same script to update the .mo files.
|
||||||
|
|
||||||
|
$ ./scripts/translation-update.sh
|
||||||
|
|
||||||
|
To add a new language:
|
||||||
|
======================
|
||||||
|
|
||||||
|
First add the language code to file ./locale/LINGUAS. Then run msginit,
|
||||||
|
replacing $LANGCODE with the language code you want.
|
||||||
|
|
||||||
|
$ msginit -l $LANGCODE -o ./locale/$LANGCODE.po -i ./locale/openscad.pot
|
||||||
|
|
||||||
|
You will now have a new ./locale/xx.po file to edit and translate
|
||||||
|
|
||||||
|
Testing:
|
||||||
|
========
|
||||||
|
|
||||||
|
On unix, set the locale related environment variables. For example in
|
||||||
|
French, run this:
|
||||||
|
|
||||||
|
$ LANGUAGE=fr ./openscad
|
||||||
|
|
||||||
|
Linux system trace tools can help find errors. To show open()s on .mo files:
|
||||||
|
|
||||||
|
$ LANGUAGE=fr strace -f ./openscad 2>&1 | grep LC_MESSAGES
|
||||||
|
|
33
eigen.pri
33
eigen.pri
|
@ -1,18 +1,14 @@
|
||||||
# Detect eigen3 + eigen2, then use this priority list to determine
|
# Detect eigen3
|
||||||
# which eigen to use:
|
|
||||||
#
|
#
|
||||||
# Priority
|
# Priority
|
||||||
# 0. EIGENDIR if set (also EIGEN2DIR for backwards compatability)
|
# 0. EIGENDIR if set
|
||||||
# 1. OPENSCAD_LIBRARIES eigen3
|
# 1. OPENSCAD_LIBRARIES eigen3
|
||||||
# 2. OPENSCAD_LIBRARIES eigen2
|
|
||||||
# 3. system's standard include paths for eigen3
|
# 3. system's standard include paths for eigen3
|
||||||
# 4. system's standard include paths for eigen2
|
|
||||||
|
|
||||||
eigen {
|
eigen {
|
||||||
|
|
||||||
# read environment variables
|
# read environment variables
|
||||||
OPENSCAD_LIBRARIES_DIR = $$(OPENSCAD_LIBRARIES)
|
OPENSCAD_LIBRARIES_DIR = $$(OPENSCAD_LIBRARIES)
|
||||||
EIGEN2_DIR = $$(EIGEN2DIR)
|
|
||||||
EIGEN_DIR = $$(EIGENDIR)
|
EIGEN_DIR = $$(EIGENDIR)
|
||||||
|
|
||||||
# Optionally specify location of Eigen3 using the
|
# Optionally specify location of Eigen3 using the
|
||||||
|
@ -23,20 +19,8 @@ EIGEN_DIR = $$(EIGENDIR)
|
||||||
EIGEN_INCLUDEPATH = $$OPENSCAD_LIBRARIES_DIR/include/eigen3
|
EIGEN_INCLUDEPATH = $$OPENSCAD_LIBRARIES_DIR/include/eigen3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isEmpty(EIGEN_INCLUDEPATH) {
|
|
||||||
exists($$OPENSCAD_LIBRARIES_DIR/include/eigen2) {
|
|
||||||
EIGEN_INCLUDEPATH = $$OPENSCAD_LIBRARIES_DIR/include/eigen2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Optionally specify location of Eigen using the
|
|
||||||
# EIGENDIR env. variable (EIGEN2 for backwards compatability)
|
|
||||||
!isEmpty(EIGEN2_DIR) {
|
|
||||||
EIGEN_INCLUDEPATH = $$EIGEN2_DIR
|
|
||||||
message("User set EIGEN location: $$EIGEN_INCLUDEPATH")
|
|
||||||
}
|
|
||||||
!isEmpty(EIGEN_DIR) {
|
!isEmpty(EIGEN_DIR) {
|
||||||
EIGEN_INCLUDEPATH = $$EIGEN_DIR
|
EIGEN_INCLUDEPATH = $$EIGEN_DIR
|
||||||
message("User set EIGEN location: $$EIGEN_INCLUDEPATH")
|
message("User set EIGEN location: $$EIGEN_INCLUDEPATH")
|
||||||
|
@ -47,17 +31,6 @@ isEmpty(EIGEN_INCLUDEPATH) {
|
||||||
freebsd-g++: EIGEN_INCLUDEPATH = /usr/local/include/eigen3
|
freebsd-g++: EIGEN_INCLUDEPATH = /usr/local/include/eigen3
|
||||||
netbsd*: EIGEN_INCLUDEPATH = /usr/pkg/include/eigen3
|
netbsd*: EIGEN_INCLUDEPATH = /usr/pkg/include/eigen3
|
||||||
macx: EIGEN_INCLUDEPATH = /opt/local/include/eigen3
|
macx: EIGEN_INCLUDEPATH = /opt/local/include/eigen3
|
||||||
!exists($$EIGEN_INCLUDEPATH) {
|
|
||||||
linux*|hurd*|unix*: EIGEN_INCLUDEPATH = /usr/include/eigen2
|
|
||||||
freebsd-g++: EIGEN_INCLUDEPATH = /usr/local/include/eigen2
|
|
||||||
netbsd*: EIGEN_INCLUDEPATH = /usr/pkg/include/eigen2
|
|
||||||
macx: EIGEN_INCLUDEPATH = /opt/local/include/eigen2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
!exists($$EIGEN_INCLUDEPATH/Eigen/Core) {
|
|
||||||
EIGEN_CFLAGS = $$system("pkg-config --cflags eigen2")
|
|
||||||
EIGEN_INCLUDEPATH = $$replace(EIGEN_CFLAGS,"-I","")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
!exists($$EIGEN_INCLUDEPATH/Eigen/Core) {
|
!exists($$EIGEN_INCLUDEPATH/Eigen/Core) {
|
||||||
|
@ -72,7 +45,7 @@ isEmpty(EIGEN_INCLUDEPATH) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# EIGEN being under 'include/eigen[2-3]' needs special prepending
|
# EIGEN being under 'include/eigen3' needs special prepending
|
||||||
contains(QT_VERSION, ^5\\..*) {
|
contains(QT_VERSION, ^5\\..*) {
|
||||||
QMAKE_INCDIR = $$EIGEN_INCLUDEPATH $$QMAKE_INCDIR
|
QMAKE_INCDIR = $$EIGEN_INCLUDEPATH $$QMAKE_INCDIR
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Detect gettext, then use this priority list to determine
|
||||||
|
# which library to use:
|
||||||
|
#
|
||||||
|
# Priority
|
||||||
|
# 1. GETTEXT_INCLUDEPATH / GETTEXT_LIBPATH (qmake parameter, not checked it given on commandline)
|
||||||
|
# 2. OPENSCAD_LIBRARIES (environment variable)
|
||||||
|
# 3. system's standard include paths from pkg-config
|
||||||
|
|
||||||
|
gettext {
|
||||||
|
|
||||||
|
# read environment variables
|
||||||
|
OPENSCAD_LIBRARIES_DIR = $$(OPENSCAD_LIBRARIES)
|
||||||
|
GETTEXT_DIR = $$(GETTEXTDIR)
|
||||||
|
|
||||||
|
macx: {
|
||||||
|
isEmpty(GETTEXT_INCLUDEPATH) {
|
||||||
|
!isEmpty(OPENSCAD_LIBRARIES_DIR) {
|
||||||
|
GETTEXT_INCLUDEPATH = $$OPENSCAD_LIBRARIES_DIR/include
|
||||||
|
GETTEXT_LIBPATH = $$OPENSCAD_LIBRARIES_DIR/lib
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GETTEXT_CXXFLAGS=-I$$GETTEXT_INCLUDEPATH
|
||||||
|
GETTEXT_LIBS=-L$$GETTEXT_LIBPATH -lintl -liconv
|
||||||
|
}
|
||||||
|
|
||||||
|
QMAKE_CXXFLAGS += $$GETTEXT_CXXFLAGS
|
||||||
|
LIBS += $$GETTEXT_LIBS
|
||||||
|
}
|
7
glew.pri
7
glew.pri
|
@ -9,6 +9,9 @@ glew {
|
||||||
}
|
}
|
||||||
|
|
||||||
unix:LIBS += -lGLEW
|
unix:LIBS += -lGLEW
|
||||||
win32:LIBS += -lglew32s
|
CONFIG(mingw-cross-env): {
|
||||||
CONFIG(mingw-cross-env):DEFINES += GLEW_STATIC
|
DEFINES += GLEW_STATIC
|
||||||
|
} else {
|
||||||
|
win32:LIBS += -lglew32
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 101 KiB |
|
@ -0,0 +1,2 @@
|
||||||
|
# available languages
|
||||||
|
fr ru de cs
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,946 @@
|
||||||
|
# SOME DESCRIPTIVE TITLE.
|
||||||
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
|
#
|
||||||
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: OpenSCAD 2014.12.22\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2014-12-22 23:37+0100\n"
|
||||||
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
"Language: \n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
|
#: objects/ui_AboutDialog.h:51 src/AboutDialog.h:15
|
||||||
|
msgid "About OpenSCAD"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_FontListDialog.h:102
|
||||||
|
msgid "OpenSCAD Font List"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_FontListDialog.h:103 objects/ui_LibraryInfoDialog.h:77
|
||||||
|
msgid "&OK"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_FontListDialog.h:104
|
||||||
|
msgid "Copy to Clipboard"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_FontListDialog.h:105
|
||||||
|
msgid "Filter:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_FontListDialog.h:106
|
||||||
|
msgid ""
|
||||||
|
"<html><head/><body><p>This list shows the fonts currently registered with "
|
||||||
|
"OpenSCAD.</p><p>Example:</p><pre style=\" margin-top:12px; margin-"
|
||||||
|
"bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-"
|
||||||
|
"indent:0px;\"><span style=\" font-family:'Courier New,courier';\"> text(t = "
|
||||||
|
""OpenSCAD", font = "DejaVu Sans");</span></pre><pre "
|
||||||
|
"style=\" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-"
|
||||||
|
"right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-"
|
||||||
|
"family:'Courier New,courier';\"> text(t = "OpenSCAD", font = "
|
||||||
|
""Liberation Sans:style=Italic");</span></pre></body></html>"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_launchingscreen.h:276
|
||||||
|
msgid "Welcome to OpenSCAD"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_launchingscreen.h:277
|
||||||
|
msgid "New"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_launchingscreen.h:278
|
||||||
|
msgid "Open"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_launchingscreen.h:279
|
||||||
|
msgid "Help"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_launchingscreen.h:280
|
||||||
|
msgid "Recents"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_launchingscreen.h:281
|
||||||
|
msgid "Open Recent"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_launchingscreen.h:282 objects/ui_launchingscreen.h:284
|
||||||
|
#: objects/ui_MainWindow.h:855
|
||||||
|
msgid "Examples"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_launchingscreen.h:285
|
||||||
|
msgid "Open Example"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_launchingscreen.h:287
|
||||||
|
msgid ""
|
||||||
|
"<html><head/><body>\n"
|
||||||
|
"<p style=\"font-family: 'Open Sans', 'Droid Sans', 'sans-serif'; font-"
|
||||||
|
"weight: bold; padding-bottom: 0; margin-bottom: 0; font-size: 22pt;\"><span "
|
||||||
|
"style=\"color: green;\">Open</span>SCAD</p>\n"
|
||||||
|
"<p style=\"font-family: 'Open Sans', 'Droid Sans', 'sans-serif'; font-"
|
||||||
|
"weight: normal; font-size: 14pt; padding-top: 0; margin-top: 0; margin-left: "
|
||||||
|
"2em;\">The Programmers Solid 3D CAD Modeller</p>\n"
|
||||||
|
"</body></html>\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_launchingscreen.h:294
|
||||||
|
msgid "Don't show again"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_LibraryInfoDialog.h:75
|
||||||
|
msgid "Lib & Build Info"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_LibraryInfoDialog.h:76
|
||||||
|
msgid "OpenSCAD Detailed Library and Build Information"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:731
|
||||||
|
msgid "&New"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:732
|
||||||
|
msgid "Ctrl+N"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:733
|
||||||
|
msgid "&Open..."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:734
|
||||||
|
msgid "Ctrl+O"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:735
|
||||||
|
msgid "&Save"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:736
|
||||||
|
msgid "Ctrl+S"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:737
|
||||||
|
msgid "Save &As..."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:738
|
||||||
|
msgid "Ctrl+Shift+S"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:739
|
||||||
|
msgid "&Reload"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:740
|
||||||
|
msgid "Ctrl+R"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:741
|
||||||
|
msgid "&Quit"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:742
|
||||||
|
msgid "Ctrl+Q"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:743
|
||||||
|
msgid "&Undo"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:744
|
||||||
|
msgid "Ctrl+Z"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:745
|
||||||
|
msgid "&Redo"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:746
|
||||||
|
msgid "Ctrl+Shift+Z"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:747
|
||||||
|
msgid "Cu&t"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:748
|
||||||
|
msgid "Ctrl+X"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:749
|
||||||
|
msgid "&Copy"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:750
|
||||||
|
msgid "Ctrl+C"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:751
|
||||||
|
msgid "&Paste"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:752
|
||||||
|
msgid "Ctrl+V"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:753
|
||||||
|
msgid "&Indent"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:754
|
||||||
|
msgid "Ctrl+I"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:755
|
||||||
|
msgid "U&nindent"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:756
|
||||||
|
msgid "Ctrl+Shift+I"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:757
|
||||||
|
msgid "C&omment"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:758
|
||||||
|
msgid "Ctrl+D"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:759
|
||||||
|
msgid "Unco&mment"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:760
|
||||||
|
msgid "Ctrl+Shift+D"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:761
|
||||||
|
msgid "Paste viewport translation"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:762
|
||||||
|
msgid "Ctrl+T"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:763
|
||||||
|
msgid "Paste viewport rotation"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:764 objects/ui_MainWindow.h:842
|
||||||
|
msgid "Zoom In"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:765
|
||||||
|
msgid "Ctrl++"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:766 objects/ui_MainWindow.h:844
|
||||||
|
msgid "Zoom Out"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:767
|
||||||
|
msgid "Ctrl+-"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:768
|
||||||
|
msgid "Hide editor"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:769
|
||||||
|
msgid "&Reload and Preview"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:770
|
||||||
|
msgid "F4"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:771
|
||||||
|
msgid "&Preview"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:772
|
||||||
|
msgid "F5"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:773
|
||||||
|
msgid "&Render"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:774
|
||||||
|
msgid "F6"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:775
|
||||||
|
msgid "Check Validity"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:776
|
||||||
|
msgid "Display &AST..."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:777
|
||||||
|
msgid "Display CSG &Tree..."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:778
|
||||||
|
msgid "Display CSG &Products..."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:779
|
||||||
|
msgid "Export as &STL..."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:780
|
||||||
|
msgid "Export as &OFF..."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:781
|
||||||
|
msgid "Preview"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:782
|
||||||
|
msgid "F9"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:783
|
||||||
|
msgid "Surfaces"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:784
|
||||||
|
msgid "F10"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:785
|
||||||
|
msgid "Wireframe"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:786
|
||||||
|
msgid "F11"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:787
|
||||||
|
msgid "Thrown Together"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:788
|
||||||
|
msgid "F12"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:789
|
||||||
|
msgid "Show Edges"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:790
|
||||||
|
msgid "Ctrl+1"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:791
|
||||||
|
msgid "Show Axes"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:792
|
||||||
|
msgid "Ctrl+2"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:793
|
||||||
|
msgid "Show Crosshairs"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:794
|
||||||
|
msgid "Ctrl+3"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:795
|
||||||
|
msgid "Animate"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:796
|
||||||
|
msgid "Top"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:797
|
||||||
|
msgid "Ctrl+4"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:798
|
||||||
|
msgid "Bottom"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:799
|
||||||
|
msgid "Ctrl+5"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:800
|
||||||
|
msgid "Left"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:801
|
||||||
|
msgid "Ctrl+6"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:802
|
||||||
|
msgid "Right"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:803
|
||||||
|
msgid "Ctrl+7"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:804
|
||||||
|
msgid "Front"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:805
|
||||||
|
msgid "Ctrl+8"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:806
|
||||||
|
msgid "Back"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:807
|
||||||
|
msgid "Ctrl+9"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:808
|
||||||
|
msgid "Diagonal"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:809
|
||||||
|
msgid "Ctrl+0"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:810
|
||||||
|
msgid "Center"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:811
|
||||||
|
msgid "Perspective"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:812
|
||||||
|
msgid "Orthogonal"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:813
|
||||||
|
msgid "Hide console"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:814
|
||||||
|
msgid "About"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:815
|
||||||
|
msgid "Documentation"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:816
|
||||||
|
msgid "Clear Recent"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:817
|
||||||
|
msgid "Export as DXF..."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:818 objects/ui_OpenCSGWarningDialog.h:94
|
||||||
|
msgid "Close"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:819
|
||||||
|
msgid "Ctrl+W"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:820 objects/ui_Preferences.h:608
|
||||||
|
msgid "Preferences"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:821
|
||||||
|
msgid "Find..."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:822
|
||||||
|
msgid "Ctrl+F"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:823
|
||||||
|
msgid "Find and Replace..."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:824
|
||||||
|
msgid "Ctrl+Alt+F"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:825
|
||||||
|
msgid "Find Next"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:826
|
||||||
|
msgid "Ctrl+G"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:827
|
||||||
|
msgid "Find Previous"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:828
|
||||||
|
msgid "Ctrl+Shift+G"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:829
|
||||||
|
msgid "Use Selection for Find"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:830
|
||||||
|
msgid "Ctrl+E"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:831
|
||||||
|
msgid "Flush Caches"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:832
|
||||||
|
msgid "OpenSCAD Homepage"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:833
|
||||||
|
msgid "Automatic Reload and Preview"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:834
|
||||||
|
msgid "Export as Image..."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:835
|
||||||
|
msgid "Export as CSG..."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:836
|
||||||
|
msgid "Library info"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:837
|
||||||
|
msgid "Show Library Folder..."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:838
|
||||||
|
msgid "Reset View"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:839
|
||||||
|
msgid "Font List"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:840
|
||||||
|
msgid "Export as SVG..."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:841
|
||||||
|
msgid "Export as AMF..."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:843
|
||||||
|
msgid "Ctrl+]"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:845
|
||||||
|
msgid "Ctrl+["
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:846
|
||||||
|
msgid "View All"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:847
|
||||||
|
msgid "Convert Tabs to Spaces"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:848
|
||||||
|
msgid "Hide toolbars"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:849
|
||||||
|
msgid "Time:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:850
|
||||||
|
msgid "FPS:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:851
|
||||||
|
msgid "Steps:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:852
|
||||||
|
msgid "Dump Pictures"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:853
|
||||||
|
msgid "&File"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:854
|
||||||
|
msgid "Recent Files"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:856
|
||||||
|
msgid "Export"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:857
|
||||||
|
msgid "&Edit"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:858
|
||||||
|
msgid "&Design"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:859
|
||||||
|
msgid "&View"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:860
|
||||||
|
msgid "&Help"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:863
|
||||||
|
msgid "Find"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:864 objects/ui_MainWindow.h:871
|
||||||
|
msgid "Replace"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:866
|
||||||
|
msgid "Search string"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:867
|
||||||
|
msgid "<"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:868
|
||||||
|
msgid ">"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:869
|
||||||
|
msgid "Done"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:870
|
||||||
|
msgid "Replacement string"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_MainWindow.h:872
|
||||||
|
msgid "All"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_OpenCSGWarningDialog.h:86
|
||||||
|
msgid "OpenGL Warning"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_OpenCSGWarningDialog.h:87
|
||||||
|
msgid ""
|
||||||
|
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/"
|
||||||
|
"REC-html40/strict.dtd\">\n"
|
||||||
|
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css"
|
||||||
|
"\">\n"
|
||||||
|
"p, li { white-space: pre-wrap; }\n"
|
||||||
|
"</style></head><body style=\" font-family:'Lucida Grande'; font-size:13pt; "
|
||||||
|
"font-weight:400; font-style:normal;\">\n"
|
||||||
|
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; "
|
||||||
|
"margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"></"
|
||||||
|
"p></body></html>"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_OpenCSGWarningDialog.h:92
|
||||||
|
msgid "Enable OpenCSG"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_OpenCSGWarningDialog.h:93
|
||||||
|
msgid "Show this message again"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:609
|
||||||
|
msgid "3D View"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:610 src/UIUtils.cc:85
|
||||||
|
msgid "Advanced"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:611 src/mainwin.cc:2315
|
||||||
|
msgid "Editor"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:612
|
||||||
|
msgid "Update"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:613 objects/ui_Preferences.h:633
|
||||||
|
msgid "Features"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:615
|
||||||
|
msgid "Enable/Disable experimental features"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:617
|
||||||
|
msgid "Color scheme:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:618
|
||||||
|
msgid "Editor Type"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:621
|
||||||
|
msgid "Simple Editor"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:622
|
||||||
|
msgid "QScintilla Editor"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:624
|
||||||
|
msgid "(requires restart)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:625
|
||||||
|
msgid "Font"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:626
|
||||||
|
msgid "Color syntax highlighting"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:627
|
||||||
|
msgid "Use Ctrl/Cmd-Mouse-wheel to zoom text"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:629
|
||||||
|
msgid "Automatically check for updates"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:630
|
||||||
|
msgid "Include development snapshots"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:631
|
||||||
|
msgid "Check Now"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:632
|
||||||
|
msgid "Last checked: "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:634
|
||||||
|
msgid "OpenCSG"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:635
|
||||||
|
msgid "Show capability warning"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:636
|
||||||
|
msgid "Enable for OpenGL 1.x"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:637
|
||||||
|
msgid "Turn off rendering at "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:638
|
||||||
|
msgid "elements"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:639
|
||||||
|
msgid "Force Goldfeather"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:640
|
||||||
|
msgid "CGAL Cache size"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:641 objects/ui_Preferences.h:643
|
||||||
|
msgid "bytes"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:642
|
||||||
|
msgid "PolySet Cache size"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:644
|
||||||
|
msgid "Allow to open multiple documents"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:645
|
||||||
|
msgid "Enable docking of Editor and Console in different places"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:646
|
||||||
|
msgid "Enable undocking of Editor and Console to separate windows"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:647
|
||||||
|
msgid "Show Welcome Screen"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:648
|
||||||
|
msgid "Enable user interface localization (requires restart of OpenSCAD)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_Preferences.h:649
|
||||||
|
msgid "toolBar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_ProgressWidget.h:72
|
||||||
|
msgid "Form"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: objects/ui_ProgressWidget.h:73
|
||||||
|
msgid "%v / %m"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/mainwin.cc:768 src/mainwin.cc:1300
|
||||||
|
msgid "Untitled.scad"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/mainwin.cc:1299
|
||||||
|
msgid "Save File"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/mainwin.cc:1301
|
||||||
|
msgid "OpenSCAD Designs (*.scad)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/mainwin.cc:1311
|
||||||
|
msgid ""
|
||||||
|
"%1 already exists.\n"
|
||||||
|
"Do you want to replace it?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/mainwin.cc:1630
|
||||||
|
msgid "Application"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/mainwin.cc:1631
|
||||||
|
msgid ""
|
||||||
|
"The document has been modified.\n"
|
||||||
|
"Do you really want to reload the file?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/mainwin.cc:1942 src/mainwin.cc:1999
|
||||||
|
msgid "Export %1 File"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/mainwin.cc:1943 src/mainwin.cc:2003
|
||||||
|
msgid "%1 Files (*%2)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/mainwin.cc:1944
|
||||||
|
msgid "Untitled"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/mainwin.cc:2001
|
||||||
|
msgid "Untitled%1"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/mainwin.cc:2052
|
||||||
|
msgid "Export CSG File"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/mainwin.cc:2053
|
||||||
|
msgid "Untitled.csg"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/mainwin.cc:2054
|
||||||
|
msgid "CSG Files (*.csg)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/mainwin.cc:2080
|
||||||
|
msgid "Export Image"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/mainwin.cc:2080
|
||||||
|
msgid "PNG Files (*.png)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/mainwin.cc:2320
|
||||||
|
msgid "Console"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/mainwin.cc:2447
|
||||||
|
msgid "The document has been modified."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/mainwin.cc:2448
|
||||||
|
msgid "Do you want to save your changes?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/QGLView.cc:114
|
||||||
|
msgid ""
|
||||||
|
"\n"
|
||||||
|
"Using QGLWidget\n"
|
||||||
|
"\n"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/QGLView.cc:131
|
||||||
|
msgid ""
|
||||||
|
"Warning: You may experience OpenCSG rendering errors.\n"
|
||||||
|
"\n"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/QGLView.cc:134
|
||||||
|
msgid ""
|
||||||
|
"Warning: Missing OpenGL capabilities for OpenCSG - OpenCSG has been "
|
||||||
|
"disabled.\n"
|
||||||
|
"\n"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/QGLView.cc:137
|
||||||
|
msgid ""
|
||||||
|
"It is highly recommended to use OpenSCAD on a system with OpenGL 2.0 or "
|
||||||
|
"later.\n"
|
||||||
|
"Your renderer information is as follows:\n"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/QGLView.cc:141
|
||||||
|
#, c-format
|
||||||
|
msgid ""
|
||||||
|
"GLEW version %s\n"
|
||||||
|
"%s (%s)\n"
|
||||||
|
"OpenGL version %s\n"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/QGLView.cc:171
|
||||||
|
#, c-format
|
||||||
|
msgid ""
|
||||||
|
"Viewport: translate = [ %.2f %.2f %.2f ], rotate = [ %.2f %.2f %.2f ], "
|
||||||
|
"distance = %.2f"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/UIUtils.cc:85
|
||||||
|
msgid "Basics"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/UIUtils.cc:85
|
||||||
|
msgid "Shapes"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/UIUtils.cc:85
|
||||||
|
msgid "Extrusion"
|
||||||
|
msgstr ""
|
File diff suppressed because it is too large
Load Diff
88
openscad.pro
88
openscad.pro
|
@ -8,7 +8,15 @@
|
||||||
# OPENCSGDIR
|
# OPENCSGDIR
|
||||||
# OPENSCAD_LIBRARIES
|
# OPENSCAD_LIBRARIES
|
||||||
#
|
#
|
||||||
# Please see the 'Building' sections of the OpenSCAD user manual
|
# qmake Variables to define the installation:
|
||||||
|
#
|
||||||
|
# PREFIX defines the base installation folder
|
||||||
|
#
|
||||||
|
# SUFFIX defines an optional suffix for the binary and the
|
||||||
|
# resource folder. E.g. using SUFFIX=-nightly will name the
|
||||||
|
# resulting binary openscad-nightly.
|
||||||
|
#
|
||||||
|
# Please see the 'Building' sections of the OpenSCAD user manual
|
||||||
# for updated tips & workarounds.
|
# for updated tips & workarounds.
|
||||||
#
|
#
|
||||||
# http://en.wikibooks.org/wiki/OpenSCAD_User_Manual
|
# http://en.wikibooks.org/wiki/OpenSCAD_User_Manual
|
||||||
|
@ -74,8 +82,10 @@ macx {
|
||||||
TARGET = OpenSCAD
|
TARGET = OpenSCAD
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
TARGET = openscad
|
TARGET = openscad$${SUFFIX}
|
||||||
}
|
}
|
||||||
|
FULLNAME = openscad$${SUFFIX}
|
||||||
|
!isEmpty(SUFFIX): DEFINES += INSTALL_SUFFIX="\"\\\"$${SUFFIX}\\\"\""
|
||||||
|
|
||||||
macx {
|
macx {
|
||||||
ICON = icons/OpenSCAD.icns
|
ICON = icons/OpenSCAD.icns
|
||||||
|
@ -89,11 +99,18 @@ macx {
|
||||||
|
|
||||||
win* {
|
win* {
|
||||||
RC_FILE = openscad_win32.rc
|
RC_FILE = openscad_win32.rc
|
||||||
QTPLUGIN += qtaccessiblewidgets
|
QMAKE_CXXFLAGS += -DNOGDI
|
||||||
|
}
|
||||||
|
|
||||||
|
mingw* {
|
||||||
|
# needed to prevent compilation error on MSYS2:
|
||||||
|
# as.exe: objects/cgalutils.o: too many sections (76541)
|
||||||
|
# using -Wa,-mbig-obj did not help
|
||||||
|
debug: QMAKE_CXXFLAGS += -O1
|
||||||
}
|
}
|
||||||
|
|
||||||
CONFIG += qt
|
CONFIG += qt
|
||||||
QT += opengl
|
QT += opengl concurrent
|
||||||
|
|
||||||
# see http://fedoraproject.org/wiki/UnderstandingDSOLinkChange
|
# see http://fedoraproject.org/wiki/UnderstandingDSOLinkChange
|
||||||
# and https://github.com/openscad/openscad/pull/119
|
# and https://github.com/openscad/openscad/pull/119
|
||||||
|
@ -140,6 +157,8 @@ netbsd* {
|
||||||
QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-parameter
|
QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-parameter
|
||||||
QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-variable
|
QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-variable
|
||||||
QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-function
|
QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-function
|
||||||
|
# gettext
|
||||||
|
QMAKE_CXXFLAGS_WARN_ON += -Wno-format-security
|
||||||
# might want to actually turn this on once in a while
|
# might want to actually turn this on once in a while
|
||||||
QMAKE_CXXFLAGS_WARN_ON += -Wno-sign-compare
|
QMAKE_CXXFLAGS_WARN_ON += -Wno-sign-compare
|
||||||
}
|
}
|
||||||
|
@ -160,6 +179,7 @@ CONFIG += glib-2.0
|
||||||
CONFIG += harfbuzz
|
CONFIG += harfbuzz
|
||||||
CONFIG += freetype
|
CONFIG += freetype
|
||||||
CONFIG += fontconfig
|
CONFIG += fontconfig
|
||||||
|
CONFIG += gettext
|
||||||
|
|
||||||
#Uncomment the following line to enable the QScintilla editor
|
#Uncomment the following line to enable the QScintilla editor
|
||||||
CONFIG += scintilla
|
CONFIG += scintilla
|
||||||
|
@ -190,7 +210,12 @@ win* {
|
||||||
|
|
||||||
RESOURCES = openscad.qrc
|
RESOURCES = openscad.qrc
|
||||||
|
|
||||||
FORMS += src/MainWindow.ui \
|
# Qt5 removed access to the QMAKE_UIC variable, the following
|
||||||
|
# way works for both Qt4 and Qt5
|
||||||
|
load(uic)
|
||||||
|
uic.commands += -tr _
|
||||||
|
|
||||||
|
FORMS += src/MainWindow.ui \
|
||||||
src/Preferences.ui \
|
src/Preferences.ui \
|
||||||
src/OpenCSGWarningDialog.ui \
|
src/OpenCSGWarningDialog.ui \
|
||||||
src/AboutDialog.ui \
|
src/AboutDialog.ui \
|
||||||
|
@ -204,6 +229,7 @@ HEADERS += src/typedefs.h \
|
||||||
src/ProgressWidget.h \
|
src/ProgressWidget.h \
|
||||||
src/parsersettings.h \
|
src/parsersettings.h \
|
||||||
src/renderer.h \
|
src/renderer.h \
|
||||||
|
src/settings.h \
|
||||||
src/rendersettings.h \
|
src/rendersettings.h \
|
||||||
src/colormap.h \
|
src/colormap.h \
|
||||||
src/ThrownTogetherRenderer.h \
|
src/ThrownTogetherRenderer.h \
|
||||||
|
@ -216,6 +242,7 @@ HEADERS += src/typedefs.h \
|
||||||
src/OpenCSGWarningDialog.h \
|
src/OpenCSGWarningDialog.h \
|
||||||
src/AboutDialog.h \
|
src/AboutDialog.h \
|
||||||
src/FontListDialog.h \
|
src/FontListDialog.h \
|
||||||
|
src/FontListTableView.h \
|
||||||
src/builtin.h \
|
src/builtin.h \
|
||||||
src/calc.h \
|
src/calc.h \
|
||||||
src/context.h \
|
src/context.h \
|
||||||
|
@ -227,7 +254,9 @@ HEADERS += src/typedefs.h \
|
||||||
src/dxfdim.h \
|
src/dxfdim.h \
|
||||||
src/export.h \
|
src/export.h \
|
||||||
src/expression.h \
|
src/expression.h \
|
||||||
|
src/stackcheck.h \
|
||||||
src/function.h \
|
src/function.h \
|
||||||
|
src/exceptions.h \
|
||||||
src/grid.h \
|
src/grid.h \
|
||||||
src/highlighter.h \
|
src/highlighter.h \
|
||||||
src/localscope.h \
|
src/localscope.h \
|
||||||
|
@ -303,6 +332,7 @@ SOURCES += src/version_check.cc \
|
||||||
src/handle_dep.cc \
|
src/handle_dep.cc \
|
||||||
src/value.cc \
|
src/value.cc \
|
||||||
src/expr.cc \
|
src/expr.cc \
|
||||||
|
src/stackcheck.cc \
|
||||||
src/func.cc \
|
src/func.cc \
|
||||||
src/localscope.cc \
|
src/localscope.cc \
|
||||||
src/module.cc \
|
src/module.cc \
|
||||||
|
@ -352,6 +382,7 @@ SOURCES += src/version_check.cc \
|
||||||
src/FreetypeRenderer.cc \
|
src/FreetypeRenderer.cc \
|
||||||
src/FontCache.cc \
|
src/FontCache.cc \
|
||||||
\
|
\
|
||||||
|
src/settings.cc \
|
||||||
src/rendersettings.cc \
|
src/rendersettings.cc \
|
||||||
src/highlighter.cc \
|
src/highlighter.cc \
|
||||||
src/Preferences.cc \
|
src/Preferences.cc \
|
||||||
|
@ -382,6 +413,7 @@ SOURCES += src/version_check.cc \
|
||||||
src/UIUtils.cc \
|
src/UIUtils.cc \
|
||||||
src/Dock.cc \
|
src/Dock.cc \
|
||||||
src/FontListDialog.cc \
|
src/FontListDialog.cc \
|
||||||
|
src/FontListTableView.cc \
|
||||||
src/launchingscreen.cc \
|
src/launchingscreen.cc \
|
||||||
src/legacyeditor.cc \
|
src/legacyeditor.cc \
|
||||||
src/LibraryInfoDialog.cc
|
src/LibraryInfoDialog.cc
|
||||||
|
@ -422,6 +454,8 @@ HEADERS += src/cgal.h \
|
||||||
|
|
||||||
SOURCES += src/cgalutils.cc \
|
SOURCES += src/cgalutils.cc \
|
||||||
src/cgalutils-tess.cc \
|
src/cgalutils-tess.cc \
|
||||||
|
src/cgalutils-polyhedron.cc \
|
||||||
|
src/cgalutils-tess-old.cc \
|
||||||
src/CGALCache.cc \
|
src/CGALCache.cc \
|
||||||
src/CGALRenderer.cc \
|
src/CGALRenderer.cc \
|
||||||
src/CGAL_Nef_polyhedron.cc \
|
src/CGAL_Nef_polyhedron.cc \
|
||||||
|
@ -450,42 +484,60 @@ isEmpty(PREFIX):PREFIX = /usr/local
|
||||||
target.path = $$PREFIX/bin/
|
target.path = $$PREFIX/bin/
|
||||||
INSTALLS += target
|
INSTALLS += target
|
||||||
|
|
||||||
examples.path = $$PREFIX/share/openscad/examples/
|
# Run translation update scripts as last step after linking the target
|
||||||
|
QMAKE_POST_LINK += $$PWD/scripts/translation-make.sh
|
||||||
|
|
||||||
|
# Create install targets for the languages defined in LINGUAS
|
||||||
|
LINGUAS = $$cat(locale/LINGUAS)
|
||||||
|
LOCALE_PREFIX = "$$PREFIX/share/$${FULLNAME}/locale"
|
||||||
|
for(language, LINGUAS) {
|
||||||
|
catalogdir = locale/$$language/LC_MESSAGES
|
||||||
|
exists(locale/$${language}.po) {
|
||||||
|
# Use .extra and copy manually as the source path might not exist,
|
||||||
|
# e.g. on a clean checkout. In that case qmake would not create
|
||||||
|
# the needed targets in the generated Makefile.
|
||||||
|
translation_path = translation_$${language}.path
|
||||||
|
translation_extra = translation_$${language}.extra
|
||||||
|
translation_depends = translation_$${language}.depends
|
||||||
|
$$translation_path = $$LOCALE_PREFIX/$$language/LC_MESSAGES/
|
||||||
|
$$translation_extra = cp -f $${catalogdir}/openscad.mo \"\$(INSTALL_ROOT)$$LOCALE_PREFIX/$$language/LC_MESSAGES/openscad.mo\"
|
||||||
|
$$translation_depends = locale/$${language}.po
|
||||||
|
INSTALLS += translation_$$language
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
examples.path = "$$PREFIX/share/$${FULLNAME}/examples/"
|
||||||
examples.files = examples/*
|
examples.files = examples/*
|
||||||
INSTALLS += examples
|
INSTALLS += examples
|
||||||
|
|
||||||
libraries.path = $$PREFIX/share/openscad/libraries/
|
libraries.path = "$$PREFIX/share/$${FULLNAME}/libraries/"
|
||||||
libraries.files = libraries/*
|
libraries.files = libraries/*
|
||||||
INSTALLS += libraries
|
INSTALLS += libraries
|
||||||
|
|
||||||
fonts.path = $$PREFIX/share/openscad/fonts/
|
fonts.path = "$$PREFIX/share/$${FULLNAME}/fonts/"
|
||||||
fonts.files = fonts/*
|
fonts.files = fonts/*
|
||||||
INSTALLS += fonts
|
INSTALLS += fonts
|
||||||
|
|
||||||
colorschemes.path = $$PREFIX/share/openscad/color-schemes/
|
colorschemes.path = "$$PREFIX/share/$${FULLNAME}/color-schemes/"
|
||||||
colorschemes.files = color-schemes/*
|
colorschemes.files = color-schemes/*
|
||||||
INSTALLS += colorschemes
|
INSTALLS += colorschemes
|
||||||
|
|
||||||
applications.path = $$PREFIX/share/applications
|
applications.path = $$PREFIX/share/applications
|
||||||
applications.files = icons/openscad.desktop
|
applications.extra = cat icons/openscad.desktop | sed -e \"'s/^Icon=openscad/Icon=$${FULLNAME}/; s/^Exec=openscad/Exec=$${FULLNAME}/'\" > \"\$(INSTALL_ROOT)$${applications.path}/$${FULLNAME}.desktop\"
|
||||||
INSTALLS += applications
|
INSTALLS += applications
|
||||||
|
|
||||||
mimexml.path = $$PREFIX/share/mime/packages
|
mimexml.path = $$PREFIX/share/mime/packages
|
||||||
mimexml.files = icons/openscad.xml
|
mimexml.extra = cp -f icons/openscad.xml \"\$(INSTALL_ROOT)$${mimexml.path}/$${FULLNAME}.xml\"
|
||||||
INSTALLS += mimexml
|
INSTALLS += mimexml
|
||||||
|
|
||||||
appdata.path = $$PREFIX/share/appdata
|
appdata.path = $$PREFIX/share/appdata
|
||||||
appdata.files = openscad.appdata.xml
|
appdata.extra = cp -f openscad.appdata.xml \"\$(INSTALL_ROOT)$${appdata.path}/$${FULLNAME}.appdata.xml\"
|
||||||
INSTALLS += appdata
|
INSTALLS += appdata
|
||||||
|
|
||||||
icons.path = $$PREFIX/share/pixmaps
|
icons.path = $$PREFIX/share/pixmaps
|
||||||
icons.files = icons/openscad.png
|
icons.extra = cp -f icons/openscad.png \"\$(INSTALL_ROOT)$${icons.path}/$${FULLNAME}.png\"
|
||||||
INSTALLS += icons
|
INSTALLS += icons
|
||||||
|
|
||||||
man.path = $$PREFIX/share/man/man1
|
man.path = $$PREFIX/share/man/man1
|
||||||
man.files = doc/openscad.1
|
man.extra = cp -f doc/openscad.1 \"\$(INSTALL_ROOT)$${man.path}/$${FULLNAME}.1\"
|
||||||
INSTALLS += man
|
INSTALLS += man
|
||||||
|
|
||||||
CONFIG(winconsole) {
|
|
||||||
include(winconsole.pri)
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,201 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE QtCreatorProject>
|
|
||||||
<!-- Written by QtCreator 3.0.1, 2014-08-11T22:59:13. -->
|
|
||||||
<qtcreator>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
|
||||||
<value type="int">0</value>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
|
||||||
<valuemap type="QVariantMap">
|
|
||||||
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
|
|
||||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
|
||||||
<value type="QString" key="language">Cpp</value>
|
|
||||||
<valuemap type="QVariantMap" key="value">
|
|
||||||
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
|
|
||||||
</valuemap>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
|
|
||||||
<value type="QString" key="language">QmlJS</value>
|
|
||||||
<valuemap type="QVariantMap" key="value">
|
|
||||||
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
|
|
||||||
</valuemap>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
|
|
||||||
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
|
||||||
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
|
||||||
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
|
|
||||||
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
|
||||||
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
|
||||||
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
|
||||||
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
|
|
||||||
</valuemap>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
|
||||||
<valuemap type="QVariantMap"/>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.Target.0</variable>
|
|
||||||
<valuemap type="QVariantMap">
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Qt 4.8.6 (qt4)</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Qt 4.8.6 (qt4)</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{90222843-28c9-4a66-ac82-99bd31ae7263}</value>
|
|
||||||
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
|
||||||
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
|
||||||
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
|
||||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory"></value>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
|
|
||||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
|
|
||||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto">false</value>
|
|
||||||
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments">CONFIG+=experimental</value>
|
|
||||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
|
||||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
|
|
||||||
<value type="QString">-w</value>
|
|
||||||
<value type="QString">-r</value>
|
|
||||||
</valuelist>
|
|
||||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
|
|
||||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
|
|
||||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
|
||||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
|
|
||||||
<value type="QString">-w</value>
|
|
||||||
<value type="QString">-r</value>
|
|
||||||
</valuelist>
|
|
||||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
|
|
||||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
|
|
||||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
|
||||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Release</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
|
|
||||||
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
|
|
||||||
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
|
||||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy locally</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
|
||||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
|
|
||||||
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
|
|
||||||
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
|
|
||||||
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
|
|
||||||
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
|
|
||||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
|
|
||||||
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
|
|
||||||
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
|
|
||||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
|
|
||||||
<value type="int">0</value>
|
|
||||||
<value type="int">1</value>
|
|
||||||
<value type="int">2</value>
|
|
||||||
<value type="int">3</value>
|
|
||||||
<value type="int">4</value>
|
|
||||||
<value type="int">5</value>
|
|
||||||
<value type="int">6</value>
|
|
||||||
<value type="int">7</value>
|
|
||||||
<value type="int">8</value>
|
|
||||||
<value type="int">9</value>
|
|
||||||
<value type="int">10</value>
|
|
||||||
<value type="int">11</value>
|
|
||||||
<value type="int">12</value>
|
|
||||||
<value type="int">13</value>
|
|
||||||
<value type="int">14</value>
|
|
||||||
</valuelist>
|
|
||||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
|
||||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">openscad</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:/home/shaina/openscad/openscad.pro</value>
|
|
||||||
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.CommandLineArguments"></value>
|
|
||||||
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.ProFile">openscad.pro</value>
|
|
||||||
<value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseDyldImageSuffix">false</value>
|
|
||||||
<value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseTerminal">false</value>
|
|
||||||
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory"></value>
|
|
||||||
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseCppDebugger">true</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">false</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
|
||||||
</valuemap>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.TargetCount</variable>
|
|
||||||
<value type="int">1</value>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.Updater.EnvironmentId</variable>
|
|
||||||
<value type="QByteArray">{56f57d1a-fe9b-42b2-a96b-3ac76cf7565f}</value>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
|
|
||||||
<value type="int">15</value>
|
|
||||||
</data>
|
|
||||||
</qtcreator>
|
|
|
@ -10,9 +10,33 @@ INCLUDEPATH += $$[QT_INSTALL_HEADERS]
|
||||||
|
|
||||||
LIBS += -L$$[QT_INSTALL_LIBS]
|
LIBS += -L$$[QT_INSTALL_LIBS]
|
||||||
|
|
||||||
greaterThan(QT_MAJOR_VERSION, 4) {
|
CONFIG(debug, debug|release) {
|
||||||
win32|macx:LIBS += -lqscintilla2
|
mac: {
|
||||||
else:LIBS += -lqt5scintilla2
|
#LIBS += -lqscintilla2_debug
|
||||||
|
LIBS += -lqscintilla2
|
||||||
|
} else {
|
||||||
|
win32: {
|
||||||
|
LIBS += -lqscintilla2d
|
||||||
|
} else {
|
||||||
|
greaterThan(QT_MAJOR_VERSION, 4) {
|
||||||
|
LIBS += -lqt5scintilla2
|
||||||
|
} else {
|
||||||
|
LIBS += -lqscintilla2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
LIBS += -lqscintilla2
|
mac: {
|
||||||
|
LIBS += -lqscintilla2
|
||||||
|
} else {
|
||||||
|
win32: {
|
||||||
|
LIBS += -lqscintilla2
|
||||||
|
} else {
|
||||||
|
greaterThan(QT_MAJOR_VERSION, 4) {
|
||||||
|
LIBS += -lqt5scintilla2
|
||||||
|
} else {
|
||||||
|
LIBS += -lqscintilla2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Generate list of files for translation. The output is saved to po/POTFILES
|
||||||
|
# which is needed for the xgettext call.
|
||||||
|
|
||||||
|
for ui in src/*.ui
|
||||||
|
do
|
||||||
|
UI="${ui#src/}"
|
||||||
|
UI="${UI%.ui}"
|
||||||
|
for d in mingw64 mingw32 .
|
||||||
|
do
|
||||||
|
if [ -f "$d/objects/ui_$UI.h" ]
|
||||||
|
then
|
||||||
|
echo "$d/objects/ui_$UI.h"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
for src in src/*.h src/*.cc
|
||||||
|
do
|
||||||
|
echo $src
|
||||||
|
done
|
|
@ -13,6 +13,7 @@ File openscad.com
|
||||||
File /r /x mingw-cross-env examples
|
File /r /x mingw-cross-env examples
|
||||||
File /r /x mingw-cross-env libraries
|
File /r /x mingw-cross-env libraries
|
||||||
File /r /x mingw-cross-env fonts
|
File /r /x mingw-cross-env fonts
|
||||||
|
File /r /x mingw-cross-env locale
|
||||||
File /r /x mingw-cross-env color-schemes
|
File /r /x mingw-cross-env color-schemes
|
||||||
${registerExtension} "$INSTDIR\openscad.exe" ".scad" "OpenSCAD_File"
|
${registerExtension} "$INSTDIR\openscad.exe" ".scad" "OpenSCAD_File"
|
||||||
CreateShortCut $SMPROGRAMS\OpenSCAD.lnk $INSTDIR\openscad.exe
|
CreateShortCut $SMPROGRAMS\OpenSCAD.lnk $INSTDIR\openscad.exe
|
||||||
|
@ -31,6 +32,7 @@ RMDir /r $INSTDIR\fonts
|
||||||
RMDir /r $INSTDIR\color-schemes
|
RMDir /r $INSTDIR\color-schemes
|
||||||
RMDir /r $INSTDIR\examples
|
RMDir /r $INSTDIR\examples
|
||||||
RMDir /r $INSTDIR\libraries\mcad
|
RMDir /r $INSTDIR\libraries\mcad
|
||||||
|
RMDir /r $INSTDIR\locale
|
||||||
Delete $INSTDIR\libraries\boxes.scad
|
Delete $INSTDIR\libraries\boxes.scad
|
||||||
Delete $INSTDIR\libraries\shapes.scad
|
Delete $INSTDIR\libraries\shapes.scad
|
||||||
RMDir $INSTDIR\libraries
|
RMDir $INSTDIR\libraries
|
||||||
|
|
|
@ -325,10 +325,10 @@ build_boost()
|
||||||
fi
|
fi
|
||||||
if $USING_LLVM; then
|
if $USING_LLVM; then
|
||||||
BOOST_TOOLSET="toolset=darwin-llvm"
|
BOOST_TOOLSET="toolset=darwin-llvm"
|
||||||
echo "using darwin : llvm : llvm-g++ ;" >> tools/build/v2/user-config.jam
|
echo "using darwin : llvm : llvm-g++ ;" >> tools/build/user-config.jam
|
||||||
elif $USING_CLANG; then
|
elif $USING_CLANG; then
|
||||||
BOOST_TOOLSET="toolset=clang"
|
BOOST_TOOLSET="toolset=clang"
|
||||||
echo "using clang ;" >> tools/build/v2/user-config.jam
|
echo "using clang ;" >> tools/build/user-config.jam
|
||||||
fi
|
fi
|
||||||
./b2 -j"$NUMCPU" -d+2 $BOOST_TOOLSET cflags="-mmacosx-version-min=$MAC_OSX_VERSION_MIN -arch x86_64 $BOOST_EXTRA_FLAGS" linkflags="-mmacosx-version-min=$MAC_OSX_VERSION_MIN -arch x86_64 $BOOST_EXTRA_FLAGS -headerpad_max_install_names" install
|
./b2 -j"$NUMCPU" -d+2 $BOOST_TOOLSET cflags="-mmacosx-version-min=$MAC_OSX_VERSION_MIN -arch x86_64 $BOOST_EXTRA_FLAGS" linkflags="-mmacosx-version-min=$MAC_OSX_VERSION_MIN -arch x86_64 $BOOST_EXTRA_FLAGS -headerpad_max_install_names" install
|
||||||
install_name_tool -id $DEPLOYDIR/lib/libboost_thread.dylib $DEPLOYDIR/lib/libboost_thread.dylib
|
install_name_tool -id $DEPLOYDIR/lib/libboost_thread.dylib $DEPLOYDIR/lib/libboost_thread.dylib
|
||||||
|
@ -356,8 +356,9 @@ build_cgal()
|
||||||
cd $BASEDIR/src
|
cd $BASEDIR/src
|
||||||
rm -rf CGAL-$version
|
rm -rf CGAL-$version
|
||||||
if [ ! -f CGAL-$version.tar.gz ]; then
|
if [ ! -f CGAL-$version.tar.gz ]; then
|
||||||
# 4.5
|
# 4.5.1
|
||||||
curl -O https://gforge.inria.fr/frs/download.php/file/34149/CGAL-$version.tar.gz
|
curl -O https://gforge.inria.fr/frs/download.php/file/34400/CGAL-$version.tar.gz
|
||||||
|
# 4.5 curl -O https://gforge.inria.fr/frs/download.php/file/34149/CGAL-$version.tar.gz
|
||||||
# 4.4 curl -O https://gforge.inria.fr/frs/download.php/file/33525/CGAL-$version.tar.gz
|
# 4.4 curl -O https://gforge.inria.fr/frs/download.php/file/33525/CGAL-$version.tar.gz
|
||||||
# 4.3 curl -O https://gforge.inria.fr/frs/download.php/32994/CGAL-$version.tar.gz
|
# 4.3 curl -O https://gforge.inria.fr/frs/download.php/32994/CGAL-$version.tar.gz
|
||||||
# 4.2 curl -O https://gforge.inria.fr/frs/download.php/32359/CGAL-$version.tar.gz
|
# 4.2 curl -O https://gforge.inria.fr/frs/download.php/32359/CGAL-$version.tar.gz
|
||||||
|
@ -450,6 +451,8 @@ build_eigen()
|
||||||
elif [ $version = "3.1.4" ]; then EIGENDIR=eigen-eigen-36bf2ceaf8f5;
|
elif [ $version = "3.1.4" ]; then EIGENDIR=eigen-eigen-36bf2ceaf8f5;
|
||||||
elif [ $version = "3.2.0" ]; then EIGENDIR=eigen-eigen-ffa86ffb5570;
|
elif [ $version = "3.2.0" ]; then EIGENDIR=eigen-eigen-ffa86ffb5570;
|
||||||
elif [ $version = "3.2.1" ]; then EIGENDIR=eigen-eigen-6b38706d90a9;
|
elif [ $version = "3.2.1" ]; then EIGENDIR=eigen-eigen-6b38706d90a9;
|
||||||
|
elif [ $version = "3.2.2" ]; then EIGENDIR=eigen-eigen-1306d75b4a21;
|
||||||
|
elif [ $version = "3.2.3" ]; then EIGENDIR=eigen-eigen-36fd1ba04c12;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $EIGENDIR = "none" ]; then
|
if [ $EIGENDIR = "none" ]; then
|
||||||
|
@ -515,7 +518,7 @@ build_freetype()
|
||||||
cd "$BASEDIR"/src
|
cd "$BASEDIR"/src
|
||||||
rm -rf "freetype-$version"
|
rm -rf "freetype-$version"
|
||||||
if [ ! -f "freetype-$version.tar.gz" ]; then
|
if [ ! -f "freetype-$version.tar.gz" ]; then
|
||||||
curl --insecure -LO "http://download.savannah.gnu.org/releases/freetype/freetype-$version.tar.gz"
|
curl --insecure -LO "http://downloads.sourceforge.net/project/freetype/freetype2/$version/freetype-$version.tar.gz"
|
||||||
fi
|
fi
|
||||||
tar xzf "freetype-$version.tar.gz"
|
tar xzf "freetype-$version.tar.gz"
|
||||||
cd "freetype-$version"
|
cd "freetype-$version"
|
||||||
|
@ -541,7 +544,7 @@ build_libxml2()
|
||||||
fi
|
fi
|
||||||
tar xzf "libxml2-$version.tar.gz"
|
tar xzf "libxml2-$version.tar.gz"
|
||||||
cd "libxml2-$version"
|
cd "libxml2-$version"
|
||||||
./configure --prefix="$DEPLOYDIR" --without-ftp --without-http --without-python CFLAGS=-mmacosx-version-min=$MAC_OSX_VERSION_MIN LDFLAGS=-mmacosx-version-min=$MAC_OSX_VERSION_MIN
|
./configure --prefix="$DEPLOYDIR" --with-zlib=/usr -without-lzma --without-ftp --without-http --without-python CFLAGS=-mmacosx-version-min=$MAC_OSX_VERSION_MIN LDFLAGS=-mmacosx-version-min=$MAC_OSX_VERSION_MIN
|
||||||
make -j$NUMCPU
|
make -j$NUMCPU
|
||||||
make install
|
make install
|
||||||
}
|
}
|
||||||
|
@ -655,7 +658,7 @@ build_ragel()
|
||||||
cd "$BASEDIR"/src
|
cd "$BASEDIR"/src
|
||||||
rm -rf "ragel-$version"
|
rm -rf "ragel-$version"
|
||||||
if [ ! -f "ragel-$version.tar.gz" ]; then
|
if [ ! -f "ragel-$version.tar.gz" ]; then
|
||||||
curl --insecure -LO "http://www.colm.net/wp-content/uploads/2014/10/ragel-$version.tar.gz"
|
curl --insecure -LO "http://www.colm.net/files/ragel/ragel-$version.tar.gz"
|
||||||
fi
|
fi
|
||||||
tar xzf "ragel-$version.tar.gz"
|
tar xzf "ragel-$version.tar.gz"
|
||||||
cd "ragel-$version"
|
cd "ragel-$version"
|
||||||
|
@ -686,7 +689,7 @@ build_harfbuzz()
|
||||||
# disable doc directories as they make problems on Mac OS Build
|
# disable doc directories as they make problems on Mac OS Build
|
||||||
sed -e "s/SUBDIRS = src util test docs/SUBDIRS = src util test/g" Makefile.am > Makefile.am.bak && mv Makefile.am.bak Makefile.am
|
sed -e "s/SUBDIRS = src util test docs/SUBDIRS = src util test/g" Makefile.am > Makefile.am.bak && mv Makefile.am.bak Makefile.am
|
||||||
sed -e "s/^docs.*$//" configure.ac > configure.ac.bak && mv configure.ac.bak configure.ac
|
sed -e "s/^docs.*$//" configure.ac > configure.ac.bak && mv configure.ac.bak configure.ac
|
||||||
PKG_CONFIG_LIBDIR="$DEPLOYDIR/lib/pkgconfig" ./autogen.sh --prefix="$DEPLOYDIR" --with-freetype=yes --with-gobject=no --with-cairo=no --with-icu=no CFLAGS=-mmacosx-version-min=$MAC_OSX_VERSION_MIN LDFLAGS=-mmacosx-version-min=$MAC_OSX_VERSION_MIN $extra_config_flags
|
PKG_CONFIG_LIBDIR="$DEPLOYDIR/lib/pkgconfig" ./autogen.sh --prefix="$DEPLOYDIR" --with-freetype=yes --with-gobject=no --with-cairo=no --with-icu=no CFLAGS=-mmacosx-version-min=$MAC_OSX_VERSION_MIN CXXFLAGS=-mmacosx-version-min=$MAC_OSX_VERSION_MIN LDFLAGS=-mmacosx-version-min=$MAC_OSX_VERSION_MIN $extra_config_flags
|
||||||
make -j$NUMCPU
|
make -j$NUMCPU
|
||||||
make install
|
make install
|
||||||
}
|
}
|
||||||
|
@ -770,26 +773,26 @@ fi
|
||||||
|
|
||||||
echo "Using basedir:" $BASEDIR
|
echo "Using basedir:" $BASEDIR
|
||||||
mkdir -p $SRCDIR $DEPLOYDIR
|
mkdir -p $SRCDIR $DEPLOYDIR
|
||||||
build_qt5 5.3.1
|
build_qt5 5.4.0
|
||||||
build_qscintilla 2.8.4
|
build_qscintilla 2.8.4
|
||||||
# NB! For eigen, also update the path in the function
|
# NB! For eigen, also update the path in the function
|
||||||
build_eigen 3.2.1
|
build_eigen 3.2.3
|
||||||
build_gmp 5.1.3
|
build_gmp 5.1.3
|
||||||
build_mpfr 3.1.2
|
build_mpfr 3.1.2
|
||||||
build_boost 1.54.0
|
build_boost 1.57.0
|
||||||
# NB! For CGAL, also update the actual download URL in the function
|
# NB! For CGAL, also update the actual download URL in the function
|
||||||
build_cgal 4.5
|
build_cgal 4.5.1
|
||||||
build_glew 1.10.0
|
build_glew 1.11.0
|
||||||
build_gettext 0.18.3.2
|
build_gettext 0.19.4
|
||||||
build_libffi 3.1
|
build_libffi 3.2.1
|
||||||
build_glib2 2.40.0
|
build_glib2 2.42.1
|
||||||
build_opencsg 1.4.0
|
build_opencsg 1.4.0
|
||||||
build_freetype 2.5.3 --without-png
|
build_freetype 2.5.4 --without-png
|
||||||
build_ragel 6.9
|
build_ragel 6.9
|
||||||
build_harfbuzz 0.9.35 "--with-coretext=auto --with-glib=no"
|
build_harfbuzz 0.9.37 "--with-coretext=auto --with-glib=no"
|
||||||
export FREETYPE_CFLAGS="-I$DEPLOYDIR/include -I$DEPLOYDIR/include/freetype2"
|
export FREETYPE_CFLAGS="-I$DEPLOYDIR/include -I$DEPLOYDIR/include/freetype2"
|
||||||
export FREETYPE_LIBS="-L$DEPLOYDIR/lib -lfreetype"
|
export FREETYPE_LIBS="-L$DEPLOYDIR/lib -lfreetype"
|
||||||
build_libxml2 2.9.1
|
build_libxml2 2.9.2
|
||||||
build_fontconfig 2.11.1
|
build_fontconfig 2.11.1
|
||||||
if $OPTION_DEPLOY; then
|
if $OPTION_DEPLOY; then
|
||||||
# build_sparkle andymatuschak 0ed83cf9f2eeb425d4fdd141c01a29d843970c20
|
# build_sparkle andymatuschak 0ed83cf9f2eeb425d4fdd141c01a29d843970c20
|
||||||
|
|
|
@ -254,8 +254,8 @@ case $OS in
|
||||||
echo "cant find $TARGET/openscad.exe. build failed. stopping."
|
echo "cant find $TARGET/openscad.exe. build failed. stopping."
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
# make console pipe-able openscad.com - see winconsole.pri for info
|
# make console pipe-able openscad.com - see winconsole.pro for info
|
||||||
qmake CONFIG+=winconsole ../openscad.pro
|
qmake ../winconsole.pro
|
||||||
make
|
make
|
||||||
if [ ! -e $TARGET/openscad.com ]; then
|
if [ ! -e $TARGET/openscad.com ]; then
|
||||||
echo "cant find $TARGET/openscad.com. build failed. stopping."
|
echo "cant find $TARGET/openscad.com. build failed. stopping."
|
||||||
|
@ -280,7 +280,6 @@ if [[ $? != 0 ]]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
echo "Building test suite..."
|
echo "Building test suite..."
|
||||||
|
|
||||||
if [ $BUILD_TESTS ]; then
|
if [ $BUILD_TESTS ]; then
|
||||||
|
@ -326,6 +325,7 @@ case $OS in
|
||||||
EXAMPLESDIR=OpenSCAD.app/Contents/Resources/examples
|
EXAMPLESDIR=OpenSCAD.app/Contents/Resources/examples
|
||||||
LIBRARYDIR=OpenSCAD.app/Contents/Resources/libraries
|
LIBRARYDIR=OpenSCAD.app/Contents/Resources/libraries
|
||||||
FONTDIR=OpenSCAD.app/Contents/Resources/fonts
|
FONTDIR=OpenSCAD.app/Contents/Resources/fonts
|
||||||
|
TRANSLATIONDIR=OpenSCAD.app/Contents/Resources/locale
|
||||||
COLORSCHEMESDIR=OpenSCAD.app/Contents/Resources/color-schemes
|
COLORSCHEMESDIR=OpenSCAD.app/Contents/Resources/color-schemes
|
||||||
;;
|
;;
|
||||||
UNIX_CROSS_WIN)
|
UNIX_CROSS_WIN)
|
||||||
|
@ -333,6 +333,7 @@ case $OS in
|
||||||
EXAMPLESDIR=$DEPLOYDIR/openscad-$VERSION/examples/
|
EXAMPLESDIR=$DEPLOYDIR/openscad-$VERSION/examples/
|
||||||
LIBRARYDIR=$DEPLOYDIR/openscad-$VERSION/libraries/
|
LIBRARYDIR=$DEPLOYDIR/openscad-$VERSION/libraries/
|
||||||
FONTDIR=$DEPLOYDIR/openscad-$VERSION/fonts/
|
FONTDIR=$DEPLOYDIR/openscad-$VERSION/fonts/
|
||||||
|
TRANSLATIONDIR=$DEPLOYDIR/openscad-$VERSION/locale/
|
||||||
COLORSCHEMESDIR=$DEPLOYDIR/openscad-$VERSION/color-schemes/
|
COLORSCHEMESDIR=$DEPLOYDIR/openscad-$VERSION/color-schemes/
|
||||||
rm -rf $DEPLOYDIR/openscad-$VERSION
|
rm -rf $DEPLOYDIR/openscad-$VERSION
|
||||||
mkdir $DEPLOYDIR/openscad-$VERSION
|
mkdir $DEPLOYDIR/openscad-$VERSION
|
||||||
|
@ -341,6 +342,7 @@ case $OS in
|
||||||
EXAMPLESDIR=openscad-$VERSION/examples/
|
EXAMPLESDIR=openscad-$VERSION/examples/
|
||||||
LIBRARYDIR=openscad-$VERSION/libraries/
|
LIBRARYDIR=openscad-$VERSION/libraries/
|
||||||
FONTDIR=openscad-$VERSION/fonts/
|
FONTDIR=openscad-$VERSION/fonts/
|
||||||
|
TRANSLATIONDIR=openscad-$VERSION/locale/
|
||||||
COLORSCHEMESDIR=openscad-$VERSION/color-schemes/
|
COLORSCHEMESDIR=openscad-$VERSION/color-schemes/
|
||||||
rm -rf openscad-$VERSION
|
rm -rf openscad-$VERSION
|
||||||
mkdir openscad-$VERSION
|
mkdir openscad-$VERSION
|
||||||
|
@ -386,6 +388,13 @@ if [ -n $LIBRARYDIR ]; then
|
||||||
rm -f libraries.tar
|
rm -f libraries.tar
|
||||||
chmod -R u=rwx,go=r,+X $LIBRARYDIR/*
|
chmod -R u=rwx,go=r,+X $LIBRARYDIR/*
|
||||||
fi
|
fi
|
||||||
|
if [ -n $TRANSLATIONDIR ]; then
|
||||||
|
echo $TRANSLATIONDIR
|
||||||
|
mkdir -p $TRANSLATIONDIR
|
||||||
|
cd locale && tar cvf $OPENSCADDIR/translations.tar */*/*.mo && cd $OPENSCADDIR
|
||||||
|
cd $TRANSLATIONDIR && tar xvf $OPENSCADDIR/translations.tar && cd $OPENSCADDIR
|
||||||
|
rm -f translations.tar
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Creating archive.."
|
echo "Creating archive.."
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Script for use from qmake to generate the translation
|
||||||
|
# related files.
|
||||||
|
#
|
||||||
|
|
||||||
|
SCRIPTDIR="`dirname \"$0\"`"
|
||||||
|
TOPDIR="`dirname \"$SCRIPTDIR\"`"
|
||||||
|
|
||||||
|
cd "$TOPDIR" || exit 1
|
||||||
|
|
||||||
|
echo "Compiling language files..."
|
||||||
|
./scripts/translation-update.sh updatemo
|
|
@ -0,0 +1,86 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# see doc/translation.txt for more info
|
||||||
|
|
||||||
|
updatepot()
|
||||||
|
{
|
||||||
|
# check we have all files from POTFILES present
|
||||||
|
while read f
|
||||||
|
do
|
||||||
|
if [ ! -f "$f" ]; then
|
||||||
|
echo "cannot find file '$f' from POTFILES"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done < locale/POTFILES
|
||||||
|
|
||||||
|
grep ui_MainWindow.h locale/POTFILES >/dev/null 2>/dev/null
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "cannot find .../ui_xxxxx.h files. perhaps if you run make...?"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
VER=`date +"%Y.%m.%d"`
|
||||||
|
OPTS=
|
||||||
|
OPTS=$OPTS' --package-name=OpenSCAD'
|
||||||
|
OPTS=$OPTS' --package-version='$VER
|
||||||
|
OPTS=$OPTS' --default-domain=openscad'
|
||||||
|
OPTS=$OPTS' --keyword=_'
|
||||||
|
OPTS=$OPTS' --keyword=N_'
|
||||||
|
OPTS=$OPTS' --files-from=./locale/POTFILES'
|
||||||
|
cmd="${GETTEXT_PATH}xgettext "$OPTS' -o ./locale/openscad.pot'
|
||||||
|
echo $cmd
|
||||||
|
$cmd
|
||||||
|
if [ ! $? = 0 ]; then
|
||||||
|
echo error running xgettext
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
sed -e s/"CHARSET"/"UTF-8"/g ./locale/openscad.pot > ./locale/openscad.pot.new && mv ./locale/openscad.pot.new ./locale/openscad.pot
|
||||||
|
}
|
||||||
|
|
||||||
|
updatepo()
|
||||||
|
{
|
||||||
|
for LANGCODE in `cat ./locale/LINGUAS | grep -v "#"`; do
|
||||||
|
OPTS='--update --backup=t'
|
||||||
|
cmd="$GETTEXT_PATH"'msgmerge '$OPTS' ./locale/'$LANGCODE'.po ./locale/openscad.pot'
|
||||||
|
echo $cmd
|
||||||
|
$cmd
|
||||||
|
if [ ! $? = 0 ]; then
|
||||||
|
echo error running msgmerge
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
updatemo()
|
||||||
|
{
|
||||||
|
for LANGCODE in `cat locale/LINGUAS | grep -v "#"`; do
|
||||||
|
mkdir -p ./locale/$LANGCODE/LC_MESSAGES
|
||||||
|
OPTS='-c -v'
|
||||||
|
cmd="$GETTEXT_PATH"'msgfmt '$OPTS' -o ./locale/'$LANGCODE'/LC_MESSAGES/openscad.mo ./locale/'$LANGCODE'.po'
|
||||||
|
echo $cmd
|
||||||
|
$cmd
|
||||||
|
if [ ! $? = 0 ]; then
|
||||||
|
echo error running msgfmt
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
GETTEXT_PATH=""
|
||||||
|
#if [ "x$OPENSCAD_LIBRARIES" != x ]; then
|
||||||
|
# GETTEXT_PATH="$OPENSCAD_LIBRARIES/bin/"
|
||||||
|
#fi
|
||||||
|
|
||||||
|
SCRIPTDIR="`dirname \"$0\"`"
|
||||||
|
TOPDIR="`dirname \"$SCRIPTDIR\"`"
|
||||||
|
|
||||||
|
cd "$TOPDIR" || exit 1
|
||||||
|
|
||||||
|
if [ "x$1" = xupdatemo ]; then
|
||||||
|
updatemo
|
||||||
|
else
|
||||||
|
echo "Generating POTFILES..."
|
||||||
|
./scripts/generate-potfiles.sh > locale/POTFILES
|
||||||
|
updatepot && updatepo && updatemo
|
||||||
|
fi
|
||||||
|
|
|
@ -13,7 +13,7 @@ if [[ $? != 0 ]]; then
|
||||||
fi
|
fi
|
||||||
# Exclude tests known the cause issues on Travis
|
# Exclude tests known the cause issues on Travis
|
||||||
# opencsgtest_rotate_extrude-tests - Fails on Ubuntu 12.04 using Gallium 0.4 drivers
|
# opencsgtest_rotate_extrude-tests - Fails on Ubuntu 12.04 using Gallium 0.4 drivers
|
||||||
ctest -j8 -E "opencsgtest_rotate_extrude-tests|opencsgtest_render-tests|opencsgtest_rotate_extrude-hole|opencsgtest_internal-cavity|opencsgtest_internal-cavity-polyhedron|opencsgtest_minkowski3-erosion"
|
ctest -j8 -E "opencsgtest_rotate_extrude-tests|opencsgtest_render-tests|opencsgtest_rotate_extrude-hole|opencsgtest_internal-cavity|opencsgtest_internal-cavity-polyhedron|opencsgtest_minkowski3-erosion|opencsgtest_issue835|opencsgtest_issue911|opencsgtest_issue913"
|
||||||
if [[ $? != 0 ]]; then
|
if [[ $? != 0 ]]; then
|
||||||
echo "Test failure"
|
echo "Test failure"
|
||||||
exit 1
|
exit 1
|
||||||
|
|
|
@ -1,22 +1,23 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "openscad.h"
|
||||||
|
#include "qtgettext.h"
|
||||||
#include "ui_AboutDialog.h"
|
#include "ui_AboutDialog.h"
|
||||||
|
|
||||||
#define STRINGIFY(x) #x
|
|
||||||
#define TOSTRING(x) STRINGIFY(x)
|
|
||||||
|
|
||||||
class AboutDialog : public QDialog, public Ui::AboutDialog
|
class AboutDialog : public QDialog, public Ui::AboutDialog
|
||||||
{
|
{
|
||||||
Q_OBJECT;
|
Q_OBJECT;
|
||||||
public:
|
public:
|
||||||
AboutDialog(QWidget *) {
|
AboutDialog(QWidget *) {
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
this->setWindowTitle( QString("About OpenSCAD ") + QString(TOSTRING( OPENSCAD_VERSION)) );
|
this->setWindowTitle( QString(_("About OpenSCAD")) + " " + openscad_versionnumber.c_str());
|
||||||
this->aboutText->setOpenExternalLinks(true);
|
|
||||||
QUrl flattr_qurl(":icons/flattr.png" );
|
QUrl flattr_qurl(":icons/flattr.png" );
|
||||||
this->aboutText->loadResource( QTextDocument::ImageResource, flattr_qurl );
|
this->aboutText->loadResource( QTextDocument::ImageResource, flattr_qurl );
|
||||||
QString tmp = this->aboutText->toHtml();
|
QString tmp = this->aboutText->toHtml();
|
||||||
tmp.replace("__VERSION__",QString(TOSTRING(OPENSCAD_VERSION)));
|
tmp.replace("__VERSION__", openscad_versionnumber.c_str());
|
||||||
this->aboutText->setHtml(tmp);
|
this->aboutText->setHtml(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void on_okPushButton_clicked() { accept(); }
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<a href="http://www.openscad.org">OpenSCAD</a> version __VERSION__
|
<b><a href="http://www.openscad.org">OpenSCAD</a> version __VERSION__</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@ -149,9 +149,9 @@ benhowes, 5263, Craig Trader, Miro Hrončok, Tony Theodore ... and many others
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<lu>
|
<lu>
|
||||||
<li><a href="http://www.github.com">Github</a>
|
<li><a href="http://www.github.com">Source code repos and website hosted on Github</a>
|
||||||
<li><a href="http://rocklinux.net/pipermail/openscad/">Rock Linux</a>
|
<li><a href="http://jesusabdullah.net">Downloads hosted by Joshua Holbrook</a>
|
||||||
<li><a href="http://www.thingiverse.com">Thingiverse</a>
|
<li><a href="https://travis-ci.org/">CI hosted on Travis-CI</a>
|
||||||
</lu>
|
</lu>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -6,16 +6,98 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>567</width>
|
<width>628</width>
|
||||||
<height>359</height>
|
<height>419</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>About OpenSCAD</string>
|
<string>About OpenSCAD</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item>
|
<property name="margin">
|
||||||
|
<number>16</number>
|
||||||
|
</property>
|
||||||
|
<property name="horizontalSpacing">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<item row="0" column="0" colspan="3">
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="horizontalSpacing">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="logoLabel">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>96</width>
|
||||||
|
<height>96</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>96</width>
|
||||||
|
<height>96</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="pixmap">
|
||||||
|
<pixmap resource="../openscad.qrc">:/icons/openscad.png</pixmap>
|
||||||
|
</property>
|
||||||
|
<property name="scaledContents">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QLabel" name="titleLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string><html><head/><body>
|
||||||
|
<p style="font-family: 'Open Sans', 'Droid Sans', 'sans-serif'; font-weight: bold; padding-bottom: 0; margin-bottom: 0; font-size: 22pt;"><span style="color: green;">Open</span>SCAD</p>
|
||||||
|
<p style="font-family: 'Open Sans', 'Droid Sans', 'sans-serif'; font-weight: normal; font-size: 14pt; padding-top: 0; margin-top: 0; margin-left: 2em;">The Programmers Solid 3D CAD Modeller</p>
|
||||||
|
</body></html>
|
||||||
|
|
||||||
|
|
||||||
|
</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Fixed</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>2</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0" colspan="3">
|
||||||
<widget class="QTextBrowser" name="aboutText">
|
<widget class="QTextBrowser" name="aboutText">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>400</width>
|
||||||
|
<height>200</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
<property name="readOnly">
|
<property name="readOnly">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
|
@ -24,8 +106,31 @@
|
||||||
<string>qrc:/src/AboutDialog.html</string>
|
<string>qrc:/src/AboutDialog.html</string>
|
||||||
</url>
|
</url>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="openExternalLinks">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="4" column="2">
|
||||||
|
<widget class="QPushButton" name="okPushButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>OK</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<spacer name="horizontalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources>
|
<resources>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#include <Carbon/Carbon.h>
|
#include <AppleEvents.h>
|
||||||
|
#include <MacTypes.h>
|
||||||
|
#include <CoreServices/CoreServices.h>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,11 @@ size_t CGAL_Nef_polyhedron::memsize() const
|
||||||
return memsize;
|
return memsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CGAL_Nef_polyhedron::isEmpty() const
|
||||||
|
{
|
||||||
|
return !this->p3 || this->p3->is_empty();
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Creates a new PolySet and initializes it with the data from this polyhedron
|
Creates a new PolySet and initializes it with the data from this polyhedron
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ public:
|
||||||
virtual std::string dump() const;
|
virtual std::string dump() const;
|
||||||
virtual unsigned int getDimension() const { return 3; }
|
virtual unsigned int getDimension() const { return 3; }
|
||||||
// Empty means it is a geometric node which has zero area/volume
|
// Empty means it is a geometric node which has zero area/volume
|
||||||
virtual bool isEmpty() const { return !p3; }
|
virtual bool isEmpty() const;
|
||||||
virtual Geometry *copy() const { return new CGAL_Nef_polyhedron(*this); }
|
virtual Geometry *copy() const { return new CGAL_Nef_polyhedron(*this); }
|
||||||
|
|
||||||
void reset() { p3.reset(); }
|
void reset() { p3.reset(); }
|
||||||
|
|
|
@ -46,7 +46,7 @@ void CGAL_Nef_polyhedron::transform( const Transform3d &matrix )
|
||||||
{
|
{
|
||||||
if (!this->isEmpty()) {
|
if (!this->isEmpty()) {
|
||||||
if (matrix.matrix().determinant() == 0) {
|
if (matrix.matrix().determinant() == 0) {
|
||||||
PRINT("Warning: Scaling a 3D object with 0 - removing object");
|
PRINT("WARNING: Scaling a 3D object with 0 - removing object");
|
||||||
this->reset();
|
this->reset();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -95,7 +95,13 @@ static shared_ptr<CSGTerm> evaluate_csg_term_from_geometry(const State &state,
|
||||||
{
|
{
|
||||||
std::stringstream stream;
|
std::stringstream stream;
|
||||||
stream << node.name() << node.index();
|
stream << node.name() << node.index();
|
||||||
shared_ptr<CSGTerm> t(new CSGTerm(geom, state.matrix(), state.color(), stream.str()));
|
|
||||||
|
// We cannot render Polygon2d directly, so we preprocess (tessellate) it here
|
||||||
|
shared_ptr<const Geometry> g = geom;
|
||||||
|
shared_ptr<const Polygon2d> p2d = dynamic_pointer_cast<const Polygon2d>(geom);
|
||||||
|
if (p2d) g.reset(p2d->tessellate());
|
||||||
|
|
||||||
|
shared_ptr<CSGTerm> t(new CSGTerm(g, state.matrix(), state.color(), stream.str()));
|
||||||
if (modinst->isHighlight()) {
|
if (modinst->isHighlight()) {
|
||||||
t->flag = CSGTerm::FLAG_HIGHLIGHT;
|
t->flag = CSGTerm::FLAG_HIGHLIGHT;
|
||||||
highlights.push_back(t);
|
highlights.push_back(t);
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#include "printutils.h"
|
#include "printutils.h"
|
||||||
|
|
||||||
Camera::Camera(enum CameraType camtype) :
|
Camera::Camera(enum CameraType camtype) :
|
||||||
type(camtype), projection(Camera::PERSPECTIVE), fov(45), height(60), viewall(false)
|
type(camtype), projection(Camera::PERSPECTIVE), fov(45), viewall(false), height(60)
|
||||||
{
|
{
|
||||||
PRINTD("Camera()");
|
PRINTD("Camera()");
|
||||||
if (this->type == Camera::GIMBAL) {
|
if (this->type == Camera::GIMBAL) {
|
||||||
|
@ -101,25 +101,34 @@ void Camera::viewAll(const BoundingBox &bbox, float scalefactor)
|
||||||
|
|
||||||
void Camera::zoom(int delta)
|
void Camera::zoom(int delta)
|
||||||
{
|
{
|
||||||
if (this->projection == PERSPECTIVE) {
|
this->viewer_distance *= pow(0.9, delta / 120.0);
|
||||||
this->viewer_distance *= pow(0.9, delta / 120.0);
|
this->height = this->viewer_distance;
|
||||||
}
|
|
||||||
else {
|
|
||||||
this->height *= pow(0.9, delta / 120.0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Camera::setProjection(ProjectionType type)
|
void Camera::setProjection(ProjectionType type)
|
||||||
{
|
{
|
||||||
if (this->projection != type) {
|
this->projection = type;
|
||||||
switch (type) {
|
}
|
||||||
case PERSPECTIVE:
|
|
||||||
this->viewer_distance = this->height;
|
void Camera::resetView()
|
||||||
break;
|
{
|
||||||
case ORTHOGONAL:
|
type = Camera::GIMBAL;
|
||||||
this->height = this->viewer_distance;
|
object_rot << 35, 0, -25;
|
||||||
break;
|
object_trans << 0, 0, 0;
|
||||||
}
|
height = 140;
|
||||||
this->projection = type;
|
viewer_distance = 140;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double Camera::zoomValue()
|
||||||
|
{
|
||||||
|
return this->projection == PERSPECTIVE ? viewer_distance : height;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Camera::statusText()
|
||||||
|
{
|
||||||
|
boost::format fmt(_("Viewport: translate = [ %.2f %.2f %.2f ], rotate = [ %.2f %.2f %.2f ], distance = %.2f"));
|
||||||
|
fmt % object_trans.x() % object_trans.y() % object_trans.z()
|
||||||
|
% object_rot.x() % object_rot.y() % object_rot.z()
|
||||||
|
% (this->projection == PERSPECTIVE ? viewer_distance : height);
|
||||||
|
return fmt.str();
|
||||||
}
|
}
|
||||||
|
|
13
src/Camera.h
13
src/Camera.h
|
@ -30,7 +30,10 @@ public:
|
||||||
void gimbalDefaultTranslate();
|
void gimbalDefaultTranslate();
|
||||||
void setProjection(ProjectionType type);
|
void setProjection(ProjectionType type);
|
||||||
void zoom(int delta);
|
void zoom(int delta);
|
||||||
|
double zoomValue();
|
||||||
|
void resetView();
|
||||||
void viewAll(const BoundingBox &bbox, float scalefactor = 1.0f);
|
void viewAll(const BoundingBox &bbox, float scalefactor = 1.0f);
|
||||||
|
std::string statusText();
|
||||||
|
|
||||||
// Vectorcam
|
// Vectorcam
|
||||||
Eigen::Vector3d eye;
|
Eigen::Vector3d eye;
|
||||||
|
@ -40,14 +43,10 @@ public:
|
||||||
// Gimbalcam
|
// Gimbalcam
|
||||||
Eigen::Vector3d object_trans;
|
Eigen::Vector3d object_trans;
|
||||||
Eigen::Vector3d object_rot;
|
Eigen::Vector3d object_rot;
|
||||||
double viewer_distance;
|
|
||||||
|
|
||||||
// Perspective settings
|
// Perspective settings
|
||||||
double fov; // Field of view
|
double fov; // Field of view
|
||||||
|
|
||||||
// Orthographic settings
|
|
||||||
double height; // world-space height of viewport
|
|
||||||
|
|
||||||
// true if camera should try to view everything in a given
|
// true if camera should try to view everything in a given
|
||||||
// bounding box.
|
// bounding box.
|
||||||
bool viewall;
|
bool viewall;
|
||||||
|
@ -58,4 +57,10 @@ public:
|
||||||
|
|
||||||
unsigned int pixel_width;
|
unsigned int pixel_width;
|
||||||
unsigned int pixel_height;
|
unsigned int pixel_height;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Perspective settings
|
||||||
|
double viewer_distance;
|
||||||
|
// Orthographic settings
|
||||||
|
double height; // world-space height of viewport
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,13 +12,8 @@
|
||||||
class CsgInfo
|
class CsgInfo
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CsgInfo()
|
CsgInfo() : glview(NULL), root_chain(NULL), highlights_chain(NULL), background_chain(NULL), progress_function(NULL)
|
||||||
{
|
{
|
||||||
root_chain = NULL;
|
|
||||||
highlights_chain = NULL;
|
|
||||||
background_chain = NULL;
|
|
||||||
glview = NULL;
|
|
||||||
progress_function = NULL;
|
|
||||||
normalizelimit = RenderSettings::inst()->openCSGTermLimit;
|
normalizelimit = RenderSettings::inst()->openCSGTermLimit;
|
||||||
}
|
}
|
||||||
OffscreenView *glview;
|
OffscreenView *glview;
|
||||||
|
@ -43,12 +38,6 @@ public:
|
||||||
CSGTermEvaluator evaluator(tree, &geomevaluator);
|
CSGTermEvaluator evaluator(tree, &geomevaluator);
|
||||||
boost::shared_ptr<CSGTerm> root_raw_term = evaluator.evaluateCSGTerm( *root_node, this->highlight_terms, this->background_terms );
|
boost::shared_ptr<CSGTerm> root_raw_term = evaluator.evaluateCSGTerm( *root_node, this->highlight_terms, this->background_terms );
|
||||||
|
|
||||||
if (!root_raw_term && this->background_terms.empty()) {
|
|
||||||
PRINT("Error: CSG generation failed! (no objects found)");
|
|
||||||
call_progress_function();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRINT("Compiling design (CSG Products normalization)...");
|
PRINT("Compiling design (CSG Products normalization)...");
|
||||||
call_progress_function();
|
call_progress_function();
|
||||||
CSGTermNormalizer normalizer( normalizelimit );
|
CSGTermNormalizer normalizer( normalizelimit );
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
|
|
||||||
|
#include "boosty.h"
|
||||||
#include "FontCache.h"
|
#include "FontCache.h"
|
||||||
#include "PlatformUtils.h"
|
#include "PlatformUtils.h"
|
||||||
#include "parsersettings.h"
|
#include "parsersettings.h"
|
||||||
|
@ -80,8 +81,20 @@ const std::string &FontInfo::get_file() const
|
||||||
}
|
}
|
||||||
|
|
||||||
FontCache * FontCache::self = NULL;
|
FontCache * FontCache::self = NULL;
|
||||||
|
FontCache::InitHandlerFunc *FontCache::cb_handler = FontCache::defaultInitHandler;
|
||||||
|
void *FontCache::cb_userdata = NULL;
|
||||||
const std::string FontCache::DEFAULT_FONT("XXX");
|
const std::string FontCache::DEFAULT_FONT("XXX");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default implementation for the font cache initialization. In case no other
|
||||||
|
* handler is registered, the cache build is just called synchronously in the
|
||||||
|
* current thread by this handler.
|
||||||
|
*/
|
||||||
|
void FontCache::defaultInitHandler(FontCacheInitializer *initializer, void *)
|
||||||
|
{
|
||||||
|
initializer->run();
|
||||||
|
}
|
||||||
|
|
||||||
FontCache::FontCache()
|
FontCache::FontCache()
|
||||||
{
|
{
|
||||||
this->init_ok = false;
|
this->init_ok = false;
|
||||||
|
@ -89,7 +102,7 @@ FontCache::FontCache()
|
||||||
// If we've got a bundled fonts.conf, initialize fontconfig with our own config
|
// If we've got a bundled fonts.conf, initialize fontconfig with our own config
|
||||||
// by overriding the built-in fontconfig path.
|
// by overriding the built-in fontconfig path.
|
||||||
// For system installs and dev environments, we leave this alone
|
// For system installs and dev environments, we leave this alone
|
||||||
fs::path fontdir(fs::path(PlatformUtils::resourcesPath()) / "fonts");
|
fs::path fontdir(PlatformUtils::resourcePath("fonts"));
|
||||||
if (fs::is_regular_file(fontdir / "fonts.conf")) {
|
if (fs::is_regular_file(fontdir / "fonts.conf")) {
|
||||||
PlatformUtils::setenv("FONTCONFIG_PATH", boosty::stringy(boosty::absolute(fontdir)).c_str(), 0);
|
PlatformUtils::setenv("FONTCONFIG_PATH", boosty::stringy(boosty::absolute(fontdir)).c_str(), 0);
|
||||||
}
|
}
|
||||||
|
@ -97,12 +110,12 @@ FontCache::FontCache()
|
||||||
// Just load the configs. We'll build the fonts once all configs are loaded
|
// Just load the configs. We'll build the fonts once all configs are loaded
|
||||||
this->config = FcInitLoadConfig();
|
this->config = FcInitLoadConfig();
|
||||||
if (!this->config) {
|
if (!this->config) {
|
||||||
PRINT("Can't initialize fontconfig library, text() objects will not be rendered");
|
PRINT("WARNING: Can't initialize fontconfig library, text() objects will not be rendered");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the built-in fonts & config
|
// Add the built-in fonts & config
|
||||||
fs::path builtinfontpath = fs::path(PlatformUtils::resourcesPath()) / "fonts";
|
fs::path builtinfontpath(PlatformUtils::resourcePath("fonts"));
|
||||||
if (fs::is_directory(builtinfontpath)) {
|
if (fs::is_directory(builtinfontpath)) {
|
||||||
FcConfigParseAndLoad(this->config, reinterpret_cast<const FcChar8 *>(boosty::stringy(builtinfontpath).c_str()), false);
|
FcConfigParseAndLoad(this->config, reinterpret_cast<const FcChar8 *>(boosty::stringy(builtinfontpath).c_str()), false);
|
||||||
add_font_dir(boosty::stringy(boosty::canonical(builtinfontpath)));
|
add_font_dir(boosty::stringy(boosty::canonical(builtinfontpath)));
|
||||||
|
@ -130,8 +143,8 @@ FontCache::FontCache()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Caching happens here. This would be a good place to notify the user
|
FontCacheInitializer initializer(this->config);
|
||||||
FcConfigBuildFonts(this->config);
|
cb_handler(&initializer, cb_userdata);
|
||||||
|
|
||||||
// For use by LibraryInfo
|
// For use by LibraryInfo
|
||||||
FcStrList *dirs = FcConfigGetFontDirs(this->config);
|
FcStrList *dirs = FcConfigGetFontDirs(this->config);
|
||||||
|
@ -142,7 +155,7 @@ FontCache::FontCache()
|
||||||
|
|
||||||
const FT_Error error = FT_Init_FreeType(&this->library);
|
const FT_Error error = FT_Init_FreeType(&this->library);
|
||||||
if (error) {
|
if (error) {
|
||||||
PRINT("Can't initialize freetype library, text() objects will not be rendered");
|
PRINT("WARNING: Can't initialize freetype library, text() objects will not be rendered");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,6 +174,12 @@ FontCache * FontCache::instance()
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FontCache::registerProgressHandler(InitHandlerFunc *handler, void *userdata)
|
||||||
|
{
|
||||||
|
FontCache::cb_handler = handler;
|
||||||
|
FontCache::cb_userdata = userdata;
|
||||||
|
}
|
||||||
|
|
||||||
void FontCache::register_font_file(const std::string &path)
|
void FontCache::register_font_file(const std::string &path)
|
||||||
{
|
{
|
||||||
if (!FcConfigAppFontAddFile(this->config, reinterpret_cast<const FcChar8 *> (path.c_str()))) {
|
if (!FcConfigAppFontAddFile(this->config, reinterpret_cast<const FcChar8 *> (path.c_str()))) {
|
||||||
|
|
|
@ -59,6 +59,19 @@ private:
|
||||||
|
|
||||||
typedef std::vector<FontInfo> FontInfoList;
|
typedef std::vector<FontInfo> FontInfoList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Slow call of the font cache initialization. This is separated here so it
|
||||||
|
* can be passed to the GUI to run in a separate thread while showing a
|
||||||
|
* progress dialog.
|
||||||
|
*/
|
||||||
|
class FontCacheInitializer {
|
||||||
|
public:
|
||||||
|
FontCacheInitializer(FcConfig *config) : config(config) { }
|
||||||
|
void run() { FcConfigBuildFonts(config); }
|
||||||
|
private:
|
||||||
|
FcConfig *config;
|
||||||
|
};
|
||||||
|
|
||||||
class FontCache {
|
class FontCache {
|
||||||
public:
|
public:
|
||||||
const static std::string DEFAULT_FONT;
|
const static std::string DEFAULT_FONT;
|
||||||
|
@ -75,12 +88,20 @@ public:
|
||||||
FontInfoList *list_fonts() const;
|
FontInfoList *list_fonts() const;
|
||||||
|
|
||||||
static FontCache *instance();
|
static FontCache *instance();
|
||||||
|
|
||||||
|
typedef void (InitHandlerFunc)(FontCacheInitializer *initializer, void *userdata);
|
||||||
|
static void registerProgressHandler(InitHandlerFunc *handler, void *userdata = NULL);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::pair<FT_Face, time_t> cache_entry_t;
|
typedef std::pair<FT_Face, time_t> cache_entry_t;
|
||||||
typedef std::map<std::string, cache_entry_t> cache_t;
|
typedef std::map<std::string, cache_entry_t> cache_t;
|
||||||
|
|
||||||
static FontCache *self;
|
static FontCache *self;
|
||||||
|
static InitHandlerFunc *cb_handler;
|
||||||
|
static void *cb_userdata;
|
||||||
|
|
||||||
|
static void defaultInitHandler(FontCacheInitializer *delegate, void *userdata);
|
||||||
|
|
||||||
bool init_ok;
|
bool init_ok;
|
||||||
cache_t cache;
|
cache_t cache;
|
||||||
FcConfig *config;
|
FcConfig *config;
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include <QClipboard>
|
#include <QClipboard>
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
|
|
||||||
|
#include "qtgettext.h"
|
||||||
#include "FontListDialog.h"
|
#include "FontListDialog.h"
|
||||||
#include "FontCache.h"
|
#include "FontCache.h"
|
||||||
|
|
||||||
|
@ -59,14 +60,16 @@ void FontListDialog::selection_changed(const QItemSelection ¤t, const QIte
|
||||||
{
|
{
|
||||||
if (current.count() == 0) {
|
if (current.count() == 0) {
|
||||||
copyButton->setEnabled(false);
|
copyButton->setEnabled(false);
|
||||||
|
tableView->setDragText("");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QModelIndex &idx = proxy->mapToSource(current.indexes().at(0));
|
const QModelIndex &idx = proxy->mapToSource(current.indexes().at(0));
|
||||||
const QString name = model->item(idx.row(), 0)->text();
|
const QString name = model->item(idx.row(), 0)->text();
|
||||||
const QString style = model->item(idx.row(), 1)->text();
|
const QString style = model->item(idx.row(), 1)->text();
|
||||||
selection = QString("\"%1:style=%2\"").arg(name).arg(style);
|
selection = QString("\"%1:style=%2\"").arg(quote(name)).arg(quote(style));
|
||||||
copyButton->setEnabled(true);
|
copyButton->setEnabled(true);
|
||||||
|
tableView->setDragText(selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FontListDialog::update_font_list()
|
void FontListDialog::update_font_list()
|
||||||
|
@ -116,3 +119,28 @@ void FontListDialog::update_font_list()
|
||||||
|
|
||||||
delete list;
|
delete list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Quote a string according to the requirements of font-config.
|
||||||
|
* See http://www.freedesktop.org/software/fontconfig/fontconfig-user.html
|
||||||
|
*
|
||||||
|
* The '\', '-', ':' and ',' characters in family names must be preceded
|
||||||
|
* by a '\' character to avoid having them misinterpreted. Similarly, values
|
||||||
|
* containing '\', '=', '_', ':' and ',' must also have them preceded by a
|
||||||
|
* '\' character. The '\' characters are stripped out of the family name and
|
||||||
|
* values as the font name is read.
|
||||||
|
*
|
||||||
|
* @param text unquoted string
|
||||||
|
* @return quoted text
|
||||||
|
*/
|
||||||
|
QString FontListDialog::quote(const QString& text)
|
||||||
|
{
|
||||||
|
QString result = text;
|
||||||
|
result.replace('\\', "\\\\")
|
||||||
|
.replace('-', "\\-")
|
||||||
|
.replace(':', "\\:")
|
||||||
|
.replace(',', "\\,")
|
||||||
|
.replace('=', "\\=")
|
||||||
|
.replace('_', "\\_");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -3,11 +3,9 @@
|
||||||
#include <QStandardItemModel>
|
#include <QStandardItemModel>
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
|
|
||||||
|
#include "qtgettext.h"
|
||||||
#include "ui_FontListDialog.h"
|
#include "ui_FontListDialog.h"
|
||||||
|
|
||||||
#define STRINGIFY(x) #x
|
|
||||||
#define TOSTRING(x) STRINGIFY(x)
|
|
||||||
|
|
||||||
class FontListDialog : public QDialog, public Ui::FontListDialog
|
class FontListDialog : public QDialog, public Ui::FontListDialog
|
||||||
{
|
{
|
||||||
Q_OBJECT;
|
Q_OBJECT;
|
||||||
|
@ -26,6 +24,8 @@ signals:
|
||||||
void font_selected(const QString font);
|
void font_selected(const QString font);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QString quote(const QString& text);
|
||||||
|
|
||||||
QString selection;
|
QString selection;
|
||||||
QStandardItemModel *model;
|
QStandardItemModel *model;
|
||||||
QSortFilterProxyModel *proxy;
|
QSortFilterProxyModel *proxy;
|
||||||
|
|
|
@ -35,9 +35,6 @@
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="3">
|
<item row="4" column="3">
|
||||||
<widget class="QPushButton" name="copyButton">
|
<widget class="QPushButton" name="copyButton">
|
||||||
<property name="toolTip">
|
|
||||||
<string>Paste font selector to Editor Window</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Copy to Clipboard</string>
|
<string>Copy to Clipboard</string>
|
||||||
</property>
|
</property>
|
||||||
|
@ -70,7 +67,17 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0" colspan="5">
|
<item row="2" column="0" colspan="5">
|
||||||
<widget class="QTableView" name="tableView"/>
|
<widget class="FontListTableView" name="tableView">
|
||||||
|
<property name="dragEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="dragDropMode">
|
||||||
|
<enum>QAbstractItemView::DragOnly</enum>
|
||||||
|
</property>
|
||||||
|
<property name="selectionBehavior">
|
||||||
|
<enum>QAbstractItemView::SelectRows</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0" colspan="5">
|
<item row="0" column="0" colspan="5">
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label">
|
||||||
|
@ -103,6 +110,13 @@
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>FontListTableView</class>
|
||||||
|
<extends>QTableView</extends>
|
||||||
|
<header>FontListTableView.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="../openscad.qrc"/>
|
<include location="../openscad.qrc"/>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* 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 <QDrag>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QMimeData>
|
||||||
|
|
||||||
|
#include "qtgettext.h"
|
||||||
|
#include "FontListDialog.h"
|
||||||
|
|
||||||
|
FontListTableView::FontListTableView(QWidget *parent) : QTableView(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void FontListTableView::setDragText(const QString &text)
|
||||||
|
{
|
||||||
|
this->text = text.trimmed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FontListTableView::startDrag(Qt::DropActions supportedActions)
|
||||||
|
{
|
||||||
|
if (text.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMimeData *mimeData = new QMimeData;
|
||||||
|
mimeData->setText(text);
|
||||||
|
|
||||||
|
QFontMetrics fm(font());
|
||||||
|
QRect rect(0, 0, fm.width(text) + 8, fm.height() + 8);
|
||||||
|
QPixmap pixmap(rect.width(), rect.height());
|
||||||
|
pixmap.fill(QColor(240, 240, 240, 160));
|
||||||
|
|
||||||
|
QPainter painter(&pixmap);
|
||||||
|
painter.setFont(font());
|
||||||
|
painter.drawText(rect, Qt::AlignCenter, text);
|
||||||
|
painter.drawRect(0, 0, rect.width() - 1, rect.height() - 1);
|
||||||
|
|
||||||
|
QDrag *drag = new QDrag(this);
|
||||||
|
drag->setPixmap(pixmap);
|
||||||
|
drag->setMimeData(mimeData);
|
||||||
|
drag->setHotSpot(QPoint(-10, rect.height() + 6));
|
||||||
|
drag->exec(supportedActions, Qt::CopyAction);
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QTableView>
|
||||||
|
|
||||||
|
class FontListTableView : public QTableView
|
||||||
|
{
|
||||||
|
Q_OBJECT;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FontListTableView(QWidget *parent = NULL);
|
||||||
|
void setDragText(const QString &text);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void startDrag(Qt::DropActions supportedActions);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString text;
|
||||||
|
};
|
|
@ -91,21 +91,23 @@ void GLView::setupCamera()
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
|
|
||||||
switch (this->cam.type) {
|
switch (this->cam.type) {
|
||||||
case Camera::GIMBAL:
|
case Camera::GIMBAL: {
|
||||||
|
double eyeY = 0.0;
|
||||||
switch (this->cam.projection) {
|
switch (this->cam.projection) {
|
||||||
case Camera::PERSPECTIVE: {
|
case Camera::PERSPECTIVE: {
|
||||||
double dist = cam.viewer_distance;
|
eyeY = cam.zoomValue();
|
||||||
gluPerspective(cam.fov, aspectratio, 0.1*dist, 100*dist);
|
gluPerspective(cam.fov, aspectratio, 0.1 * eyeY, 100 * eyeY);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Camera::ORTHOGONAL: {
|
case Camera::ORTHOGONAL: {
|
||||||
glOrtho(-cam.height/2*aspectratio, cam.height*aspectratio/2,
|
eyeY = cam.zoomValue();
|
||||||
-cam.height/2, cam.height/2,
|
glOrtho(-eyeY/2*aspectratio, eyeY*aspectratio/2,
|
||||||
|
-eyeY/2, eyeY/2,
|
||||||
-far_far_away, +far_far_away);
|
-far_far_away, +far_far_away);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gluLookAt(0.0, -cam.viewer_distance, 0.0,
|
gluLookAt(0.0, -eyeY, 0.0,
|
||||||
0.0, 0.0, 0.0,
|
0.0, 0.0, 0.0,
|
||||||
0.0, 0.0, 1.0);
|
0.0, 0.0, 1.0);
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
@ -113,8 +115,8 @@ void GLView::setupCamera()
|
||||||
glRotated(cam.object_rot.x(), 1.0, 0.0, 0.0);
|
glRotated(cam.object_rot.x(), 1.0, 0.0, 0.0);
|
||||||
glRotated(cam.object_rot.y(), 0.0, 1.0, 0.0);
|
glRotated(cam.object_rot.y(), 0.0, 1.0, 0.0);
|
||||||
glRotated(cam.object_rot.z(), 0.0, 0.0, 1.0);
|
glRotated(cam.object_rot.z(), 0.0, 0.0, 1.0);
|
||||||
glTranslated(cam.object_trans.x(), cam.object_trans.y(), cam.object_trans.z() );
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case Camera::VECTOR: {
|
case Camera::VECTOR: {
|
||||||
switch (this->cam.projection) {
|
switch (this->cam.projection) {
|
||||||
case Camera::PERSPECTIVE: {
|
case Camera::PERSPECTIVE: {
|
||||||
|
@ -123,8 +125,9 @@ void GLView::setupCamera()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Camera::ORTHOGONAL: {
|
case Camera::ORTHOGONAL: {
|
||||||
glOrtho(-cam.height/2*aspectratio, cam.height*aspectratio/2,
|
double height = cam.zoomValue();
|
||||||
-cam.height/2, cam.height/2,
|
glOrtho(-height/2*aspectratio, height*aspectratio/2,
|
||||||
|
-height/2, height/2,
|
||||||
-far_far_away, +far_far_away);
|
-far_far_away, +far_far_away);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -150,18 +153,24 @@ void GLView::setupCamera()
|
||||||
|
|
||||||
void GLView::paintGL()
|
void GLView::paintGL()
|
||||||
{
|
{
|
||||||
glEnable(GL_LIGHTING);
|
glDisable(GL_LIGHTING);
|
||||||
|
|
||||||
setupCamera();
|
|
||||||
|
|
||||||
Color4f bgcol = ColorMap::getColor(*this->colorscheme, BACKGROUND_COLOR);
|
Color4f bgcol = ColorMap::getColor(*this->colorscheme, BACKGROUND_COLOR);
|
||||||
|
Color4f bgcontrast = ColorMap::getContrastColor(bgcol);
|
||||||
glClearColor(bgcol[0], bgcol[1], bgcol[2], 1.0);
|
glClearColor(bgcol[0], bgcol[1], bgcol[2], 1.0);
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||||
|
|
||||||
// Only for GIMBAL cam
|
setupCamera();
|
||||||
if (showcrosshairs) GLView::showCrosshairs();
|
if (this->cam.type) {
|
||||||
if (showaxes) GLView::showAxes();
|
// Only for GIMBAL cam
|
||||||
|
// The crosshair should be fixed at the center of the viewport...
|
||||||
|
if (showcrosshairs) GLView::showCrosshairs();
|
||||||
|
glTranslated(cam.object_trans.x(), cam.object_trans.y(), cam.object_trans.z());
|
||||||
|
// ...the axis lines need to follow the object translation.
|
||||||
|
if (showaxes) GLView::showAxes(bgcontrast);
|
||||||
|
}
|
||||||
|
|
||||||
|
glEnable(GL_LIGHTING);
|
||||||
glDepthFunc(GL_LESS);
|
glDepthFunc(GL_LESS);
|
||||||
glCullFace(GL_BACK);
|
glCullFace(GL_BACK);
|
||||||
glDisable(GL_CULL_FACE);
|
glDisable(GL_CULL_FACE);
|
||||||
|
@ -174,10 +183,11 @@ void GLView::paintGL()
|
||||||
OpenCSG::setContext(this->opencsg_id);
|
OpenCSG::setContext(this->opencsg_id);
|
||||||
#endif
|
#endif
|
||||||
this->renderer->draw(showfaces, showedges);
|
this->renderer->draw(showfaces, showedges);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only for GIMBAL
|
// Only for GIMBAL
|
||||||
if (showaxes) GLView::showSmallaxes();
|
glDisable(GL_LIGHTING);
|
||||||
|
if (showaxes) GLView::showSmallaxes(bgcontrast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_OPENCSG
|
#ifdef ENABLE_OPENCSG
|
||||||
|
@ -358,7 +368,7 @@ void GLView::initializeGL()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLView::showSmallaxes()
|
void GLView::showSmallaxes(const Color4f &col)
|
||||||
{
|
{
|
||||||
// Fixme - this doesnt work in Vector Camera mode
|
// Fixme - this doesnt work in Vector Camera mode
|
||||||
|
|
||||||
|
@ -423,14 +433,9 @@ void GLView::showSmallaxes()
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
|
|
||||||
// FIXME: This was an attempt to keep contrast with background, but is suboptimal
|
glColor3f(col[0], col[1], col[2]);
|
||||||
// (e.g. nearly invisible against a gray background).
|
|
||||||
// int r,g,b;
|
float d = 3*dpi;
|
||||||
// r=g=b=0;
|
|
||||||
// bgcol.getRgb(&r, &g, &b);
|
|
||||||
// glColor3f((255.0f-r)/255.0f, (255.0f-g)/255.0f, (255.0f-b)/255.0f);
|
|
||||||
float d = 3*dpi;
|
|
||||||
glColor3f(0.0f, 0.0f, 0.0f);
|
|
||||||
glBegin(GL_LINES);
|
glBegin(GL_LINES);
|
||||||
// X Label
|
// X Label
|
||||||
glVertex3d(xlabel_x-d, xlabel_y-d, 0); glVertex3d(xlabel_x+d, xlabel_y+d, 0);
|
glVertex3d(xlabel_x-d, xlabel_y-d, 0); glVertex3d(xlabel_x+d, xlabel_y+d, 0);
|
||||||
|
@ -447,36 +452,48 @@ void GLView::showSmallaxes()
|
||||||
glEnd();
|
glEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLView::showAxes()
|
void GLView::showAxes(const Color4f &col)
|
||||||
{
|
{
|
||||||
|
double l = cam.zoomValue();
|
||||||
|
|
||||||
// FIXME: doesn't work under Vector Camera
|
// FIXME: doesn't work under Vector Camera
|
||||||
// Large gray axis cross inline with the model
|
// Large gray axis cross inline with the model
|
||||||
// FIXME: This is always gray - adjust color to keep contrast with background
|
|
||||||
glLineWidth(this->getDPI());
|
glLineWidth(this->getDPI());
|
||||||
glColor3d(0.5, 0.5, 0.5);
|
glColor3f(col[0], col[1], col[2]);
|
||||||
|
|
||||||
glBegin(GL_LINES);
|
glBegin(GL_LINES);
|
||||||
double l = cam.projection == Camera::PERSPECTIVE ? cam.viewer_distance : cam.height;
|
glVertex3d(0, 0, 0);
|
||||||
glVertex3d(-l, 0, 0);
|
|
||||||
glVertex3d(+l, 0, 0);
|
glVertex3d(+l, 0, 0);
|
||||||
glVertex3d(0, -l, 0);
|
glVertex3d(0, 0, 0);
|
||||||
glVertex3d(0, +l, 0);
|
glVertex3d(0, +l, 0);
|
||||||
glVertex3d(0, 0, -l);
|
glVertex3d(0, 0, 0);
|
||||||
glVertex3d(0, 0, +l);
|
glVertex3d(0, 0, +l);
|
||||||
glEnd();
|
glEnd();
|
||||||
|
|
||||||
|
glPushAttrib(GL_LINE_BIT);
|
||||||
|
glEnable(GL_LINE_STIPPLE);
|
||||||
|
glLineStipple(3, 0xAAAA);
|
||||||
|
glBegin(GL_LINES);
|
||||||
|
glVertex3d(0, 0, 0);
|
||||||
|
glVertex3d(-l, 0, 0);
|
||||||
|
glVertex3d(0, 0, 0);
|
||||||
|
glVertex3d(0, -l, 0);
|
||||||
|
glVertex3d(0, 0, 0);
|
||||||
|
glVertex3d(0, 0, -l);
|
||||||
|
glEnd();
|
||||||
|
glPopAttrib();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLView::showCrosshairs()
|
void GLView::showCrosshairs()
|
||||||
{
|
{
|
||||||
// FIXME: this might not work with Vector camera
|
// FIXME: this might not work with Vector camera
|
||||||
// FIXME: Crosshairs and axes are lighted, this doesn't make sense and causes them
|
glLineWidth(this->getDPI());
|
||||||
// to change color based on view orientation.
|
|
||||||
glLineWidth(3);
|
|
||||||
Color4f col = ColorMap::getColor(*this->colorscheme, CROSSHAIR_COLOR);
|
Color4f col = ColorMap::getColor(*this->colorscheme, CROSSHAIR_COLOR);
|
||||||
glColor3f(col[0], col[1], col[2]);
|
glColor3f(col[0], col[1], col[2]);
|
||||||
glBegin(GL_LINES);
|
glBegin(GL_LINES);
|
||||||
for (double xf = -1; xf <= +1; xf += 2)
|
for (double xf = -1; xf <= +1; xf += 2)
|
||||||
for (double yf = -1; yf <= +1; yf += 2) {
|
for (double yf = -1; yf <= +1; yf += 2) {
|
||||||
double vd = cam.viewer_distance/20;
|
double vd = cam.zoomValue()/8;
|
||||||
glVertex3d(-xf*vd, -yf*vd, -vd);
|
glVertex3d(-xf*vd, -yf*vd, -vd);
|
||||||
glVertex3d(+xf*vd, +yf*vd, +vd);
|
glVertex3d(+xf*vd, +yf*vd, +vd);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,10 +42,6 @@ public:
|
||||||
void setCamera(const Camera &cam);
|
void setCamera(const Camera &cam);
|
||||||
void setupCamera();
|
void setupCamera();
|
||||||
|
|
||||||
void showCrosshairs();
|
|
||||||
void showAxes();
|
|
||||||
void showSmallaxes();
|
|
||||||
|
|
||||||
void setColorScheme(const ColorScheme &cs);
|
void setColorScheme(const ColorScheme &cs);
|
||||||
void setColorScheme(const std::string &cs);
|
void setColorScheme(const std::string &cs);
|
||||||
void updateColorScheme();
|
void updateColorScheme();
|
||||||
|
@ -76,4 +72,8 @@ public:
|
||||||
bool opencsg_support;
|
bool opencsg_support;
|
||||||
int opencsg_id;
|
int opencsg_id;
|
||||||
#endif
|
#endif
|
||||||
|
private:
|
||||||
|
void showCrosshairs();
|
||||||
|
void showAxes(const Color4f &col);
|
||||||
|
void showSmallaxes(const Color4f &col);
|
||||||
};
|
};
|
||||||
|
|
|
@ -63,10 +63,12 @@ shared_ptr<const Geometry> GeometryEvaluator::evaluateGeometry(const AbstractNod
|
||||||
PolySet *ps = new PolySet(3);
|
PolySet *ps = new PolySet(3);
|
||||||
ps->setConvexity(N->getConvexity());
|
ps->setConvexity(N->getConvexity());
|
||||||
this->root.reset(ps);
|
this->root.reset(ps);
|
||||||
bool err = CGALUtils::createPolySetFromNefPolyhedron3(*N->p3, *ps);
|
if (!N->isEmpty()) {
|
||||||
if (err) {
|
bool err = CGALUtils::createPolySetFromNefPolyhedron3(*N->p3, *ps);
|
||||||
PRINT("ERROR: Nef->PolySet failed");
|
if (err) {
|
||||||
}
|
PRINT("ERROR: Nef->PolySet failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
smartCacheInsert(node, this->root);
|
smartCacheInsert(node, this->root);
|
||||||
}
|
}
|
||||||
|
@ -88,8 +90,12 @@ GeometryEvaluator::ResultObject GeometryEvaluator::applyToChildren(const Abstrac
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dim == 2) return ResultObject(applyToChildren2D(node, op));
|
if (dim == 2) {
|
||||||
else if (dim == 3) return applyToChildren3D(node, op);
|
Polygon2d *p2d = applyToChildren2D(node, op);
|
||||||
|
assert(p2d);
|
||||||
|
return ResultObject(p2d);
|
||||||
|
}
|
||||||
|
else if (dim == 3) return applyToChildren3D(node, op);
|
||||||
return ResultObject();
|
return ResultObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,16 +125,23 @@ GeometryEvaluator::ResultObject GeometryEvaluator::applyToChildren3D(const Abstr
|
||||||
|
|
||||||
if (op == OPENSCAD_MINKOWSKI) return ResultObject(CGALUtils::applyMinkowski(children));
|
if (op == OPENSCAD_MINKOWSKI) return ResultObject(CGALUtils::applyMinkowski(children));
|
||||||
|
|
||||||
CGAL_Nef_polyhedron *N = new CGAL_Nef_polyhedron;
|
CGAL_Nef_polyhedron *N = CGALUtils::applyOperator(children, op);
|
||||||
CGALUtils::applyOperator(children, *N, op);
|
// FIXME: Clarify when we can return NULL and what that means
|
||||||
|
if (!N) N = new CGAL_Nef_polyhedron;
|
||||||
return ResultObject(N);
|
return ResultObject(N);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Apply 2D hull.
|
||||||
|
|
||||||
|
May return an empty geometry but will not return NULL.
|
||||||
|
*/
|
||||||
Polygon2d *GeometryEvaluator::applyHull2D(const AbstractNode &node)
|
Polygon2d *GeometryEvaluator::applyHull2D(const AbstractNode &node)
|
||||||
{
|
{
|
||||||
std::vector<const Polygon2d *> children = collectChildren2D(node);
|
std::vector<const Polygon2d *> children = collectChildren2D(node);
|
||||||
Polygon2d *geometry = NULL;
|
Polygon2d *geometry = new Polygon2d();
|
||||||
|
|
||||||
typedef CGAL::Point_2<CGAL::Cartesian<double> > CGALPoint2;
|
typedef CGAL::Point_2<CGAL::Cartesian<double> > CGALPoint2;
|
||||||
// Collect point cloud
|
// Collect point cloud
|
||||||
|
@ -150,7 +163,6 @@ Polygon2d *GeometryEvaluator::applyHull2D(const AbstractNode &node)
|
||||||
BOOST_FOREACH(const CGALPoint2 &p, result) {
|
BOOST_FOREACH(const CGALPoint2 &p, result) {
|
||||||
outline.vertices.push_back(Vector2d(p[0], p[1]));
|
outline.vertices.push_back(Vector2d(p[0], p[1]));
|
||||||
}
|
}
|
||||||
geometry = new Polygon2d();
|
|
||||||
geometry->addOutline(outline);
|
geometry->addOutline(outline);
|
||||||
}
|
}
|
||||||
return geometry;
|
return geometry;
|
||||||
|
@ -271,12 +283,12 @@ Geometry::ChildList GeometryEvaluator::collectChildren3D(const AbstractNode &nod
|
||||||
smartCacheInsert(*chnode, chgeom);
|
smartCacheInsert(*chnode, chgeom);
|
||||||
|
|
||||||
if (chgeom) {
|
if (chgeom) {
|
||||||
if (chgeom->isEmpty() || chgeom->getDimension() == 3) {
|
if (chgeom->getDimension() == 2) {
|
||||||
children.push_back(item);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
PRINT("WARNING: Ignoring 2D child object for 3D operation");
|
PRINT("WARNING: Ignoring 2D child object for 3D operation");
|
||||||
}
|
}
|
||||||
|
else if (chgeom->isEmpty() || chgeom->getDimension() == 3) {
|
||||||
|
children.push_back(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return children;
|
return children;
|
||||||
|
@ -345,6 +357,7 @@ void GeometryEvaluator::addToParent(const State &state,
|
||||||
// Root node, insert into cache
|
// Root node, insert into cache
|
||||||
smartCacheInsert(node, geom);
|
smartCacheInsert(node, geom);
|
||||||
this->root = geom;
|
this->root = geom;
|
||||||
|
assert(this->visitedchildren.empty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,7 +391,7 @@ Response GeometryEvaluator::visit(State &state, const OffsetNode &node)
|
||||||
const Polygon2d *polygon = dynamic_cast<const Polygon2d*>(geometry);
|
const Polygon2d *polygon = dynamic_cast<const Polygon2d*>(geometry);
|
||||||
// ClipperLib documentation: The formula for the number of steps in a full
|
// ClipperLib documentation: The formula for the number of steps in a full
|
||||||
// circular arc is ... Pi / acos(1 - arc_tolerance / abs(delta))
|
// circular arc is ... Pi / acos(1 - arc_tolerance / abs(delta))
|
||||||
double n = Calc::get_fragments_from_r(10, node.fn, node.fs, node.fa);
|
double n = Calc::get_fragments_from_r(std::abs(node.delta), node.fn, node.fs, node.fa);
|
||||||
double arc_tolerance = std::abs(node.delta) * (1 - cos(M_PI / n));
|
double arc_tolerance = std::abs(node.delta) * (1 - cos(M_PI / n));
|
||||||
const Polygon2d *result = ClipperUtils::applyOffset(*polygon, node.delta, node.join_type, node.miter_limit, arc_tolerance);
|
const Polygon2d *result = ClipperUtils::applyOffset(*polygon, node.delta, node.join_type, node.miter_limit, arc_tolerance);
|
||||||
assert(result);
|
assert(result);
|
||||||
|
@ -443,6 +456,7 @@ Response GeometryEvaluator::visit(State &state, const LeafNode &node)
|
||||||
shared_ptr<const Geometry> geom;
|
shared_ptr<const Geometry> geom;
|
||||||
if (!isSmartCached(node)) {
|
if (!isSmartCached(node)) {
|
||||||
const Geometry *geometry = node.createGeometry();
|
const Geometry *geometry = node.createGeometry();
|
||||||
|
assert(geometry);
|
||||||
if (const Polygon2d *polygon = dynamic_cast<const Polygon2d*>(geometry)) {
|
if (const Polygon2d *polygon = dynamic_cast<const Polygon2d*>(geometry)) {
|
||||||
if (!polygon->isSanitized()) {
|
if (!polygon->isSanitized()) {
|
||||||
Polygon2d *p = ClipperUtils::sanitize(*polygon);
|
Polygon2d *p = ClipperUtils::sanitize(*polygon);
|
||||||
|
@ -516,7 +530,7 @@ Response GeometryEvaluator::visit(State &state, const TransformNode &node)
|
||||||
if (!isSmartCached(node)) {
|
if (!isSmartCached(node)) {
|
||||||
if (matrix_contains_infinity(node.matrix) || matrix_contains_nan(node.matrix)) {
|
if (matrix_contains_infinity(node.matrix) || matrix_contains_nan(node.matrix)) {
|
||||||
// due to the way parse/eval works we can't currently distinguish between NaN and Inf
|
// due to the way parse/eval works we can't currently distinguish between NaN and Inf
|
||||||
PRINT("Warning: Transformation matrix contains Not-a-Number and/or Infinity - removing object.");
|
PRINT("WARNING: Transformation matrix contains Not-a-Number and/or Infinity - removing object.");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// First union all children
|
// First union all children
|
||||||
|
@ -537,7 +551,12 @@ Response GeometryEvaluator::visit(State &state, const TransformNode &node)
|
||||||
node.matrix(1,0), node.matrix(1,1), node.matrix(1,3),
|
node.matrix(1,0), node.matrix(1,1), node.matrix(1,3),
|
||||||
node.matrix(3,0), node.matrix(3,1), node.matrix(3,3);
|
node.matrix(3,0), node.matrix(3,1), node.matrix(3,3);
|
||||||
newpoly->transform(mat2);
|
newpoly->transform(mat2);
|
||||||
geom = newpoly;
|
// A 2D transformation may flip the winding order of a polygon.
|
||||||
|
// If that happens with a sanitized polygon, we need to reverse
|
||||||
|
// the winding order for it to be correct.
|
||||||
|
if (newpoly->isSanitized() && mat2.matrix().determinant() <= 0) {
|
||||||
|
geom.reset(ClipperUtils::sanitize(*newpoly));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (geom->getDimension() == 3) {
|
else if (geom->getDimension() == 3) {
|
||||||
shared_ptr<const PolySet> ps = dynamic_pointer_cast<const PolySet>(geom);
|
shared_ptr<const PolySet> ps = dynamic_pointer_cast<const PolySet>(geom);
|
||||||
|
@ -573,7 +592,7 @@ Response GeometryEvaluator::visit(State &state, const TransformNode &node)
|
||||||
|
|
||||||
static void translate_PolySet(PolySet &ps, const Vector3d &translation)
|
static void translate_PolySet(PolySet &ps, const Vector3d &translation)
|
||||||
{
|
{
|
||||||
BOOST_FOREACH(PolySet::Polygon &p, ps.polygons) {
|
BOOST_FOREACH(Polygon &p, ps.polygons) {
|
||||||
BOOST_FOREACH(Vector3d &v, p) {
|
BOOST_FOREACH(Vector3d &v, p) {
|
||||||
v += translation;
|
v += translation;
|
||||||
}
|
}
|
||||||
|
@ -651,7 +670,7 @@ static Geometry *extrudePolygon(const LinearExtrudeNode &node, const Polygon2d &
|
||||||
PolySet *ps_bottom = poly.tessellate(); // bottom
|
PolySet *ps_bottom = poly.tessellate(); // bottom
|
||||||
|
|
||||||
// Flip vertex ordering for bottom polygon
|
// Flip vertex ordering for bottom polygon
|
||||||
BOOST_FOREACH(PolySet::Polygon &p, ps_bottom->polygons) {
|
BOOST_FOREACH(Polygon &p, ps_bottom->polygons) {
|
||||||
std::reverse(p.begin(), p.end());
|
std::reverse(p.begin(), p.end());
|
||||||
}
|
}
|
||||||
translate_PolySet(*ps_bottom, Vector3d(0,0,h1));
|
translate_PolySet(*ps_bottom, Vector3d(0,0,h1));
|
||||||
|
@ -934,9 +953,10 @@ Response GeometryEvaluator::visit(State &state, const ProjectionNode &node)
|
||||||
}
|
}
|
||||||
if (!Nptr->isEmpty()) {
|
if (!Nptr->isEmpty()) {
|
||||||
Polygon2d *poly = CGALUtils::project(*Nptr, node.cut_mode);
|
Polygon2d *poly = CGALUtils::project(*Nptr, node.cut_mode);
|
||||||
assert(poly);
|
if (poly) {
|
||||||
poly->setConvexity(node.convexity);
|
poly->setConvexity(node.convexity);
|
||||||
geom.reset(poly);
|
geom.reset(poly);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,12 +29,20 @@ std::string LibraryInfo::info()
|
||||||
{
|
{
|
||||||
std::stringstream s;
|
std::stringstream s;
|
||||||
|
|
||||||
|
#if defined(__x86_64__) || defined(_M_X64)
|
||||||
|
std::string bits(" 64bit");
|
||||||
|
#elif defined(__i386) || defined(_M_IX86)
|
||||||
|
std::string bits(" 32bit");
|
||||||
|
#else
|
||||||
|
std::string bits("");
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(__GNUG__) && !defined(__clang__)
|
#if defined(__GNUG__) && !defined(__clang__)
|
||||||
std::string compiler_info( "GCC " + std::string(TOSTRING(__VERSION__)) );
|
std::string compiler_info( "GCC " + std::string(TOSTRING(__VERSION__)) + bits);
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
std::string compiler_info( "MSVC " + std::string(TOSTRING(_MSC_FULL_VER)) );
|
std::string compiler_info( "MSVC " + std::string(TOSTRING(_MSC_FULL_VER)) + bits);
|
||||||
#elif defined(__clang__)
|
#elif defined(__clang__)
|
||||||
std::string compiler_info( "Clang " + std::string(TOSTRING(__clang_version__)) );
|
std::string compiler_info( "Clang " + std::string(TOSTRING(__clang_version__)) + bits);
|
||||||
#else
|
#else
|
||||||
std::string compiler_info( "unknown compiler" );
|
std::string compiler_info( "unknown compiler" );
|
||||||
#endif
|
#endif
|
||||||
|
@ -80,6 +88,7 @@ std::string LibraryInfo::info()
|
||||||
const char *env_font_path = getenv("OPENSCAD_FONT_PATH");
|
const char *env_font_path = getenv("OPENSCAD_FONT_PATH");
|
||||||
|
|
||||||
s << "OpenSCAD Version: " << TOSTRING(OPENSCAD_VERSION)
|
s << "OpenSCAD Version: " << TOSTRING(OPENSCAD_VERSION)
|
||||||
|
<< "\nSystem information: " << PlatformUtils::sysinfo()
|
||||||
<< "\nCompiler, build date: " << compiler_info << ", " << __DATE__
|
<< "\nCompiler, build date: " << compiler_info << ", " << __DATE__
|
||||||
<< "\nBoost version: " << BOOST_LIB_VERSION
|
<< "\nBoost version: " << BOOST_LIB_VERSION
|
||||||
<< "\nEigen version: " << EIGEN_WORLD_VERSION << "." << EIGEN_MAJOR_VERSION << "." << EIGEN_MINOR_VERSION
|
<< "\nEigen version: " << EIGEN_WORLD_VERSION << "." << EIGEN_MAJOR_VERSION << "." << EIGEN_MINOR_VERSION
|
||||||
|
@ -93,7 +102,7 @@ std::string LibraryInfo::info()
|
||||||
<< "\nGLib version: " << GLIB_MAJOR_VERSION << "." << GLIB_MINOR_VERSION << "." << GLIB_MICRO_VERSION
|
<< "\nGLib version: " << GLIB_MAJOR_VERSION << "." << GLIB_MINOR_VERSION << "." << GLIB_MICRO_VERSION
|
||||||
<< "\nApplication Path: " << PlatformUtils::applicationPath()
|
<< "\nApplication Path: " << PlatformUtils::applicationPath()
|
||||||
<< "\nDocuments Path: " << PlatformUtils::documentsPath()
|
<< "\nDocuments Path: " << PlatformUtils::documentsPath()
|
||||||
<< "\nResource Path: " << PlatformUtils::resourcesPath()
|
<< "\nResource Path: " << PlatformUtils::resourceBasePath()
|
||||||
<< "\nUser Library Path: " << PlatformUtils::userLibraryPath()
|
<< "\nUser Library Path: " << PlatformUtils::userLibraryPath()
|
||||||
<< "\nUser Config Path: " << PlatformUtils::userConfigPath()
|
<< "\nUser Config Path: " << PlatformUtils::userConfigPath()
|
||||||
<< "\nBackup Path: " << PlatformUtils::backupPath()
|
<< "\nBackup Path: " << PlatformUtils::backupPath()
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
|
#include "qtgettext.h"
|
||||||
#include "ui_LibraryInfoDialog.h"
|
#include "ui_LibraryInfoDialog.h"
|
||||||
|
|
||||||
class LibraryInfoDialog : public QDialog, public Ui::LibraryInfoDialog
|
class LibraryInfoDialog : public QDialog, public Ui::LibraryInfoDialog
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "qtgettext.h"
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
#include "ui_MainWindow.h"
|
#include "ui_MainWindow.h"
|
||||||
|
@ -13,6 +14,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
|
#include <QTime>
|
||||||
|
|
||||||
enum export_type_e {
|
enum export_type_e {
|
||||||
EXPORT_TYPE_UNKNOWN,
|
EXPORT_TYPE_UNKNOWN,
|
||||||
|
@ -39,6 +41,8 @@ public:
|
||||||
std::string autoReloadId;
|
std::string autoReloadId;
|
||||||
QTimer *waitAfterReloadTimer;
|
QTimer *waitAfterReloadTimer;
|
||||||
|
|
||||||
|
QTime renderingTime;
|
||||||
|
|
||||||
ModuleContext top_ctx;
|
ModuleContext top_ctx;
|
||||||
FileModule *root_module; // Result of parsing
|
FileModule *root_module; // Result of parsing
|
||||||
ModuleInstantiation root_inst; // Top level instance
|
ModuleInstantiation root_inst; // Top level instance
|
||||||
|
@ -67,6 +71,7 @@ public:
|
||||||
QAction *actionRecentFile[UIUtils::maxRecentFiles];
|
QAction *actionRecentFile[UIUtils::maxRecentFiles];
|
||||||
QMap<QString, QString> knownFileExtensions;
|
QMap<QString, QString> knownFileExtensions;
|
||||||
|
|
||||||
|
QLabel *versionLabel;
|
||||||
QWidget *editorDockTitleWidget;
|
QWidget *editorDockTitleWidget;
|
||||||
QWidget *consoleDockTitleWidget;
|
QWidget *consoleDockTitleWidget;
|
||||||
|
|
||||||
|
@ -112,6 +117,7 @@ private:
|
||||||
void show_examples();
|
void show_examples();
|
||||||
void setDockWidgetTitle(QDockWidget *dockWidget, QString prefix, bool topLevel);
|
void setDockWidgetTitle(QDockWidget *dockWidget, QString prefix, bool topLevel);
|
||||||
void addKeyboardShortCut(const QList<QAction *> &actions);
|
void addKeyboardShortCut(const QList<QAction *> &actions);
|
||||||
|
void updateStatusBar(class ProgressWidget *progressWidget);
|
||||||
|
|
||||||
EditorInterface *editor;
|
EditorInterface *editor;
|
||||||
|
|
||||||
|
|
|
@ -179,7 +179,7 @@
|
||||||
</property>
|
</property>
|
||||||
<widget class="QMenu" name="menuOpenRecent">
|
<widget class="QMenu" name="menuOpenRecent">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Open Recent</string>
|
<string>Recent Files</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menuExamples">
|
<widget class="QMenu" name="menuExamples">
|
||||||
|
@ -543,6 +543,9 @@
|
||||||
<property name="shortcut">
|
<property name="shortcut">
|
||||||
<string>Ctrl+Q</string>
|
<string>Ctrl+Q</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="menuRole">
|
||||||
|
<enum>QAction::QuitRole</enum>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="editActionUndo">
|
<action name="editActionUndo">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -955,6 +958,9 @@
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>About</string>
|
<string>About</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="menuRole">
|
||||||
|
<enum>QAction::AboutRole</enum>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="helpActionManual">
|
<action name="helpActionManual">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -983,6 +989,9 @@
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Preferences</string>
|
<string>Preferences</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="menuRole">
|
||||||
|
<enum>QAction::PreferencesRole</enum>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="editActionFind">
|
<action name="editActionFind">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
|
|
@ -4,17 +4,13 @@ GLView::GLView() {}
|
||||||
void GLView::setRenderer(Renderer* r) {}
|
void GLView::setRenderer(Renderer* r) {}
|
||||||
void GLView::initializeGL() {}
|
void GLView::initializeGL() {}
|
||||||
void GLView::resizeGL(int w, int h) {}
|
void GLView::resizeGL(int w, int h) {}
|
||||||
void GLView::setupGimbalCamPerspective() {}
|
void GLView::setCamera(const Camera &cam ) {assert(false && "not implemented");}
|
||||||
void GLView::setupGimbalCamOrtho(double distance, bool offset) {}
|
|
||||||
void GLView::setupVectorCamPerspective() {}
|
|
||||||
void GLView::setupVectorCamOrtho(bool offset) {}
|
|
||||||
void GLView::setCamera( Camera &cam ) {}
|
|
||||||
void GLView::paintGL() {}
|
void GLView::paintGL() {}
|
||||||
void GLView::vectorCamPaintGL() {}
|
void GLView::showSmallaxes(const Color4f &col) {}
|
||||||
void GLView::gimbalCamPaintGL() {}
|
void GLView::showAxes(const Color4f &col) {}
|
||||||
void GLView::showSmallaxes() {}
|
|
||||||
void GLView::showAxes() {}
|
|
||||||
void GLView::showCrosshairs() {}
|
void GLView::showCrosshairs() {}
|
||||||
|
void GLView::setColorScheme(const ColorScheme &cs){assert(false && "not implemented");}
|
||||||
|
void GLView::setColorScheme(const std::string &cs) {assert(false && "not implemented");}
|
||||||
|
|
||||||
#include "ThrownTogetherRenderer.h"
|
#include "ThrownTogetherRenderer.h"
|
||||||
|
|
||||||
|
@ -23,12 +19,16 @@ ThrownTogetherRenderer::ThrownTogetherRenderer(CSGChain *root_chain,
|
||||||
void ThrownTogetherRenderer::draw(bool /*showfaces*/, bool showedges) const {}
|
void ThrownTogetherRenderer::draw(bool /*showfaces*/, bool showedges) const {}
|
||||||
void ThrownTogetherRenderer::renderCSGChain(CSGChain *chain, bool
|
void ThrownTogetherRenderer::renderCSGChain(CSGChain *chain, bool
|
||||||
highlight, bool background, bool showedges, bool fberror) const {}
|
highlight, bool background, bool showedges, bool fberror) const {}
|
||||||
|
BoundingBox ThrownTogetherRenderer::getBoundingBox() const {assert(false && "not implemented");}
|
||||||
|
|
||||||
#include "CGALRenderer.h"
|
#include "CGALRenderer.h"
|
||||||
|
|
||||||
CGALRenderer::CGALRenderer(shared_ptr<const class Geometry> geom) {}
|
CGALRenderer::CGALRenderer(shared_ptr<const class Geometry> geom) {}
|
||||||
CGALRenderer::~CGALRenderer() {}
|
CGALRenderer::~CGALRenderer() {}
|
||||||
void CGALRenderer::draw(bool showfaces, bool showedges) const {}
|
void CGALRenderer::draw(bool showfaces, bool showedges) const {}
|
||||||
|
BoundingBox CGALRenderer::getBoundingBox() const {assert(false && "not implemented");}
|
||||||
|
void CGALRenderer::setColorScheme(const ColorScheme &cs){assert(false && "not implemented");}
|
||||||
|
|
||||||
|
|
||||||
#include "system-gl.h"
|
#include "system-gl.h"
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ const bool cull_backfaces = false;
|
||||||
const bool color_backfaces = false;
|
const bool color_backfaces = false;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
#include <windows.h> // For the CALLBACK macro
|
||||||
#define CGAL_GLU_TESS_CALLBACK CALLBACK
|
#define CGAL_GLU_TESS_CALLBACK CALLBACK
|
||||||
#else
|
#else
|
||||||
#define CGAL_GLU_TESS_CALLBACK
|
#define CGAL_GLU_TESS_CALLBACK
|
||||||
|
|
|
@ -11,6 +11,7 @@ For more info:
|
||||||
http://blogs.msdn.com/b/oldnewthing/archive/2006/12/04/1205831.aspx by Tom
|
http://blogs.msdn.com/b/oldnewthing/archive/2006/12/04/1205831.aspx by Tom
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#undef NOGDI
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,12 @@ void OpenCSGRenderer::renderCSGChain(CSGChain *chain, GLint *shaderinfo,
|
||||||
const Color4f &c = j_obj.color;
|
const Color4f &c = j_obj.color;
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glMultMatrixd(j_obj.matrix.data());
|
glMultMatrixd(j_obj.matrix.data());
|
||||||
csgmode_e csgmode = j_obj.type == CSGTerm::TYPE_DIFFERENCE ? CSGMODE_DIFFERENCE : CSGMODE_NORMAL;
|
csgmode_e csgmode = csgmode_e(
|
||||||
|
(highlight ?
|
||||||
|
CSGMODE_HIGHLIGHT :
|
||||||
|
(background ? CSGMODE_BACKGROUND : CSGMODE_NORMAL)) |
|
||||||
|
(j_obj.type == CSGTerm::TYPE_DIFFERENCE ? CSGMODE_DIFFERENCE : 0));
|
||||||
|
|
||||||
ColorMode colormode = COLORMODE_NONE;
|
ColorMode colormode = COLORMODE_NONE;
|
||||||
if (background) {
|
if (background) {
|
||||||
if (j_obj.flag & CSGTerm::FLAG_HIGHLIGHT) {
|
if (j_obj.flag & CSGTerm::FLAG_HIGHLIGHT) {
|
||||||
|
@ -99,11 +104,9 @@ void OpenCSGRenderer::renderCSGChain(CSGChain *chain, GLint *shaderinfo,
|
||||||
else {
|
else {
|
||||||
colormode = COLORMODE_BACKGROUND;
|
colormode = COLORMODE_BACKGROUND;
|
||||||
}
|
}
|
||||||
csgmode = csgmode_e(csgmode + 10);
|
|
||||||
} else if (j_obj.type == CSGTerm::TYPE_DIFFERENCE) {
|
} else if (j_obj.type == CSGTerm::TYPE_DIFFERENCE) {
|
||||||
if (j_obj.flag & CSGTerm::FLAG_HIGHLIGHT) {
|
if (j_obj.flag & CSGTerm::FLAG_HIGHLIGHT) {
|
||||||
colormode = COLORMODE_HIGHLIGHT;
|
colormode = COLORMODE_HIGHLIGHT;
|
||||||
csgmode = csgmode_e(csgmode + 20);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
colormode = COLORMODE_CUTOUT;
|
colormode = COLORMODE_CUTOUT;
|
||||||
|
@ -111,7 +114,6 @@ void OpenCSGRenderer::renderCSGChain(CSGChain *chain, GLint *shaderinfo,
|
||||||
} else {
|
} else {
|
||||||
if (j_obj.flag & CSGTerm::FLAG_HIGHLIGHT) {
|
if (j_obj.flag & CSGTerm::FLAG_HIGHLIGHT) {
|
||||||
colormode = COLORMODE_HIGHLIGHT;
|
colormode = COLORMODE_HIGHLIGHT;
|
||||||
csgmode = csgmode_e(csgmode + 20);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
colormode = COLORMODE_MATERIAL;
|
colormode = COLORMODE_MATERIAL;
|
||||||
|
@ -139,9 +141,12 @@ void OpenCSGRenderer::renderCSGChain(CSGChain *chain, GLint *shaderinfo,
|
||||||
|
|
||||||
prim->geom = i_obj.geom;
|
prim->geom = i_obj.geom;
|
||||||
prim->m = i_obj.matrix;
|
prim->m = i_obj.matrix;
|
||||||
prim->csgmode = i_obj.type == CSGTerm::TYPE_DIFFERENCE ? CSGMODE_DIFFERENCE : CSGMODE_NORMAL;
|
prim->csgmode = csgmode_e(
|
||||||
if (highlight) prim->csgmode = csgmode_e(prim->csgmode + 20);
|
(highlight ?
|
||||||
else if (background) prim->csgmode = csgmode_e(prim->csgmode + 10);
|
CSGMODE_HIGHLIGHT :
|
||||||
|
(background ? CSGMODE_BACKGROUND : CSGMODE_NORMAL)) |
|
||||||
|
(i_obj.type == CSGTerm::TYPE_DIFFERENCE ? CSGMODE_DIFFERENCE : 0));
|
||||||
|
|
||||||
primitives.push_back(prim);
|
primitives.push_back(prim);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "qtgettext.h"
|
||||||
#include "ui_OpenCSGWarningDialog.h"
|
#include "ui_OpenCSGWarningDialog.h"
|
||||||
|
|
||||||
class OpenCSGWarningDialog : public QDialog, public Ui::OpenCSGWarningDialog
|
class OpenCSGWarningDialog : public QDialog, public Ui::OpenCSGWarningDialog
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
#include "PlatformUtils.h"
|
#include "PlatformUtils.h"
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
std::string PlatformUtils::pathSeparatorChar()
|
std::string PlatformUtils::pathSeparatorChar()
|
||||||
|
@ -18,5 +22,49 @@ std::string PlatformUtils::userConfigPath()
|
||||||
return std::string([[appSupportDir path] UTF8String]) + std::string("/") + PlatformUtils::OPENSCAD_FOLDER_NAME;
|
return std::string([[appSupportDir path] UTF8String]) + std::string("/") + PlatformUtils::OPENSCAD_FOLDER_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned long PlatformUtils::stackLimit()
|
||||||
|
{
|
||||||
|
struct rlimit limit;
|
||||||
|
|
||||||
|
int ret = getrlimit(RLIMIT_STACK, &limit);
|
||||||
|
if (ret == 0) {
|
||||||
|
if (limit.rlim_cur > STACK_BUFFER_SIZE) {
|
||||||
|
return limit.rlim_cur - STACK_BUFFER_SIZE;
|
||||||
|
}
|
||||||
|
if (limit.rlim_max > STACK_BUFFER_SIZE) {
|
||||||
|
return limit.rlim_max - STACK_BUFFER_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return STACK_LIMIT_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PlatformUtils::sysinfo()
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
result += "Mac OS X ";
|
||||||
|
result += [[[NSProcessInfo processInfo] operatingSystemVersionString] UTF8String];
|
||||||
|
|
||||||
|
int64_t physical_memory;
|
||||||
|
int32_t numcpu;
|
||||||
|
size_t length64 = sizeof(int64_t);
|
||||||
|
size_t length32 = sizeof(int32_t);;
|
||||||
|
|
||||||
|
sysctlbyname("hw.memsize", &physical_memory, &length64, NULL, 0);
|
||||||
|
sysctlbyname("hw.physicalcpu", &numcpu, &length32, NULL, 0);
|
||||||
|
|
||||||
|
result += " ";
|
||||||
|
result += boost::lexical_cast<std::string>(numcpu);
|
||||||
|
result += " CPU";
|
||||||
|
if (numcpu > 1) result += "s";
|
||||||
|
|
||||||
|
result += " ";
|
||||||
|
result += PlatformUtils::toMemorySizeString(physical_memory, 2);
|
||||||
|
result += " RAM";
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void PlatformUtils::ensureStdIO(void) {}
|
void PlatformUtils::ensureStdIO(void) {}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,14 @@
|
||||||
|
#include <string>
|
||||||
|
#include <fstream>
|
||||||
|
#include <streambuf>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
|
||||||
|
#include <boost/regex.hpp>
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
|
|
||||||
#include "PlatformUtils.h"
|
#include "PlatformUtils.h"
|
||||||
#include "boosty.h"
|
#include "boosty.h"
|
||||||
|
|
||||||
|
@ -41,5 +52,126 @@ std::string PlatformUtils::userConfigPath()
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned long PlatformUtils::stackLimit()
|
||||||
|
{
|
||||||
|
struct rlimit limit;
|
||||||
|
|
||||||
|
int ret = getrlimit(RLIMIT_STACK, &limit);
|
||||||
|
if (ret == 0) {
|
||||||
|
if (limit.rlim_cur > STACK_BUFFER_SIZE) {
|
||||||
|
return limit.rlim_cur - STACK_BUFFER_SIZE;
|
||||||
|
}
|
||||||
|
if (limit.rlim_max > STACK_BUFFER_SIZE) {
|
||||||
|
return limit.rlim_max - STACK_BUFFER_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return STACK_LIMIT_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string readText(const std::string &path)
|
||||||
|
{
|
||||||
|
std::ifstream s(path.c_str());
|
||||||
|
s.seekg(0, std::ios::end);
|
||||||
|
if (s.fail() || s.tellg() > 4096) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
s.seekg(0, std::ios::beg);
|
||||||
|
|
||||||
|
std::string text((std::istreambuf_iterator<char>(s)), std::istreambuf_iterator<char>());
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check /etc/os-release as defined by systemd.
|
||||||
|
* @see http://0pointer.de/blog/projects/os-release.html
|
||||||
|
* @see http://www.freedesktop.org/software/systemd/man/os-release.html
|
||||||
|
* @return the PRETTY_NAME from the os-release file or an empty string.
|
||||||
|
*/
|
||||||
|
static std::string checkOsRelease()
|
||||||
|
{
|
||||||
|
std::string os_release(readText("/etc/os-release"));
|
||||||
|
|
||||||
|
boost::smatch results;
|
||||||
|
boost::regex pretty_name("^PRETTY_NAME=\"([^\"]+)\"");
|
||||||
|
if (boost::regex_search(os_release, results, pretty_name)) {
|
||||||
|
return results[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string checkEtcIssue()
|
||||||
|
{
|
||||||
|
std::string issue(readText("/etc/issue"));
|
||||||
|
|
||||||
|
boost::regex nl("\n.*$");
|
||||||
|
issue = boost::regex_replace(issue, nl, "");
|
||||||
|
boost::regex esc("\\\\.");
|
||||||
|
issue = boost::regex_replace(issue, esc, "");
|
||||||
|
boost::algorithm::trim(issue);
|
||||||
|
|
||||||
|
return issue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string detectDistribution()
|
||||||
|
{
|
||||||
|
std::string osrelease = checkOsRelease();
|
||||||
|
if (!osrelease.empty()) {
|
||||||
|
return osrelease;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string etcissue = checkEtcIssue();
|
||||||
|
if (!etcissue.empty()) {
|
||||||
|
return etcissue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PlatformUtils::sysinfo()
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
struct utsname osinfo;
|
||||||
|
if (uname(&osinfo) == 0) {
|
||||||
|
result += osinfo.sysname;
|
||||||
|
result += " ";
|
||||||
|
result += osinfo.release;
|
||||||
|
result += " ";
|
||||||
|
result += osinfo.version;
|
||||||
|
result += " ";
|
||||||
|
result += osinfo.machine;
|
||||||
|
} else {
|
||||||
|
result += "Unknown Linux";
|
||||||
|
}
|
||||||
|
|
||||||
|
long numcpu = sysconf(_SC_NPROCESSORS_ONLN);
|
||||||
|
if (numcpu > 0) {
|
||||||
|
result += " ";
|
||||||
|
result += boost::lexical_cast<std::string>(numcpu);
|
||||||
|
result += " CPU";
|
||||||
|
if (numcpu > 1) {
|
||||||
|
result += "s";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long pages = sysconf(_SC_PHYS_PAGES);
|
||||||
|
long pagesize = sysconf(_SC_PAGE_SIZE);
|
||||||
|
if ((pages > 0) && (pagesize > 0)) {
|
||||||
|
result += " ";
|
||||||
|
result += PlatformUtils::toMemorySizeString(pages * pagesize, 2);
|
||||||
|
result += " RAM";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string distribution = detectDistribution();
|
||||||
|
if (!distribution.empty()) {
|
||||||
|
result += " ";
|
||||||
|
result += distribution;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void PlatformUtils::ensureStdIO(void) {}
|
void PlatformUtils::ensureStdIO(void) {}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#ifndef _WIN32_WINNT
|
#ifndef _WIN32_WINNT
|
||||||
#define _WIN32_WINNT 0x0501
|
#define _WIN32_WINNT 0x0501
|
||||||
#endif
|
#endif
|
||||||
|
#undef NOGDI
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#ifndef _WIN32_IE
|
#ifndef _WIN32_IE
|
||||||
#define _WIN32_IE 0x0501 // SHGFP_TYPE_CURRENT
|
#define _WIN32_IE 0x0501 // SHGFP_TYPE_CURRENT
|
||||||
|
@ -60,11 +61,12 @@ static const std::string getFolderPath(int nFolder)
|
||||||
int result = SHGetFolderPathW( hwndOwner, nFolder, hToken, dwFlags, pszPath );
|
int result = SHGetFolderPathW( hwndOwner, nFolder, hToken, dwFlags, pszPath );
|
||||||
|
|
||||||
if (result == S_OK) {
|
if (result == S_OK) {
|
||||||
path = std::wstring( path.c_str() ); // strip extra NULLs
|
path = std::wstring( path.c_str() ); // strip extra NULLs
|
||||||
//std::wcerr << "wchar path:" << "\n";
|
// Use boost::filesystem to decide how to convert from wstring
|
||||||
const std::string retval = winapi_wstr_to_utf8( path );
|
// to string. Normally the path encoding is system local and
|
||||||
//PRINTB("Path found: %s",retval);
|
// we don't want to force conversion to UTF-8.
|
||||||
return retval;
|
fs::path p(path);
|
||||||
|
return p.string();
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
@ -92,6 +94,101 @@ std::string PlatformUtils::userConfigPath()
|
||||||
return retval + std::string("/") + PlatformUtils::OPENSCAD_FOLDER_NAME;
|
return retval + std::string("/") + PlatformUtils::OPENSCAD_FOLDER_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned long PlatformUtils::stackLimit()
|
||||||
|
{
|
||||||
|
return STACK_LIMIT_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
|
||||||
|
|
||||||
|
// see http://msdn.microsoft.com/en-us/library/windows/desktop/ms684139%28v=vs.85%29.aspx
|
||||||
|
static BOOL IsWow64()
|
||||||
|
{
|
||||||
|
BOOL bIsWow64 = FALSE;
|
||||||
|
|
||||||
|
//IsWow64Process is not available on all supported versions of Windows.
|
||||||
|
//Use GetModuleHandle to get a handle to the DLL that contains the function
|
||||||
|
//and GetProcAddress to get a pointer to the function if available.
|
||||||
|
LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process");
|
||||||
|
|
||||||
|
if (NULL != fnIsWow64Process) {
|
||||||
|
if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bIsWow64;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PlatformUtils::sysinfo()
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
OSVERSIONINFOEX osinfo;
|
||||||
|
osinfo.dwOSVersionInfoSize = sizeof(osinfo);
|
||||||
|
if (GetVersionEx((OSVERSIONINFO*)&osinfo) == 0) {
|
||||||
|
result += "Unknown Windows";
|
||||||
|
} else {
|
||||||
|
unsigned int version = osinfo.dwMajorVersion * 1000 + osinfo.dwMinorVersion;
|
||||||
|
if (osinfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
|
||||||
|
switch (version) {
|
||||||
|
case 5000:
|
||||||
|
result += "Windows 2000";
|
||||||
|
break;
|
||||||
|
case 5001:
|
||||||
|
result += "Windows XP";
|
||||||
|
break;
|
||||||
|
case 5002:
|
||||||
|
result += "Windows Server 2003";
|
||||||
|
break;
|
||||||
|
case 6000:
|
||||||
|
result += (osinfo.wProductType == VER_NT_WORKSTATION ? "Windows Vista" : "Windows Server 2008");
|
||||||
|
break;
|
||||||
|
case 6001:
|
||||||
|
result += (osinfo.wProductType == VER_NT_WORKSTATION ? "Windows 7" : "Windows Server 2008 R2");
|
||||||
|
break;
|
||||||
|
case 6002:
|
||||||
|
result += (osinfo.wProductType == VER_NT_WORKSTATION ? "Windows 8" : "Windows Server 2012");
|
||||||
|
break;
|
||||||
|
case 6003:
|
||||||
|
// For applications that have been manifested for Windows 8.1.
|
||||||
|
result += (osinfo.wProductType == VER_NT_WORKSTATION ? "Windows 8.1" : "Windows Server 2012 R2");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
boost::format fmt(" (v%d.%d)");
|
||||||
|
fmt % osinfo.dwMajorVersion % osinfo.dwMinorVersion;
|
||||||
|
result += fmt.str();
|
||||||
|
} else {
|
||||||
|
boost::format fmt("Unknown Windows (dwPlatformId = %d, dwMajorVersion = %d, dwMinorVersion = %d");
|
||||||
|
fmt % osinfo.dwPlatformId % osinfo.dwMajorVersion % osinfo.dwMinorVersion;
|
||||||
|
result += fmt.str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SYSTEM_INFO systeminfo;
|
||||||
|
bool isWow64 = IsWow64();
|
||||||
|
if (isWow64) {
|
||||||
|
GetNativeSystemInfo(&systeminfo);
|
||||||
|
} else {
|
||||||
|
GetSystemInfo(&systeminfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
int numcpu = systeminfo.dwNumberOfProcessors;
|
||||||
|
boost::format fmt(" %d CPU%s%s");
|
||||||
|
fmt % numcpu % (numcpu > 1 ? "s" : "") % (isWow64 ? " WOW64" : "");
|
||||||
|
result += fmt.str();
|
||||||
|
|
||||||
|
MEMORYSTATUSEX memoryinfo;
|
||||||
|
memoryinfo.dwLength = sizeof(memoryinfo);
|
||||||
|
if (GlobalMemoryStatusEx(&memoryinfo) != 0) {
|
||||||
|
result += " ";
|
||||||
|
result += PlatformUtils::toMemorySizeString(memoryinfo.ullTotalPhys, 2);
|
||||||
|
result += " RAM";
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
#include "PlatformUtils.h"
|
#include "PlatformUtils.h"
|
||||||
#include "boosty.h"
|
|
||||||
#include <Eigen/Core>
|
#ifdef INSTALL_SUFFIX
|
||||||
#ifdef USE_SCINTILLA_EDITOR
|
#define RESOURCE_FOLDER(path) path INSTALL_SUFFIX
|
||||||
#include <Qsci/qsciglobal.h>
|
#else
|
||||||
|
#define RESOURCE_FOLDER(path) path
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern std::vector<std::string> librarypath;
|
extern std::vector<std::string> librarypath;
|
||||||
|
@ -23,7 +25,6 @@ static std::string lookupResourcesPath()
|
||||||
fs::path resourcedir(applicationpath);
|
fs::path resourcedir(applicationpath);
|
||||||
PRINTDB("Looking up resource folder with application path '%s'", resourcedir.c_str());
|
PRINTDB("Looking up resource folder with application path '%s'", resourcedir.c_str());
|
||||||
|
|
||||||
#ifndef WIN32
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
const char *searchpath[] = {
|
const char *searchpath[] = {
|
||||||
"../Resources", // Resources can be bundled on Mac.
|
"../Resources", // Resources can be bundled on Mac.
|
||||||
|
@ -32,15 +33,24 @@ static std::string lookupResourcesPath()
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
const char *searchpath[] = {
|
#ifdef WIN32
|
||||||
"../share/openscad",
|
const char *searchpath[] = {
|
||||||
"../../share/openscad",
|
".", // Release location
|
||||||
|
RESOURCE_FOLDER("../share/openscad"), // MSYS2 location
|
||||||
|
"..", // Dev location
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
const char *searchpath[] = {
|
||||||
|
RESOURCE_FOLDER("../share/openscad"),
|
||||||
|
RESOURCE_FOLDER("../../share/openscad"),
|
||||||
".",
|
".",
|
||||||
"..",
|
"..",
|
||||||
"../..",
|
"../..",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
fs::path tmpdir;
|
fs::path tmpdir;
|
||||||
for (int a = 0;searchpath[a] != NULL;a++) {
|
for (int a = 0;searchpath[a] != NULL;a++) {
|
||||||
|
@ -55,7 +65,6 @@ static std::string lookupResourcesPath()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // !WIN32
|
|
||||||
|
|
||||||
// resourcedir defaults to applicationPath
|
// resourcedir defaults to applicationPath
|
||||||
std::string result = boosty::stringy(boosty::canonical(resourcedir));
|
std::string result = boosty::stringy(boosty::canonical(resourcedir));
|
||||||
|
@ -151,7 +160,7 @@ bool PlatformUtils::createBackupPath()
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the built-in read-only resources path
|
// This is the built-in read-only resources path
|
||||||
std::string PlatformUtils::resourcesPath()
|
std::string PlatformUtils::resourceBasePath()
|
||||||
{
|
{
|
||||||
if (!path_initialized) {
|
if (!path_initialized) {
|
||||||
throw std::runtime_error("PlatformUtils::resourcesPath(): application path not initialized!");
|
throw std::runtime_error("PlatformUtils::resourcesPath(): application path not initialized!");
|
||||||
|
@ -159,6 +168,21 @@ std::string PlatformUtils::resourcesPath()
|
||||||
return resourcespath;
|
return resourcespath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fs::path PlatformUtils::resourcePath(const std::string &resource)
|
||||||
|
{
|
||||||
|
fs::path base(resourceBasePath());
|
||||||
|
if (!fs::is_directory(base)) {
|
||||||
|
return fs::path();
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::path resource_dir = base / resource;
|
||||||
|
if (!fs::is_directory(resource_dir)) {
|
||||||
|
return fs::path();
|
||||||
|
}
|
||||||
|
|
||||||
|
return resource_dir;
|
||||||
|
}
|
||||||
|
|
||||||
int PlatformUtils::setenv(const char *name, const char *value, int overwrite)
|
int PlatformUtils::setenv(const char *name, const char *value, int overwrite)
|
||||||
{
|
{
|
||||||
#if defined(WIN32)
|
#if defined(WIN32)
|
||||||
|
@ -174,3 +198,25 @@ int PlatformUtils::setenv(const char *name, const char *value, int overwrite)
|
||||||
return ::setenv(name, value, overwrite);
|
return ::setenv(name, value, overwrite);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string PlatformUtils::toMemorySizeString(uint64_t bytes, int digits)
|
||||||
|
{
|
||||||
|
static const char *units[] = { "B", "kB", "MB", "GB", "TB", NULL };
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
double val = bytes;
|
||||||
|
while (true) {
|
||||||
|
if (val < 1024.0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (units[idx + 1] == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
val /= 1024.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::format fmt("%f %s");
|
||||||
|
fmt % boost::io::group(std::setprecision(digits), val) % units[idx];
|
||||||
|
return fmt.str();
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,11 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "boosty.h"
|
||||||
|
|
||||||
|
#define STACK_BUFFER_SIZE (64 * 1024)
|
||||||
|
#define STACK_LIMIT_DEFAULT (8 * 1024 * 1024 - STACK_BUFFER_SIZE)
|
||||||
|
|
||||||
namespace PlatformUtils {
|
namespace PlatformUtils {
|
||||||
extern const char *OPENSCAD_FOLDER_NAME;
|
extern const char *OPENSCAD_FOLDER_NAME;
|
||||||
|
|
||||||
|
@ -9,7 +14,8 @@ namespace PlatformUtils {
|
||||||
std::string applicationPath();
|
std::string applicationPath();
|
||||||
|
|
||||||
std::string documentsPath();
|
std::string documentsPath();
|
||||||
std::string resourcesPath();
|
std::string resourceBasePath();
|
||||||
|
fs::path resourcePath(const std::string& resource);
|
||||||
std::string userLibraryPath();
|
std::string userLibraryPath();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,6 +34,20 @@ namespace PlatformUtils {
|
||||||
std::string backupPath();
|
std::string backupPath();
|
||||||
bool createBackupPath();
|
bool createBackupPath();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a human readable text describing the operating system
|
||||||
|
* the application is currently running on. This is mainly intended
|
||||||
|
* to provide information for bug reports (e.g. to be included in
|
||||||
|
* the LibraryInfoDialog).
|
||||||
|
*
|
||||||
|
* If there is some error to retrieve the details, at least the
|
||||||
|
* OS type is reported based on what platform the application was
|
||||||
|
* built for.
|
||||||
|
*
|
||||||
|
* @return system information.
|
||||||
|
*/
|
||||||
|
std::string sysinfo();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Platform abstraction to set environment variables. Windows/MinGW
|
* Platform abstraction to set environment variables. Windows/MinGW
|
||||||
* does not support setenv(), but needs _putenv().
|
* does not support setenv(), but needs _putenv().
|
||||||
|
@ -38,6 +58,14 @@ namespace PlatformUtils {
|
||||||
*/
|
*/
|
||||||
int setenv(const char *name, const char *value, int overwrite);
|
int setenv(const char *name, const char *value, int overwrite);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return system defined stack limit. If the system does not define
|
||||||
|
* a specific limit, the platform specific code will select a value.
|
||||||
|
*
|
||||||
|
* @return maximum stack size in bytes.
|
||||||
|
*/
|
||||||
|
unsigned long stackLimit();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Single character separating path specifications in a list
|
* Single character separating path specifications in a list
|
||||||
* (e.g. OPENSCADPATH). On Windows that's ';' and on most other
|
* (e.g. OPENSCADPATH). On Windows that's ';' and on most other
|
||||||
|
@ -51,4 +79,10 @@ namespace PlatformUtils {
|
||||||
* Currently limited to MS Windows GUI application console only.
|
* Currently limited to MS Windows GUI application console only.
|
||||||
*/
|
*/
|
||||||
void ensureStdIO(void);
|
void ensureStdIO(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the number of bytes to a human readable string with
|
||||||
|
* a given number of digits.
|
||||||
|
*/
|
||||||
|
std::string toMemorySizeString(uint64_t bytes, int digits);
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,6 +105,7 @@ mark_domains(CDT &cdt)
|
||||||
*/
|
*/
|
||||||
PolySet *Polygon2d::tessellate() const
|
PolySet *Polygon2d::tessellate() const
|
||||||
{
|
{
|
||||||
|
PRINTDB("Polygon2d::tessellate(): %d outlines", this->outlines().size());
|
||||||
PolySet *polyset = new PolySet(*this);
|
PolySet *polyset = new PolySet(*this);
|
||||||
|
|
||||||
Polygon2DCGAL::CDT cdt; // Uses a constrained Delaunay triangulator.
|
Polygon2DCGAL::CDT cdt; // Uses a constrained Delaunay triangulator.
|
||||||
|
|
|
@ -11,7 +11,10 @@
|
||||||
|
|
||||||
We can store sanitized vs. unsanitized polygons. Sanitized polygons
|
We can store sanitized vs. unsanitized polygons. Sanitized polygons
|
||||||
will have opposite winding order for holes and is guaranteed to not
|
will have opposite winding order for holes and is guaranteed to not
|
||||||
have intersecting geometry. Sanitization is typically done by ClipperUtils.
|
have intersecting geometry. The winding order will be counter-clockwise
|
||||||
|
for positive outlines and clockwise for holes. Sanitization is typically
|
||||||
|
done by ClipperUtils, but if you create geometry which you know is sanitized,
|
||||||
|
the flag can be set manually.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
size_t Polygon2d::memsize() const
|
size_t Polygon2d::memsize() const
|
||||||
|
@ -56,7 +59,7 @@ bool Polygon2d::isEmpty() const
|
||||||
void Polygon2d::transform(const Transform2d &mat)
|
void Polygon2d::transform(const Transform2d &mat)
|
||||||
{
|
{
|
||||||
if (mat.matrix().determinant() == 0) {
|
if (mat.matrix().determinant() == 0) {
|
||||||
PRINT("Warning: Scaling a 2D object with 0 - removing object");
|
PRINT("WARNING: Scaling a 2D object with 0 - removing object");
|
||||||
this->theoutlines.clear();
|
this->theoutlines.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,55 @@ Preferences *Preferences::instance = NULL;
|
||||||
const char * Preferences::featurePropertyName = "FeatureProperty";
|
const char * Preferences::featurePropertyName = "FeatureProperty";
|
||||||
Q_DECLARE_METATYPE(Feature *);
|
Q_DECLARE_METATYPE(Feature *);
|
||||||
|
|
||||||
|
class SettingsReader : public Settings::Visitor
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
const Value getValue(const Settings::SettingsEntry& entry, const std::string& value) const {
|
||||||
|
if (value.empty()) {
|
||||||
|
return entry.defaultValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
switch (entry.defaultValue().type()) {
|
||||||
|
case Value::STRING:
|
||||||
|
return Value(value);
|
||||||
|
case Value::NUMBER:
|
||||||
|
return Value(boost::lexical_cast<int>(value));
|
||||||
|
case Value::BOOL:
|
||||||
|
return Value(boost::lexical_cast<bool>(value));
|
||||||
|
default:
|
||||||
|
assert(false && "invalid value type for settings");
|
||||||
|
}
|
||||||
|
} catch (const boost::bad_lexical_cast& e) {
|
||||||
|
return entry.defaultValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void handle(Settings::SettingsEntry& entry) const {
|
||||||
|
Settings::Settings *s = Settings::Settings::inst();
|
||||||
|
|
||||||
|
std::string key = entry.category() + "/" + entry.name();
|
||||||
|
std::string value = settings.value(QString::fromStdString(key)).toString().toStdString();
|
||||||
|
s->set(entry, getValue(entry, value));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SettingsWriter : public Settings::Visitor
|
||||||
|
{
|
||||||
|
virtual void handle(Settings::SettingsEntry& entry) const {
|
||||||
|
Settings::Settings *s = Settings::Settings::inst();
|
||||||
|
|
||||||
|
QSettings settings;
|
||||||
|
QString key = QString::fromStdString(entry.category() + "/" + entry.name());
|
||||||
|
if (entry.is_default()) {
|
||||||
|
settings.remove(key);
|
||||||
|
} else {
|
||||||
|
Value value = s->get(entry);
|
||||||
|
settings.setValue(key, QString::fromStdString(value.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Preferences::Preferences(QWidget *parent) : QMainWindow(parent)
|
Preferences::Preferences(QWidget *parent) : QMainWindow(parent)
|
||||||
{
|
{
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
|
@ -108,6 +157,7 @@ void Preferences::init() {
|
||||||
this->defaultmap["advanced/undockableWindows"] = false;
|
this->defaultmap["advanced/undockableWindows"] = false;
|
||||||
this->defaultmap["advanced/reorderWindows"] = true;
|
this->defaultmap["advanced/reorderWindows"] = true;
|
||||||
this->defaultmap["launcher/showOnStartup"] = true;
|
this->defaultmap["launcher/showOnStartup"] = true;
|
||||||
|
this->defaultmap["advanced/localization"] = true;
|
||||||
|
|
||||||
// Toolbar
|
// Toolbar
|
||||||
QActionGroup *group = new QActionGroup(this);
|
QActionGroup *group = new QActionGroup(this);
|
||||||
|
@ -139,6 +189,22 @@ void Preferences::init() {
|
||||||
#endif
|
#endif
|
||||||
this->polysetCacheSizeEdit->setValidator(validator);
|
this->polysetCacheSizeEdit->setValidator(validator);
|
||||||
this->opencsgLimitEdit->setValidator(validator);
|
this->opencsgLimitEdit->setValidator(validator);
|
||||||
|
|
||||||
|
initComboBox(this->comboBoxIndentUsing, Settings::Settings::indentStyle);
|
||||||
|
initComboBox(this->comboBoxLineWrap, Settings::Settings::lineWrap);
|
||||||
|
initComboBox(this->comboBoxLineWrapIndentationStyle, Settings::Settings::lineWrapIndentationStyle);
|
||||||
|
initComboBox(this->comboBoxLineWrapVisualizationEnd, Settings::Settings::lineWrapVisualizationEnd);
|
||||||
|
initComboBox(this->comboBoxLineWrapVisualizationStart, Settings::Settings::lineWrapVisualizationBegin);
|
||||||
|
initComboBox(this->comboBoxShowWhitespace, Settings::Settings::showWhitespace);
|
||||||
|
initComboBox(this->comboBoxTabKeyFunction, Settings::Settings::tabKeyFunction);
|
||||||
|
initSpinBox(this->spinBoxIndentationWidth, Settings::Settings::indentationWidth);
|
||||||
|
initSpinBox(this->spinBoxLineWrapIndentationIndent, Settings::Settings::lineWrapIndentation);
|
||||||
|
initSpinBox(this->spinBoxShowWhitespaceSize, Settings::Settings::showWhitespaceSize);
|
||||||
|
initSpinBox(this->spinBoxTabWidth, Settings::Settings::tabWidth);
|
||||||
|
|
||||||
|
SettingsReader settingsReader;
|
||||||
|
Settings::Settings::inst()->visit(settingsReader);
|
||||||
|
emit editorConfigChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
Preferences::~Preferences()
|
Preferences::~Preferences()
|
||||||
|
@ -380,6 +446,12 @@ void Preferences::on_opencsgLimitEdit_textChanged(const QString &text)
|
||||||
// FIXME: Set this globally?
|
// FIXME: Set this globally?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Preferences::on_localizationCheckBox_toggled(bool state)
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
settings.setValue("advanced/localization", state);
|
||||||
|
}
|
||||||
|
|
||||||
void Preferences::on_forceGoldfeatherBox_toggled(bool state)
|
void Preferences::on_forceGoldfeatherBox_toggled(bool state)
|
||||||
{
|
{
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
|
@ -393,13 +465,101 @@ void Preferences::on_mouseWheelZoomBox_toggled(bool state)
|
||||||
settings.setValue("editor/ctrlmousewheelzoom", state);
|
settings.setValue("editor/ctrlmousewheelzoom", state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void Preferences::on_launcherBox_toggled(bool state)
|
||||||
Preferences::on_launcherBox_toggled(bool state)
|
|
||||||
{
|
{
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
settings.setValue("launcher/showOnStartup", state);
|
settings.setValue("launcher/showOnStartup", state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Preferences::on_spinBoxIndentationWidth_valueChanged(int val)
|
||||||
|
{
|
||||||
|
Settings::Settings::inst()->set(Settings::Settings::indentationWidth, Value(val));
|
||||||
|
writeSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Preferences::on_spinBoxTabWidth_valueChanged(int val)
|
||||||
|
{
|
||||||
|
Settings::Settings::inst()->set(Settings::Settings::tabWidth, Value(val));
|
||||||
|
writeSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Preferences::on_comboBoxLineWrap_activated(int val)
|
||||||
|
{
|
||||||
|
applyComboBox(comboBoxLineWrap, val, Settings::Settings::lineWrap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Preferences::on_comboBoxLineWrapIndentationStyle_activated(int val)
|
||||||
|
{
|
||||||
|
applyComboBox(comboBoxLineWrapIndentationStyle, val, Settings::Settings::lineWrapIndentationStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Preferences::on_spinBoxLineWrapIndentationIndent_valueChanged(int val)
|
||||||
|
{
|
||||||
|
Settings::Settings::inst()->set(Settings::Settings::lineWrapIndentation, Value(val));
|
||||||
|
writeSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Preferences::on_comboBoxLineWrapVisualizationStart_activated(int val)
|
||||||
|
{
|
||||||
|
applyComboBox(comboBoxLineWrapVisualizationStart, val, Settings::Settings::lineWrapVisualizationBegin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Preferences::on_comboBoxLineWrapVisualizationEnd_activated(int val)
|
||||||
|
{
|
||||||
|
applyComboBox(comboBoxLineWrapVisualizationEnd, val, Settings::Settings::lineWrapVisualizationEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Preferences::on_comboBoxShowWhitespace_activated(int val)
|
||||||
|
{
|
||||||
|
applyComboBox(comboBoxShowWhitespace, val, Settings::Settings::showWhitespace);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Preferences::on_spinBoxShowWhitespaceSize_valueChanged(int val)
|
||||||
|
{
|
||||||
|
Settings::Settings::inst()->set(Settings::Settings::showWhitespaceSize, Value(val));
|
||||||
|
writeSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Preferences::on_checkBoxAutoIndent_toggled(bool val)
|
||||||
|
{
|
||||||
|
Settings::Settings::inst()->set(Settings::Settings::autoIndent, Value(val));
|
||||||
|
writeSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Preferences::on_comboBoxIndentUsing_activated(int val)
|
||||||
|
{
|
||||||
|
applyComboBox(comboBoxIndentUsing, val, Settings::Settings::indentStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Preferences::on_comboBoxTabKeyFunction_activated(int val)
|
||||||
|
{
|
||||||
|
applyComboBox(comboBoxTabKeyFunction, val, Settings::Settings::tabKeyFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Preferences::on_checkBoxHighlightCurrentLine_toggled(bool val)
|
||||||
|
{
|
||||||
|
Settings::Settings::inst()->set(Settings::Settings::highlightCurrentLine, Value(val));
|
||||||
|
writeSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Preferences::on_checkBoxEnableBraceMatching_toggled(bool val)
|
||||||
|
{
|
||||||
|
Settings::Settings::inst()->set(Settings::Settings::enableBraceMatching, Value(val));
|
||||||
|
writeSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Preferences::writeSettings()
|
||||||
|
{
|
||||||
|
SettingsWriter settingsWriter;
|
||||||
|
Settings::Settings::inst()->visit(settingsWriter);
|
||||||
|
fireEditorConfigChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Preferences::fireEditorConfigChanged() const
|
||||||
|
{
|
||||||
|
emit editorConfigChanged();
|
||||||
|
}
|
||||||
|
|
||||||
void Preferences::keyPressEvent(QKeyEvent *e)
|
void Preferences::keyPressEvent(QKeyEvent *e)
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
|
@ -486,12 +646,75 @@ void Preferences::updateGUI()
|
||||||
this->cgalCacheSizeEdit->setText(getValue("advanced/cgalCacheSize").toString());
|
this->cgalCacheSizeEdit->setText(getValue("advanced/cgalCacheSize").toString());
|
||||||
this->polysetCacheSizeEdit->setText(getValue("advanced/polysetCacheSize").toString());
|
this->polysetCacheSizeEdit->setText(getValue("advanced/polysetCacheSize").toString());
|
||||||
this->opencsgLimitEdit->setText(getValue("advanced/openCSGLimit").toString());
|
this->opencsgLimitEdit->setText(getValue("advanced/openCSGLimit").toString());
|
||||||
|
this->localizationCheckBox->setChecked(getValue("advanced/localization").toBool());
|
||||||
this->forceGoldfeatherBox->setChecked(getValue("advanced/forceGoldfeather").toBool());
|
this->forceGoldfeatherBox->setChecked(getValue("advanced/forceGoldfeather").toBool());
|
||||||
this->mdiCheckBox->setChecked(getValue("advanced/mdi").toBool());
|
this->mdiCheckBox->setChecked(getValue("advanced/mdi").toBool());
|
||||||
this->reorderCheckBox->setChecked(getValue("advanced/reorderWindows").toBool());
|
this->reorderCheckBox->setChecked(getValue("advanced/reorderWindows").toBool());
|
||||||
this->undockCheckBox->setChecked(getValue("advanced/undockableWindows").toBool());
|
this->undockCheckBox->setChecked(getValue("advanced/undockableWindows").toBool());
|
||||||
this->undockCheckBox->setEnabled(this->reorderCheckBox->isChecked());
|
this->undockCheckBox->setEnabled(this->reorderCheckBox->isChecked());
|
||||||
this->launcherBox->setChecked(getValue("launcher/showOnStartup").toBool());
|
this->launcherBox->setChecked(getValue("launcher/showOnStartup").toBool());
|
||||||
|
|
||||||
|
Settings::Settings *s = Settings::Settings::inst();
|
||||||
|
updateComboBox(this->comboBoxLineWrap, Settings::Settings::lineWrap);
|
||||||
|
updateComboBox(this->comboBoxLineWrapIndentationStyle, Settings::Settings::lineWrapIndentationStyle);
|
||||||
|
updateComboBox(this->comboBoxLineWrapVisualizationStart, Settings::Settings::lineWrapVisualizationBegin);
|
||||||
|
updateComboBox(this->comboBoxLineWrapVisualizationEnd, Settings::Settings::lineWrapVisualizationEnd);
|
||||||
|
updateComboBox(this->comboBoxShowWhitespace, Settings::Settings::showWhitespace);
|
||||||
|
updateComboBox(this->comboBoxIndentUsing, Settings::Settings::indentStyle);
|
||||||
|
updateComboBox(this->comboBoxTabKeyFunction, Settings::Settings::tabKeyFunction);
|
||||||
|
this->spinBoxIndentationWidth->setValue(s->get(Settings::Settings::indentationWidth).toDouble());
|
||||||
|
this->spinBoxTabWidth->setValue(s->get(Settings::Settings::tabWidth).toDouble());
|
||||||
|
this->spinBoxLineWrapIndentationIndent->setValue(s->get(Settings::Settings::lineWrapIndentation).toDouble());
|
||||||
|
this->spinBoxShowWhitespaceSize->setValue(s->get(Settings::Settings::showWhitespaceSize).toDouble());
|
||||||
|
this->checkBoxAutoIndent->setChecked(s->get(Settings::Settings::autoIndent).toBool());
|
||||||
|
this->checkBoxHighlightCurrentLine->setChecked(s->get(Settings::Settings::highlightCurrentLine).toBool());
|
||||||
|
this->checkBoxEnableBraceMatching->setChecked(s->get(Settings::Settings::enableBraceMatching).toBool());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Preferences::initComboBox(QComboBox *comboBox, const Settings::SettingsEntry& entry)
|
||||||
|
{
|
||||||
|
comboBox->clear();
|
||||||
|
Value::VectorType vector = entry.range().toVector();
|
||||||
|
for (Value::VectorType::iterator it = vector.begin();it != vector.end();it++) {
|
||||||
|
QString val = QString::fromStdString((*it)[0].toString());
|
||||||
|
QString text = QString::fromStdString((*it)[1].toString());
|
||||||
|
comboBox->addItem(text, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Preferences::initSpinBox(QSpinBox *spinBox, const Settings::SettingsEntry& entry)
|
||||||
|
{
|
||||||
|
Value::RangeType range = entry.range().toRange();
|
||||||
|
spinBox->setMinimum(range.begin_value());
|
||||||
|
spinBox->setMaximum(range.end_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Preferences::updateComboBox(QComboBox *comboBox, const Settings::SettingsEntry& entry)
|
||||||
|
{
|
||||||
|
Settings::Settings *s = Settings::Settings::inst();
|
||||||
|
|
||||||
|
Value value = s->get(entry);
|
||||||
|
QString text = QString::fromStdString(value.toString());
|
||||||
|
int idx = comboBox->findData(text);
|
||||||
|
if (idx >= 0) {
|
||||||
|
comboBox->setCurrentIndex(idx);
|
||||||
|
} else {
|
||||||
|
Value defaultValue = entry.defaultValue();
|
||||||
|
QString defaultText = QString::fromStdString(defaultValue.toString());
|
||||||
|
int defIdx = comboBox->findData(defaultText);
|
||||||
|
if (defIdx >= 0) {
|
||||||
|
comboBox->setCurrentIndex(defIdx);
|
||||||
|
} else {
|
||||||
|
comboBox->setCurrentIndex(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Preferences::applyComboBox(QComboBox *comboBox, int val, Settings::SettingsEntry& entry)
|
||||||
|
{
|
||||||
|
QString s = comboBox->itemData(val).toString();
|
||||||
|
Settings::Settings::inst()->set(entry, Value(s.toStdString()));
|
||||||
|
writeSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Preferences::apply() const
|
void Preferences::apply() const
|
||||||
|
|
|
@ -2,7 +2,10 @@
|
||||||
|
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
|
|
||||||
|
#include "qtgettext.h"
|
||||||
#include "ui_Preferences.h"
|
#include "ui_Preferences.h"
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
class Preferences : public QMainWindow, public Ui::Preferences
|
class Preferences : public QMainWindow, public Ui::Preferences
|
||||||
{
|
{
|
||||||
|
@ -17,6 +20,7 @@ public:
|
||||||
QVariant getValue(const QString &key) const;
|
QVariant getValue(const QString &key) const;
|
||||||
void init();
|
void init();
|
||||||
void apply() const;
|
void apply() const;
|
||||||
|
void fireEditorConfigChanged() const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void actionTriggered(class QAction *);
|
void actionTriggered(class QAction *);
|
||||||
|
@ -32,6 +36,7 @@ public slots:
|
||||||
void on_opencsgLimitEdit_textChanged(const QString &);
|
void on_opencsgLimitEdit_textChanged(const QString &);
|
||||||
void on_forceGoldfeatherBox_toggled(bool);
|
void on_forceGoldfeatherBox_toggled(bool);
|
||||||
void on_mouseWheelZoomBox_toggled(bool);
|
void on_mouseWheelZoomBox_toggled(bool);
|
||||||
|
void on_localizationCheckBox_toggled(bool);
|
||||||
void on_updateCheckBox_toggled(bool);
|
void on_updateCheckBox_toggled(bool);
|
||||||
void on_snapshotCheckBox_toggled(bool);
|
void on_snapshotCheckBox_toggled(bool);
|
||||||
void on_mdiCheckBox_toggled(bool);
|
void on_mdiCheckBox_toggled(bool);
|
||||||
|
@ -41,6 +46,30 @@ public slots:
|
||||||
void on_launcherBox_toggled(bool);
|
void on_launcherBox_toggled(bool);
|
||||||
void on_editorType_editTextChanged(const QString &);
|
void on_editorType_editTextChanged(const QString &);
|
||||||
|
|
||||||
|
//
|
||||||
|
// editor settings
|
||||||
|
//
|
||||||
|
|
||||||
|
// Indentation
|
||||||
|
void on_checkBoxAutoIndent_toggled(bool);
|
||||||
|
void on_comboBoxIndentUsing_activated(int);
|
||||||
|
void on_spinBoxIndentationWidth_valueChanged(int);
|
||||||
|
void on_spinBoxTabWidth_valueChanged(int);
|
||||||
|
void on_comboBoxTabKeyFunction_activated(int);
|
||||||
|
void on_comboBoxShowWhitespace_activated(int);
|
||||||
|
void on_spinBoxShowWhitespaceSize_valueChanged(int);
|
||||||
|
|
||||||
|
// Line wrap
|
||||||
|
void on_comboBoxLineWrap_activated(int);
|
||||||
|
void on_comboBoxLineWrapIndentationStyle_activated(int);
|
||||||
|
void on_spinBoxLineWrapIndentationIndent_valueChanged(int);
|
||||||
|
void on_comboBoxLineWrapVisualizationStart_activated(int);
|
||||||
|
void on_comboBoxLineWrapVisualizationEnd_activated(int);
|
||||||
|
|
||||||
|
// Display
|
||||||
|
void on_checkBoxHighlightCurrentLine_toggled(bool);
|
||||||
|
void on_checkBoxEnableBraceMatching_toggled(bool);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void requestRedraw() const;
|
void requestRedraw() const;
|
||||||
void updateMdiMode(bool mdi) const;
|
void updateMdiMode(bool mdi) const;
|
||||||
|
@ -51,6 +80,7 @@ signals:
|
||||||
void openCSGSettingsChanged() const;
|
void openCSGSettingsChanged() const;
|
||||||
void syntaxHighlightChanged(const QString &s) const;
|
void syntaxHighlightChanged(const QString &s) const;
|
||||||
void editorTypeChanged(const QString &type);
|
void editorTypeChanged(const QString &type);
|
||||||
|
void editorConfigChanged() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Preferences(QWidget *parent = NULL);
|
Preferences(QWidget *parent = NULL);
|
||||||
|
@ -58,8 +88,18 @@ private:
|
||||||
void updateGUI();
|
void updateGUI();
|
||||||
void removeDefaultSettings();
|
void removeDefaultSettings();
|
||||||
void setupFeaturesPage();
|
void setupFeaturesPage();
|
||||||
|
void writeSettings();
|
||||||
void addPrefPage(QActionGroup *group, QAction *action, QWidget *widget);
|
void addPrefPage(QActionGroup *group, QAction *action, QWidget *widget);
|
||||||
|
|
||||||
|
/** Initialize combobox list values from the settings range values */
|
||||||
|
void initComboBox(QComboBox *comboBox, const Settings::SettingsEntry& entry);
|
||||||
|
/** Initialize spinbox min/max values from the settings range values */
|
||||||
|
void initSpinBox(QSpinBox *spinBox, const Settings::SettingsEntry& entry);
|
||||||
|
/** Update combobox from current settings */
|
||||||
|
void updateComboBox(QComboBox *comboBox, const Settings::SettingsEntry& entry);
|
||||||
|
/** Set value from combobox to settings */
|
||||||
|
void applyComboBox(QComboBox *comboBox, int val, Settings::SettingsEntry& entry);
|
||||||
|
|
||||||
QSettings::SettingsMap defaultmap;
|
QSettings::SettingsMap defaultmap;
|
||||||
QHash<const QAction *, QWidget *> prefPages;
|
QHash<const QAction *, QWidget *> prefPages;
|
||||||
|
|
||||||
|
|
1420
src/Preferences.ui
1420
src/Preferences.ui
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "qtgettext.h"
|
||||||
#include "ui_ProgressWidget.h"
|
#include "ui_ProgressWidget.h"
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "qtgettext.h"
|
||||||
#include "QGLView.h"
|
#include "QGLView.h"
|
||||||
#include "Preferences.h"
|
#include "Preferences.h"
|
||||||
#include "renderer.h"
|
#include "renderer.h"
|
||||||
|
@ -63,7 +64,6 @@ static bool running_under_wine = false;
|
||||||
|
|
||||||
void QGLView::init()
|
void QGLView::init()
|
||||||
{
|
{
|
||||||
cam.type = Camera::GIMBAL;
|
|
||||||
resetView();
|
resetView();
|
||||||
|
|
||||||
this->mouse_drag_active = false;
|
this->mouse_drag_active = false;
|
||||||
|
@ -83,9 +83,7 @@ void QGLView::init()
|
||||||
|
|
||||||
void QGLView::resetView()
|
void QGLView::resetView()
|
||||||
{
|
{
|
||||||
cam.object_rot << 35, 0, -25;
|
cam.resetView();
|
||||||
cam.object_trans << 0, 0, 0;
|
|
||||||
cam.viewer_distance = 140;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QGLView::viewAll()
|
void QGLView::viewAll()
|
||||||
|
@ -110,7 +108,7 @@ std::string QGLView::getRendererInfo() const
|
||||||
{
|
{
|
||||||
std::string glewinfo = glew_dump();
|
std::string glewinfo = glew_dump();
|
||||||
std::string glextlist = glew_extensions_dump();
|
std::string glextlist = glew_extensions_dump();
|
||||||
return glewinfo + std::string("\nUsing QGLWidget\n\n") + glextlist;
|
return glewinfo + std::string(_("\nUsing QGLWidget\n\n")) + glextlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_OPENCSG
|
#ifdef ENABLE_OPENCSG
|
||||||
|
@ -127,19 +125,19 @@ void QGLView::display_opencsg_warning_dialog()
|
||||||
|
|
||||||
QString message;
|
QString message;
|
||||||
if (this->is_opencsg_capable) {
|
if (this->is_opencsg_capable) {
|
||||||
message += "Warning: You may experience OpenCSG rendering errors.\n\n";
|
message += _("Warning: You may experience OpenCSG rendering errors.\n\n");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
message += "Warning: Missing OpenGL capabilities for OpenCSG - OpenCSG has been disabled.\n\n";
|
message += _("Warning: Missing OpenGL capabilities for OpenCSG - OpenCSG has been disabled.\n\n");
|
||||||
dialog->enableOpenCSGBox->hide();
|
dialog->enableOpenCSGBox->hide();
|
||||||
}
|
}
|
||||||
message += "It is highly recommended to use OpenSCAD on a system with "
|
message += _("It is highly recommended to use OpenSCAD on a system with "
|
||||||
"OpenGL 2.0 or later.\n"
|
"OpenGL 2.0 or later.\n"
|
||||||
"Your renderer information is as follows:\n";
|
"Your renderer information is as follows:\n");
|
||||||
QString rendererinfo;
|
QString rendererinfo;
|
||||||
rendererinfo.sprintf("GLEW version %s\n"
|
rendererinfo.sprintf(_("GLEW version %s\n"
|
||||||
"%s (%s)\n"
|
"%s (%s)\n"
|
||||||
"OpenGL version %s\n",
|
"OpenGL version %s\n"),
|
||||||
glewGetString(GLEW_VERSION),
|
glewGetString(GLEW_VERSION),
|
||||||
glGetString(GL_RENDERER), glGetString(GL_VENDOR),
|
glGetString(GL_RENDERER), glGetString(GL_VENDOR),
|
||||||
glGetString(GL_VERSION));
|
glGetString(GL_VERSION));
|
||||||
|
@ -163,16 +161,9 @@ void QGLView::paintGL()
|
||||||
GLView::paintGL();
|
GLView::paintGL();
|
||||||
|
|
||||||
if (statusLabel) {
|
if (statusLabel) {
|
||||||
QString msg;
|
|
||||||
|
|
||||||
Camera nc(cam);
|
Camera nc(cam);
|
||||||
nc.gimbalDefaultTranslate();
|
nc.gimbalDefaultTranslate();
|
||||||
msg.sprintf("Viewport: translate = [ %.2f %.2f %.2f ], rotate = [ %.2f %.2f %.2f ], distance = %.2f",
|
statusLabel->setText(QString::fromStdString(nc.statusText()));
|
||||||
nc.object_trans.x(), nc.object_trans.y(), nc.object_trans.z(),
|
|
||||||
nc.object_rot.x(), nc.object_rot.y(), nc.object_rot.z(),
|
|
||||||
nc.viewer_distance );
|
|
||||||
|
|
||||||
statusLabel->setText(msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (running_under_wine) swapBuffers();
|
if (running_under_wine) swapBuffers();
|
||||||
|
@ -251,11 +242,11 @@ void QGLView::mouseMoveEvent(QMouseEvent *event)
|
||||||
// Middle button pans in the xy plane
|
// Middle button pans in the xy plane
|
||||||
// Shift-right and Shift-middle zooms
|
// Shift-right and Shift-middle zooms
|
||||||
if ((QApplication::keyboardModifiers() & Qt::ShiftModifier) != 0) {
|
if ((QApplication::keyboardModifiers() & Qt::ShiftModifier) != 0) {
|
||||||
cam.viewer_distance += (GLdouble)dy;
|
cam.zoom(-12.0 * dy);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
double mx = +(dx) * cam.viewer_distance/1000;
|
double mx = +(dx) * 3.0 * cam.zoomValue() / QWidget::width();
|
||||||
double mz = -(dy) * cam.viewer_distance/1000;
|
double mz = -(dy) * 3.0 * cam.zoomValue() / QWidget::height();
|
||||||
|
|
||||||
double my = 0;
|
double my = 0;
|
||||||
#if (QT_VERSION < QT_VERSION_CHECK(4, 7, 0))
|
#if (QT_VERSION < QT_VERSION_CHECK(4, 7, 0))
|
||||||
|
|
|
@ -74,12 +74,15 @@ void ThrownTogetherRenderer::renderCSGChain(CSGChain *chain, bool highlight,
|
||||||
const Color4f &c = obj.color;
|
const Color4f &c = obj.color;
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glMultMatrixd(m.data());
|
glMultMatrixd(m.data());
|
||||||
csgmode_e csgmode = obj.type == CSGTerm::TYPE_DIFFERENCE ? CSGMODE_DIFFERENCE : CSGMODE_NORMAL;
|
csgmode_e csgmode = csgmode_e(
|
||||||
|
(highlight ?
|
||||||
|
CSGMODE_HIGHLIGHT :
|
||||||
|
(background ? CSGMODE_BACKGROUND : CSGMODE_NORMAL)) |
|
||||||
|
(obj.type == CSGTerm::TYPE_DIFFERENCE ? CSGMODE_DIFFERENCE : 0));
|
||||||
ColorMode colormode = COLORMODE_NONE;
|
ColorMode colormode = COLORMODE_NONE;
|
||||||
ColorMode edge_colormode = COLORMODE_NONE;
|
ColorMode edge_colormode = COLORMODE_NONE;
|
||||||
|
|
||||||
if (highlight) {
|
if (highlight) {
|
||||||
csgmode = csgmode_e(csgmode + 20);
|
|
||||||
colormode = COLORMODE_HIGHLIGHT;
|
colormode = COLORMODE_HIGHLIGHT;
|
||||||
edge_colormode = COLORMODE_HIGHLIGHT_EDGES;
|
edge_colormode = COLORMODE_HIGHLIGHT_EDGES;
|
||||||
} else if (background) {
|
} else if (background) {
|
||||||
|
@ -89,16 +92,11 @@ void ThrownTogetherRenderer::renderCSGChain(CSGChain *chain, bool highlight,
|
||||||
else {
|
else {
|
||||||
colormode = COLORMODE_BACKGROUND;
|
colormode = COLORMODE_BACKGROUND;
|
||||||
}
|
}
|
||||||
csgmode = csgmode_e(csgmode + 10);
|
|
||||||
edge_colormode = COLORMODE_BACKGROUND_EDGES;
|
edge_colormode = COLORMODE_BACKGROUND_EDGES;
|
||||||
} else if (fberror) {
|
} else if (fberror) {
|
||||||
if (highlight) csgmode = csgmode_e(csgmode + 20);
|
|
||||||
else if (background) csgmode = csgmode_e(csgmode + 10);
|
|
||||||
else csgmode = csgmode_e(csgmode);
|
|
||||||
} else if (obj.type == CSGTerm::TYPE_DIFFERENCE) {
|
} else if (obj.type == CSGTerm::TYPE_DIFFERENCE) {
|
||||||
if (obj.flag & CSGTerm::FLAG_HIGHLIGHT) {
|
if (obj.flag & CSGTerm::FLAG_HIGHLIGHT) {
|
||||||
colormode = COLORMODE_HIGHLIGHT;
|
colormode = COLORMODE_HIGHLIGHT;
|
||||||
csgmode = csgmode_e(csgmode + 20);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
colormode = COLORMODE_CUTOUT;
|
colormode = COLORMODE_CUTOUT;
|
||||||
|
@ -107,7 +105,6 @@ void ThrownTogetherRenderer::renderCSGChain(CSGChain *chain, bool highlight,
|
||||||
} else {
|
} else {
|
||||||
if (obj.flag & CSGTerm::FLAG_HIGHLIGHT) {
|
if (obj.flag & CSGTerm::FLAG_HIGHLIGHT) {
|
||||||
colormode = COLORMODE_HIGHLIGHT;
|
colormode = COLORMODE_HIGHLIGHT;
|
||||||
csgmode = csgmode_e(csgmode + 20);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
colormode = COLORMODE_MATERIAL;
|
colormode = COLORMODE_MATERIAL;
|
||||||
|
|
26
src/Tree.cc
26
src/Tree.cc
|
@ -1,8 +1,11 @@
|
||||||
#include "Tree.h"
|
#include "Tree.h"
|
||||||
#include "nodedumper.h"
|
#include "nodedumper.h"
|
||||||
|
#include "printutils.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <sstream>
|
||||||
|
#include <boost/regex.hpp>
|
||||||
|
|
||||||
Tree::~Tree()
|
Tree::~Tree()
|
||||||
{
|
{
|
||||||
|
@ -29,11 +32,6 @@ const std::string &Tree::getString(const AbstractNode &node) const
|
||||||
return this->nodecache[node];
|
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.
|
Returns the cached ID string representation of the subtree rooted by \a node.
|
||||||
If node is not cached, the cache will be rebuilt.
|
If node is not cached, the cache will be rebuilt.
|
||||||
|
@ -45,12 +43,22 @@ static bool filter(char c)
|
||||||
const std::string &Tree::getIdString(const AbstractNode &node) const
|
const std::string &Tree::getIdString(const AbstractNode &node) const
|
||||||
{
|
{
|
||||||
assert(this->root_node);
|
assert(this->root_node);
|
||||||
|
|
||||||
if (!this->nodeidcache.contains(node)) {
|
if (!this->nodeidcache.contains(node)) {
|
||||||
std::string str = getString(node);
|
const std::string &nodestr = getString(node);
|
||||||
str.erase(std::remove_if(str.begin(), str.end(), filter), str.end());
|
const boost::regex re("[^\\s\\\"]+|\\\"(?:[^\\\"\\\\]|\\\\.)*\\\"");
|
||||||
return this->nodeidcache.insert(node, str);
|
std::stringstream sstream;
|
||||||
|
boost::sregex_token_iterator i(nodestr.begin(), nodestr.end(), re, 0);
|
||||||
|
std::copy(i, boost::sregex_token_iterator(), std::ostream_iterator<std::string>(sstream));
|
||||||
|
|
||||||
|
const std::string & result = this->nodeidcache.insert(node, sstream.str());
|
||||||
|
PRINTDB("Id Cache MISS: %s", result);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
const std::string & result = this->nodeidcache[node];
|
||||||
|
PRINTDB("Id Cache HIT: %s", result);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
return this->nodeidcache[node];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
|
|
||||||
|
#include "qtgettext.h"
|
||||||
#include "UIUtils.h"
|
#include "UIUtils.h"
|
||||||
#include "PlatformUtils.h"
|
#include "PlatformUtils.h"
|
||||||
|
|
||||||
|
@ -81,15 +82,15 @@ QStringList UIUtils::exampleCategories()
|
||||||
{
|
{
|
||||||
QStringList categories;
|
QStringList categories;
|
||||||
//categories in File menu item - Examples
|
//categories in File menu item - Examples
|
||||||
categories << "Basics" << "Shapes" << "Extrusion" << "Advanced";
|
categories << N_("Basics") << N_("Shapes") << N_("Extrusion") << N_("Advanced");
|
||||||
|
|
||||||
return categories;
|
return categories;
|
||||||
}
|
}
|
||||||
|
|
||||||
QFileInfoList UIUtils::exampleFiles(const QString &category)
|
QFileInfoList UIUtils::exampleFiles(const QString &category)
|
||||||
{
|
{
|
||||||
QDir dir(QString::fromStdString(PlatformUtils::resourcesPath()));
|
QDir dir(QString::fromStdString(PlatformUtils::resourcePath("examples").string()));
|
||||||
if (!dir.cd("examples") || !dir.cd(category)) {
|
if (!dir.cd(category)) {
|
||||||
return QFileInfoList();
|
return QFileInfoList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,19 +95,19 @@ std::string Builtins::isDeprecated(const std::string &name)
|
||||||
|
|
||||||
Builtins::Builtins()
|
Builtins::Builtins()
|
||||||
{
|
{
|
||||||
this->globalscope.assignments.push_back(Assignment("$fn", boost::shared_ptr<Expression>(new Expression(Value(0.0)))));
|
this->globalscope.assignments.push_back(Assignment("$fn", boost::shared_ptr<Expression>(new ExpressionConst(ValuePtr(0.0)))));
|
||||||
this->globalscope.assignments.push_back(Assignment("$fs", boost::shared_ptr<Expression>(new Expression(Value(2.0)))));
|
this->globalscope.assignments.push_back(Assignment("$fs", boost::shared_ptr<Expression>(new ExpressionConst(ValuePtr(2.0)))));
|
||||||
this->globalscope.assignments.push_back(Assignment("$fa", boost::shared_ptr<Expression>(new Expression(Value(12.0)))));
|
this->globalscope.assignments.push_back(Assignment("$fa", boost::shared_ptr<Expression>(new ExpressionConst(ValuePtr(12.0)))));
|
||||||
this->globalscope.assignments.push_back(Assignment("$t", boost::shared_ptr<Expression>(new Expression(Value(0.0)))));
|
this->globalscope.assignments.push_back(Assignment("$t", boost::shared_ptr<Expression>(new ExpressionConst(ValuePtr(0.0)))));
|
||||||
|
|
||||||
Value::VectorType zero3;
|
Value::VectorType zero3;
|
||||||
zero3.push_back(Value(0.0));
|
zero3.push_back(Value(0.0));
|
||||||
zero3.push_back(Value(0.0));
|
zero3.push_back(Value(0.0));
|
||||||
zero3.push_back(Value(0.0));
|
zero3.push_back(Value(0.0));
|
||||||
Value zero3val(zero3);
|
ValuePtr zero3val(zero3);
|
||||||
this->globalscope.assignments.push_back(Assignment("$vpt", boost::shared_ptr<Expression>(new Expression(zero3val))));
|
this->globalscope.assignments.push_back(Assignment("$vpt", boost::shared_ptr<Expression>(new ExpressionConst(zero3val))));
|
||||||
this->globalscope.assignments.push_back(Assignment("$vpr", boost::shared_ptr<Expression>(new Expression(zero3val))));
|
this->globalscope.assignments.push_back(Assignment("$vpr", boost::shared_ptr<Expression>(new ExpressionConst(zero3val))));
|
||||||
this->globalscope.assignments.push_back(Assignment("$vpd", boost::shared_ptr<Expression>(new Expression(500))));
|
this->globalscope.assignments.push_back(Assignment("$vpd", boost::shared_ptr<Expression>(new ExpressionConst(ValuePtr(500)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
Builtins::~Builtins()
|
Builtins::~Builtins()
|
||||||
|
|
|
@ -27,7 +27,7 @@ using boost::uintmax_t;
|
||||||
#include <CGAL/Cartesian.h>
|
#include <CGAL/Cartesian.h>
|
||||||
#include <CGAL/Polyhedron_3.h>
|
#include <CGAL/Polyhedron_3.h>
|
||||||
#include <CGAL/Nef_polyhedron_3.h>
|
#include <CGAL/Nef_polyhedron_3.h>
|
||||||
#include <CGAL_Nef3_workaround.h>
|
#include "CGAL_Nef3_workaround.h"
|
||||||
#include <CGAL/IO/Polyhedron_iostream.h>
|
#include <CGAL/IO/Polyhedron_iostream.h>
|
||||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||||
#include <CGAL/Polygon_2.h>
|
#include <CGAL/Polygon_2.h>
|
||||||
|
@ -57,11 +57,10 @@ typedef CGAL::Nef_polyhedron_3<CGAL_Kernel3> CGAL_Nef_polyhedron3;
|
||||||
typedef CGAL_Nef_polyhedron3::Aff_transformation_3 CGAL_Aff_transformation;
|
typedef CGAL_Nef_polyhedron3::Aff_transformation_3 CGAL_Aff_transformation;
|
||||||
|
|
||||||
typedef CGAL::Polyhedron_3<CGAL_Kernel3> CGAL_Polyhedron;
|
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::Point_3<CGAL_Kernel3> CGAL_Point_3;
|
typedef CGAL::Point_3<CGAL_Kernel3> CGAL_Point_3;
|
||||||
typedef CGAL::Iso_cuboid_3<CGAL_Kernel3> CGAL_Iso_cuboid_3;
|
typedef CGAL::Iso_cuboid_3<CGAL_Kernel3> CGAL_Iso_cuboid_3;
|
||||||
|
typedef std::vector<CGAL_Point_3> CGAL_Polygon_3;
|
||||||
|
|
||||||
// CGAL_Nef_polyhedron2 uses CGAL_Kernel2, but Iso_rectangle_2 needs to match
|
// CGAL_Nef_polyhedron2 uses CGAL_Kernel2, but Iso_rectangle_2 needs to match
|
||||||
// CGAL_Nef_polyhedron2::Explorer::Point which is different than
|
// CGAL_Nef_polyhedron2::Explorer::Point which is different than
|
||||||
|
|
|
@ -64,8 +64,11 @@ AbstractNode *CgaladvModule::instantiate(const Context *ctx, const ModuleInstant
|
||||||
c.setVariables(args, evalctx);
|
c.setVariables(args, evalctx);
|
||||||
inst->scope.apply(*evalctx);
|
inst->scope.apply(*evalctx);
|
||||||
|
|
||||||
Value convexity, path, subdiv_type, level;
|
ValuePtr convexity = ValuePtr::undefined;
|
||||||
|
ValuePtr path = ValuePtr::undefined;
|
||||||
|
ValuePtr subdiv_type = ValuePtr::undefined;
|
||||||
|
ValuePtr level = ValuePtr::undefined;
|
||||||
|
|
||||||
if (type == MINKOWSKI) {
|
if (type == MINKOWSKI) {
|
||||||
convexity = c.lookup_variable("convexity", true);
|
convexity = c.lookup_variable("convexity", true);
|
||||||
}
|
}
|
||||||
|
@ -82,31 +85,31 @@ AbstractNode *CgaladvModule::instantiate(const Context *ctx, const ModuleInstant
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == RESIZE) {
|
if (type == RESIZE) {
|
||||||
Value ns = c.lookup_variable("newsize");
|
ValuePtr ns = c.lookup_variable("newsize");
|
||||||
node->newsize << 0,0,0;
|
node->newsize << 0,0,0;
|
||||||
if ( ns.type() == Value::VECTOR ) {
|
if ( ns->type() == Value::VECTOR ) {
|
||||||
Value::VectorType vs = ns.toVector();
|
const Value::VectorType &vs = ns->toVector();
|
||||||
if ( vs.size() >= 1 ) node->newsize[0] = vs[0].toDouble();
|
if ( vs.size() >= 1 ) node->newsize[0] = vs[0].toDouble();
|
||||||
if ( vs.size() >= 2 ) node->newsize[1] = vs[1].toDouble();
|
if ( vs.size() >= 2 ) node->newsize[1] = vs[1].toDouble();
|
||||||
if ( vs.size() >= 3 ) node->newsize[2] = vs[2].toDouble();
|
if ( vs.size() >= 3 ) node->newsize[2] = vs[2].toDouble();
|
||||||
}
|
}
|
||||||
Value autosize = c.lookup_variable("auto");
|
ValuePtr autosize = c.lookup_variable("auto");
|
||||||
node->autosize << false, false, false;
|
node->autosize << false, false, false;
|
||||||
if ( autosize.type() == Value::VECTOR ) {
|
if ( autosize->type() == Value::VECTOR ) {
|
||||||
Value::VectorType va = autosize.toVector();
|
const Value::VectorType &va = autosize->toVector();
|
||||||
if ( va.size() >= 1 ) node->autosize[0] = va[0].toBool();
|
if ( va.size() >= 1 ) node->autosize[0] = va[0].toBool();
|
||||||
if ( va.size() >= 2 ) node->autosize[1] = va[1].toBool();
|
if ( va.size() >= 2 ) node->autosize[1] = va[1].toBool();
|
||||||
if ( va.size() >= 3 ) node->autosize[2] = va[2].toBool();
|
if ( va.size() >= 3 ) node->autosize[2] = va[2].toBool();
|
||||||
}
|
}
|
||||||
else if ( autosize.type() == Value::BOOL ) {
|
else if ( autosize->type() == Value::BOOL ) {
|
||||||
node->autosize << autosize.toBool(),autosize.toBool(),autosize.toBool();
|
node->autosize << autosize->toBool(),autosize->toBool(),autosize->toBool();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node->convexity = (int)convexity.toDouble();
|
node->convexity = (int)convexity->toDouble();
|
||||||
node->path = path;
|
node->path = path;
|
||||||
node->subdiv_type = subdiv_type.toString();
|
node->subdiv_type = subdiv_type->toString();
|
||||||
node->level = (int)level.toDouble();
|
node->level = (int)level->toDouble();
|
||||||
|
|
||||||
if (node->level <= 1)
|
if (node->level <= 1)
|
||||||
node->level = 1;
|
node->level = 1;
|
||||||
|
@ -151,7 +154,7 @@ std::string CgaladvNode::toString() const
|
||||||
stream << "(convexity = " << this->convexity << ")";
|
stream << "(convexity = " << this->convexity << ")";
|
||||||
break;
|
break;
|
||||||
case GLIDE:
|
case GLIDE:
|
||||||
stream << "(path = " << this->path << ", convexity = " << this->convexity << ")";
|
stream << "(path = " << *this->path << ", convexity = " << this->convexity << ")";
|
||||||
break;
|
break;
|
||||||
case SUBDIV:
|
case SUBDIV:
|
||||||
stream << "(level = " << this->level << ", convexity = " << this->convexity << ")";
|
stream << "(level = " << this->level << ", convexity = " << this->convexity << ")";
|
||||||
|
|
|
@ -26,7 +26,7 @@ public:
|
||||||
virtual std::string toString() const;
|
virtual std::string toString() const;
|
||||||
virtual std::string name() const;
|
virtual std::string name() const;
|
||||||
|
|
||||||
Value path;
|
ValuePtr path;
|
||||||
std::string subdiv_type;
|
std::string subdiv_type;
|
||||||
int convexity, level;
|
int convexity, level;
|
||||||
Vector3d newsize;
|
Vector3d newsize;
|
||||||
|
|
|
@ -0,0 +1,301 @@
|
||||||
|
#ifdef ENABLE_CGAL
|
||||||
|
|
||||||
|
#include "cgalutils.h"
|
||||||
|
#include "polyset.h"
|
||||||
|
#include "printutils.h"
|
||||||
|
#include "polyset-utils.h"
|
||||||
|
#include "grid.h"
|
||||||
|
|
||||||
|
#include "cgal.h"
|
||||||
|
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||||
|
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
|
namespace /* anonymous */ {
|
||||||
|
template<typename Result, typename V>
|
||||||
|
Result vector_convert(V const& v) {
|
||||||
|
return Result(CGAL::to_double(v[0]),CGAL::to_double(v[1]),CGAL::to_double(v[2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef GEN_SURFACE_DEBUG
|
||||||
|
|
||||||
|
template <typename Polyhedron>
|
||||||
|
class CGAL_Build_PolySet : public CGAL::Modifier_base<typename Polyhedron::HalfedgeDS>
|
||||||
|
{
|
||||||
|
typedef typename Polyhedron::HalfedgeDS HDS;
|
||||||
|
typedef CGAL::Polyhedron_incremental_builder_3<typename Polyhedron::HalfedgeDS> CGAL_Polybuilder;
|
||||||
|
public:
|
||||||
|
typedef typename CGAL_Polybuilder::Point_3 CGALPoint;
|
||||||
|
|
||||||
|
const PolySet &ps;
|
||||||
|
CGAL_Build_PolySet(const PolySet &ps) : ps(ps) { }
|
||||||
|
|
||||||
|
/*
|
||||||
|
Using Grid here is important for performance reasons. See following model.
|
||||||
|
If we don't grid the geometry before converting to a Nef Polyhedron, the quads
|
||||||
|
in the cylinders to tessellated into triangles since floating point
|
||||||
|
incertainty causes the faces to not be 100% planar. The incertainty is exaggerated
|
||||||
|
by the transform. This wasn't a problem earlier since we used Nef for everything,
|
||||||
|
but optimizations since then has made us keep it in floating point space longer.
|
||||||
|
|
||||||
|
minkowski() {
|
||||||
|
cube([200, 50, 7], center = true);
|
||||||
|
rotate([90,0,0]) cylinder($fn = 8, h = 1, r = 8.36, center = true);
|
||||||
|
rotate([0,90,0]) cylinder($fn = 8, h = 1, r = 8.36, center = true);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
#if 1 // Use Grid
|
||||||
|
void operator()(HDS& hds) {
|
||||||
|
CGAL_Polybuilder B(hds, true);
|
||||||
|
|
||||||
|
std::vector<CGALPoint> vertices;
|
||||||
|
Grid3d<int> grid(GRID_FINE);
|
||||||
|
std::vector<size_t> indices(3);
|
||||||
|
|
||||||
|
BOOST_FOREACH(const Polygon &p, ps.polygons) {
|
||||||
|
BOOST_REVERSE_FOREACH(Vector3d v, p) {
|
||||||
|
if (!grid.has(v)) {
|
||||||
|
// align v to the grid; the CGALPoint will receive the aligned vertex
|
||||||
|
grid.align(v) = vertices.size();
|
||||||
|
vertices.push_back(CGALPoint(v[0], v[1], v[2]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef GEN_SURFACE_DEBUG
|
||||||
|
printf("polyhedron(faces=[");
|
||||||
|
int pidx = 0;
|
||||||
|
#endif
|
||||||
|
B.begin_surface(vertices.size(), ps.polygons.size());
|
||||||
|
BOOST_FOREACH(const CGALPoint &p, vertices) {
|
||||||
|
B.add_vertex(p);
|
||||||
|
}
|
||||||
|
BOOST_FOREACH(const Polygon &p, ps.polygons) {
|
||||||
|
#ifdef GEN_SURFACE_DEBUG
|
||||||
|
if (pidx++ > 0) printf(",");
|
||||||
|
#endif
|
||||||
|
indices.clear();
|
||||||
|
BOOST_FOREACH(const Vector3d &v, p) {
|
||||||
|
indices.push_back(grid.data(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
// We remove duplicate indices since there is a bug in CGAL's
|
||||||
|
// Polyhedron_incremental_builder_3::test_facet() which fails to detect this
|
||||||
|
std::vector<size_t>::iterator last = std::unique(indices.begin(), indices.end());
|
||||||
|
std::advance(last, -1);
|
||||||
|
if (*last != indices.front()) last++; // In case the first & last are equal
|
||||||
|
indices.erase(last, indices.end());
|
||||||
|
if (indices.size() >= 3 && B.test_facet(indices.begin(), indices.end())) {
|
||||||
|
B.add_facet(indices.begin(), indices.end());
|
||||||
|
}
|
||||||
|
#ifdef GEN_SURFACE_DEBUG
|
||||||
|
printf("[");
|
||||||
|
int fidx = 0;
|
||||||
|
BOOST_REVERSE_FOREACH(size_t i, indices) {
|
||||||
|
if (fidx++ > 0) printf(",");
|
||||||
|
printf("%ld", i);
|
||||||
|
}
|
||||||
|
printf("]");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
B.end_surface();
|
||||||
|
#ifdef GEN_SURFACE_DEBUG
|
||||||
|
printf("],\n");
|
||||||
|
#endif
|
||||||
|
#ifdef GEN_SURFACE_DEBUG
|
||||||
|
printf("points=[");
|
||||||
|
for (int i=0;i<vertices.size();i++) {
|
||||||
|
if (i > 0) printf(",");
|
||||||
|
const CGALPoint &p = vertices[i];
|
||||||
|
printf("[%g,%g,%g]", CGAL::to_double(p.x()), CGAL::to_double(p.y()), CGAL::to_double(p.z()));
|
||||||
|
}
|
||||||
|
printf("]);\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#else // Don't use Grid
|
||||||
|
void operator()(HDS& hds)
|
||||||
|
{
|
||||||
|
CGAL_Polybuilder B(hds, true);
|
||||||
|
Reindexer<Vector3d> vertices;
|
||||||
|
std::vector<size_t> indices(3);
|
||||||
|
|
||||||
|
// Estimating same # of vertices as polygons (very rough)
|
||||||
|
B.begin_surface(ps.polygons.size(), ps.polygons.size());
|
||||||
|
int pidx = 0;
|
||||||
|
#ifdef GEN_SURFACE_DEBUG
|
||||||
|
printf("polyhedron(faces=[");
|
||||||
|
#endif
|
||||||
|
BOOST_FOREACH(const Polygon &p, ps.polygons) {
|
||||||
|
#ifdef GEN_SURFACE_DEBUG
|
||||||
|
if (pidx++ > 0) printf(",");
|
||||||
|
#endif
|
||||||
|
indices.clear();
|
||||||
|
BOOST_REVERSE_FOREACH(const Vector3d &v, p) {
|
||||||
|
size_t s = vertices.size();
|
||||||
|
size_t idx = vertices.lookup(v);
|
||||||
|
// If we added a vertex, also add it to the CGAL builder
|
||||||
|
if (idx == s) B.add_vertex(CGALPoint(v[0], v[1], v[2]));
|
||||||
|
indices.push_back(idx);
|
||||||
|
}
|
||||||
|
// We perform this test since there is a bug in CGAL's
|
||||||
|
// Polyhedron_incremental_builder_3::test_facet() which
|
||||||
|
// fails to detect duplicate indices
|
||||||
|
bool err = false;
|
||||||
|
for (std::size_t i = 0; i < indices.size(); ++i) {
|
||||||
|
// check if vertex indices[i] is already in the sequence [0..i-1]
|
||||||
|
for (std::size_t k = 0; k < i && !err; ++k) {
|
||||||
|
if (indices[k] == indices[i]) {
|
||||||
|
err = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!err && B.test_facet(indices.begin(), indices.end())) {
|
||||||
|
B.add_facet(indices.begin(), indices.end());
|
||||||
|
#ifdef GEN_SURFACE_DEBUG
|
||||||
|
printf("[");
|
||||||
|
int fidx = 0;
|
||||||
|
BOOST_FOREACH(size_t i, indices) {
|
||||||
|
if (fidx++ > 0) printf(",");
|
||||||
|
printf("%ld", i);
|
||||||
|
}
|
||||||
|
printf("]");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
B.end_surface();
|
||||||
|
#ifdef GEN_SURFACE_DEBUG
|
||||||
|
printf("],\n");
|
||||||
|
|
||||||
|
printf("points=[");
|
||||||
|
for (int vidx=0;vidx<vertices.size();vidx++) {
|
||||||
|
if (vidx > 0) printf(",");
|
||||||
|
const Vector3d &v = vertices.getArray()[vidx];
|
||||||
|
printf("[%g,%g,%g]", v[0], v[1], v[2]);
|
||||||
|
}
|
||||||
|
printf("]);\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
// This code is from CGAL/demo/Polyhedron/Scene_nef_polyhedron_item.cpp
|
||||||
|
// quick hacks to convert polyhedra from exact to inexact and vice-versa
|
||||||
|
template <class Polyhedron_input, class Polyhedron_output>
|
||||||
|
struct Copy_polyhedron_to : public CGAL::Modifier_base<typename Polyhedron_output::HalfedgeDS>
|
||||||
|
{
|
||||||
|
Copy_polyhedron_to(const Polyhedron_input& in_poly) : in_poly(in_poly) {}
|
||||||
|
|
||||||
|
void operator()(typename Polyhedron_output::HalfedgeDS& out_hds)
|
||||||
|
{
|
||||||
|
typedef typename Polyhedron_output::HalfedgeDS Output_HDS;
|
||||||
|
|
||||||
|
CGAL::Polyhedron_incremental_builder_3<Output_HDS> builder(out_hds);
|
||||||
|
|
||||||
|
typedef typename Polyhedron_input::Vertex_const_iterator Vertex_const_iterator;
|
||||||
|
typedef typename Polyhedron_input::Facet_const_iterator Facet_const_iterator;
|
||||||
|
typedef typename Polyhedron_input::Halfedge_around_facet_const_circulator HFCC;
|
||||||
|
|
||||||
|
builder.begin_surface(in_poly.size_of_vertices(),
|
||||||
|
in_poly.size_of_facets(),
|
||||||
|
in_poly.size_of_halfedges());
|
||||||
|
|
||||||
|
for (Vertex_const_iterator
|
||||||
|
vi = in_poly.vertices_begin(), end = in_poly.vertices_end();
|
||||||
|
vi != end ; ++vi) {
|
||||||
|
typename Polyhedron_output::Point_3 p(::CGAL::to_double(vi->point().x()),
|
||||||
|
::CGAL::to_double(vi->point().y()),
|
||||||
|
::CGAL::to_double(vi->point().z()));
|
||||||
|
builder.add_vertex(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef CGAL::Inverse_index<Vertex_const_iterator> Index;
|
||||||
|
Index index(in_poly.vertices_begin(), in_poly.vertices_end());
|
||||||
|
|
||||||
|
for (Facet_const_iterator
|
||||||
|
fi = in_poly.facets_begin(), end = in_poly.facets_end();
|
||||||
|
fi != end; ++fi) {
|
||||||
|
HFCC hc = fi->facet_begin();
|
||||||
|
HFCC hc_end = hc;
|
||||||
|
// std::size_t n = circulator_size(hc);
|
||||||
|
// CGAL_assertion(n >= 3);
|
||||||
|
builder.begin_facet ();
|
||||||
|
do {
|
||||||
|
builder.add_vertex_to_facet(index[hc->vertex()]);
|
||||||
|
++hc;
|
||||||
|
} while(hc != hc_end);
|
||||||
|
builder.end_facet();
|
||||||
|
}
|
||||||
|
builder.end_surface();
|
||||||
|
} // end operator()(..)
|
||||||
|
private:
|
||||||
|
const Polyhedron_input& in_poly;
|
||||||
|
}; // end Copy_polyhedron_to<>
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CGALUtils {
|
||||||
|
|
||||||
|
template <class Polyhedron_A, class Polyhedron_B>
|
||||||
|
void copyPolyhedron(const Polyhedron_A &poly_a, Polyhedron_B &poly_b)
|
||||||
|
{
|
||||||
|
Copy_polyhedron_to<Polyhedron_A, Polyhedron_B> modifier(poly_a);
|
||||||
|
poly_b.delegate(modifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
template void copyPolyhedron(const CGAL::Polyhedron_3<CGAL::Epick> &, CGAL_Polyhedron &);
|
||||||
|
template void copyPolyhedron(const CGAL_Polyhedron &, CGAL::Polyhedron_3<CGAL::Epick> &);
|
||||||
|
|
||||||
|
template <typename Polyhedron>
|
||||||
|
bool createPolyhedronFromPolySet(const PolySet &ps, Polyhedron &p)
|
||||||
|
{
|
||||||
|
bool err = false;
|
||||||
|
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
|
||||||
|
try {
|
||||||
|
CGAL_Build_PolySet<Polyhedron> builder(ps);
|
||||||
|
p.delegate(builder);
|
||||||
|
}
|
||||||
|
catch (const CGAL::Assertion_exception &e) {
|
||||||
|
PRINTB("CGAL error in CGALUtils::createPolyhedronFromPolySet: %s", e.what());
|
||||||
|
err = true;
|
||||||
|
}
|
||||||
|
CGAL::set_error_behaviour(old_behaviour);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
template bool createPolyhedronFromPolySet(const PolySet &ps, CGAL_Polyhedron &p);
|
||||||
|
template bool createPolyhedronFromPolySet(const PolySet &ps, CGAL::Polyhedron_3<CGAL::Epick> &p);
|
||||||
|
|
||||||
|
template <typename Polyhedron>
|
||||||
|
bool createPolySetFromPolyhedron(const Polyhedron &p, PolySet &ps)
|
||||||
|
{
|
||||||
|
bool err = false;
|
||||||
|
typedef typename Polyhedron::Vertex Vertex;
|
||||||
|
typedef typename Polyhedron::Vertex_const_iterator VCI;
|
||||||
|
typedef typename Polyhedron::Facet_const_iterator FCI;
|
||||||
|
typedef typename 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 const& v = *((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);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
template bool createPolySetFromPolyhedron(const CGAL_Polyhedron &p, PolySet &ps);
|
||||||
|
template bool createPolySetFromPolyhedron(const CGAL::Polyhedron_3<CGAL::Epick> &p, PolySet &ps);
|
||||||
|
template bool createPolySetFromPolyhedron(const CGAL::Polyhedron_3<CGAL::Epeck> &p, PolySet &ps);
|
||||||
|
template bool createPolySetFromPolyhedron(const CGAL::Polyhedron_3<CGAL::Simple_cartesian<long> > &p, PolySet &ps);
|
||||||
|
|
||||||
|
}; // namespace CGALUtils
|
||||||
|
|
||||||
|
#endif /* ENABLE_CGAL */
|
||||||
|
|
|
@ -0,0 +1,553 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
This is our custom tessellator of Nef Polyhedron faces. The problem with
|
||||||
|
Nef faces is that sometimes the 'default' tessellator of Nef Polyhedron
|
||||||
|
doesnt work. This is particularly true with situations where the polygon
|
||||||
|
face is not, actually, 'simple', according to CGAL itself. This can
|
||||||
|
occur on a bad quality STL import but also for other reasons. The
|
||||||
|
resulting Nef face will appear to the average human eye as an ordinary,
|
||||||
|
simple polygon... but in reality it has multiple edges that are
|
||||||
|
slightly-out-of-alignment and sometimes they backtrack on themselves.
|
||||||
|
|
||||||
|
When the triangulator is fed a polygon with self-intersecting edges,
|
||||||
|
it's default behavior is to throw an exception. The other terminology
|
||||||
|
for this is to say that the 'constraints' in the triangulation are
|
||||||
|
'intersecting'. The 'constraints' represent the edges of the polygon.
|
||||||
|
The 'triangulation' is the covering of all the polygon points with
|
||||||
|
triangles.
|
||||||
|
|
||||||
|
How do we allow interseting constraints during triangulation? We use an
|
||||||
|
'Itag' for the triangulation, per the CGAL docs. This allows the
|
||||||
|
triangulator to run without throwing an exception when it encounters
|
||||||
|
self-intersecting polygon edges. The trick here is that when it finds
|
||||||
|
an intersection, it actually creates a new point.
|
||||||
|
|
||||||
|
The triangulator creates new points in 2d, but they aren't matched to
|
||||||
|
any 3d points on our 3d polygon plane. (The plane of the Nef face). How
|
||||||
|
to fix this problem? We actually 'project back up' or 'lift' into the 3d
|
||||||
|
plane from the 2d point. This is handled in the 'deproject()' function.
|
||||||
|
|
||||||
|
There is also the issue of the Simplicity of Nef Polyhedron face
|
||||||
|
polygons. They are often not simple. The intersecting-constraints
|
||||||
|
Triangulation can triangulate non-simple polygons, but of course it's
|
||||||
|
result is also non-simple. This means that CGAL functions like
|
||||||
|
orientation_2() and bounded_side() simply will not work on the resulting
|
||||||
|
polygons because they all require input polygons to pass the
|
||||||
|
'is_simple2()' test. We have to use alternatives in order to create our
|
||||||
|
triangles.
|
||||||
|
|
||||||
|
There is also the question of which underlying number type to use. Some
|
||||||
|
of the CGAL functions simply dont guarantee good results with a type
|
||||||
|
like double. Although much the math here is somewhat simple, like
|
||||||
|
line-line intersection, and involves only simple algebra, the
|
||||||
|
approximations required when using floating-point types can cause the
|
||||||
|
answers to be wrong. For example questions like 'is a point inside a
|
||||||
|
triangle' do not have good answers under floating-point systems where a
|
||||||
|
line may have a slope that is not expressible exactly as a floating
|
||||||
|
point number. There are ways to deal with floating point inaccuracy but
|
||||||
|
it is much, much simpler to use Rational numbers, although potentially
|
||||||
|
much slower in many cases.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "cgalutils.h"
|
||||||
|
#include <CGAL/Delaunay_mesher_no_edge_refinement_2.h>
|
||||||
|
#include <CGAL/Delaunay_mesh_face_base_2.h>
|
||||||
|
|
||||||
|
typedef CGAL_Kernel3 Kernel;
|
||||||
|
//typedef CGAL::Triangulation_vertex_base_2<Kernel> Vb;
|
||||||
|
typedef CGAL::Triangulation_vertex_base_2<Kernel> Vb;
|
||||||
|
//typedef CGAL::Constrained_triangulation_face_base_2<Kernel> Fb;
|
||||||
|
typedef CGAL::Delaunay_mesh_face_base_2<Kernel> Fb;
|
||||||
|
typedef CGAL::Triangulation_data_structure_2<Vb,Fb> TDS;
|
||||||
|
typedef CGAL::Exact_intersections_tag ITAG;
|
||||||
|
typedef CGAL::Constrained_Delaunay_triangulation_2<Kernel,TDS,ITAG> CDT;
|
||||||
|
//typedef CGAL::Constrained_Delaunay_triangulation_2<Kernel,TDS> CDT;
|
||||||
|
|
||||||
|
typedef CDT::Vertex_handle Vertex_handle;
|
||||||
|
typedef CDT::Point CDTPoint;
|
||||||
|
|
||||||
|
typedef CGAL::Ray_2<Kernel> CGAL_Ray_2;
|
||||||
|
typedef CGAL::Line_3<Kernel> CGAL_Line_3;
|
||||||
|
typedef CGAL::Point_2<Kernel> CGAL_Point_2;
|
||||||
|
typedef CGAL::Vector_2<Kernel> CGAL_Vector_2;
|
||||||
|
typedef CGAL::Segment_2<Kernel> CGAL_Segment_2;
|
||||||
|
typedef CGAL::Direction_2<Kernel> CGAL_Direction_2;
|
||||||
|
typedef CGAL::Direction_3<Kernel> CGAL_Direction_3;
|
||||||
|
typedef CGAL::Plane_3<Kernel> CGAL_Plane_3;
|
||||||
|
|
||||||
|
/* The idea of 'projection' is how we make 3d points appear as though
|
||||||
|
they were 2d points to the tessellation algorithm. We take the 3-d plane
|
||||||
|
on which the polygon lies, and then 'project' or 'cast its shadow' onto
|
||||||
|
one of three standard planes, the xyplane, the yzplane, or the xzplane,
|
||||||
|
depending on which projection will prevent the polygon looking like a
|
||||||
|
flat line. (imagine, the triangle 0,0,1 0,1,1 0,1,0 ... if viewed from
|
||||||
|
the 'top' it looks line a flat line. so we want to view it from the
|
||||||
|
side). Thus we create a sequence of x,y points to feed to the algorithm,
|
||||||
|
but those points might actually be x,z pairs or y,z pairs... it is an
|
||||||
|
illusion we present to the triangulation algorithm by way of 'projection'.
|
||||||
|
We get a resulting sequence of triangles with x,y coordinates, which we
|
||||||
|
then 'deproject' back to x,z or y,z, in 3d space as needed. For example
|
||||||
|
the square 0,0,0 0,0,1 0,1,1 0,1,0 becomes '0,0 0,1 1,1 1,0', is then
|
||||||
|
split into two triangles, 0,0 1,0 1,1 and 0,0 1,1 0,1. those two triangles
|
||||||
|
then are projected back to 3d as 0,0,0 0,1,0 0,1,1 and 0,0 0,1,1 0,0,1.
|
||||||
|
|
||||||
|
There is an additional trick we do with projection related to Polygon
|
||||||
|
orientation and the orientation of our output triangles, and thus, which
|
||||||
|
way they are facing in space (aka their 'normals' or 'oriented side').
|
||||||
|
|
||||||
|
The basic issues is this: every 3d flat polygon can be thought of as
|
||||||
|
having two sides. In Computer Graphics the convention is that the
|
||||||
|
'outside' or 'oriented side' or 'normal' is determined by looking at the
|
||||||
|
triangle in terms of the 'ordering' or 'winding' of the points. If the
|
||||||
|
points come in a 'clockwise' order, you must be looking at the triangle
|
||||||
|
from 'inside'. If the points come in a 'counterclockwise' order, you
|
||||||
|
must be looking at the triangle from the outside. For example, the
|
||||||
|
triangle 0,0,0 1,0,0 0,1,0, when viewed from the 'top', has points in a
|
||||||
|
counterclockwise order, so the 'up' side is the 'normal' or 'outside'.
|
||||||
|
if you look at that same triangle from the 'bottom' side, the points
|
||||||
|
will appear to be 'clockwise', so the 'down' side is the 'inside', and is the
|
||||||
|
opposite of the 'normal' side.
|
||||||
|
|
||||||
|
How do we keep track of all that when doing a triangulation? We could
|
||||||
|
check each triangle as it was generated, and fix it's orientation before
|
||||||
|
we feed it back to our output list. That is done by, for example, checking
|
||||||
|
the orientation of the input polygon and then forcing the triangle to
|
||||||
|
match that orientation during output. This is what CGAL's Nef Polyhedron
|
||||||
|
does, you can read it inside /usr/include/CGAL/Nef_polyhedron_3.h.
|
||||||
|
|
||||||
|
Or.... we could actually add an additional 'projection' to the incoming
|
||||||
|
polygon points so that our triangulation algorithm is guaranteed to
|
||||||
|
create triangles with the proper orientation in the first place. How?
|
||||||
|
First, we assume that the triangulation algorithm will always produce
|
||||||
|
'counterclockwise' triangles in our plain old x-y plane.
|
||||||
|
|
||||||
|
The method is based on the following curious fact: That is, if you take
|
||||||
|
the points of a polygon, and flip the x,y coordinate of each point,
|
||||||
|
making y:=x and x:=y, then you essentially get a 'mirror image' of the
|
||||||
|
original polygon... but the orientation will be flipped. Given a
|
||||||
|
clockwise polygon, the 'flip' will result in a 'counterclockwise'
|
||||||
|
polygon mirror-image and vice versa.
|
||||||
|
|
||||||
|
Now, there is a second curious fact that helps us here. In 3d, we are
|
||||||
|
using the plane equation of ax+by+cz+d=0, where a,b,c determine its
|
||||||
|
direction. If you notice, there are actually mutiple sets of numbers
|
||||||
|
a:b:c that will describe the exact same plane. For example the 'ground'
|
||||||
|
plane, called the XYplane, where z is everywhere 0, has the equation
|
||||||
|
0x+0y+1z+0=0, simplifying to a solution for x,y,z of z=0 and x,y = any
|
||||||
|
numbers in your number system. However you can also express this as
|
||||||
|
0x+0y+-1z=0. The x,y,z solution is the same: z is everywhere 0, x and y
|
||||||
|
are any number, even though a,b,c are different. We can say that the
|
||||||
|
plane is 'oriented' differently, if we wish.
|
||||||
|
|
||||||
|
But how can we link that concept to the points on the polygon? Well, if
|
||||||
|
you generate a plane using the standard plane-equation generation
|
||||||
|
formula, given three points M,N,P, then you will get a plane equation
|
||||||
|
with <a:b:c:d>. However if you feed the points in the reverse order,
|
||||||
|
P,N,M, so that they are now oriented in the opposite order, you will get
|
||||||
|
a plane equation with the signs flipped. <-a:-b:-c:-d> This means you
|
||||||
|
can essentially consider that a plane has an 'orientation' based on it's
|
||||||
|
equation, by looking at the signs of a,b,c relative to some other
|
||||||
|
quantity.
|
||||||
|
|
||||||
|
This means that you can 'flip' the projection of the input polygon
|
||||||
|
points so that the projection will match the orientation of the input
|
||||||
|
plane, thus guaranteeing that the output triangles will be oriented in
|
||||||
|
the same direction as the input polygon was. In other words, even though
|
||||||
|
we technically 'lose information' when we project from 3d->2d, we can
|
||||||
|
actually keep the concept of 'orientation' through the whole
|
||||||
|
triangulation process, and not have to recalculate the proper
|
||||||
|
orientation during output.
|
||||||
|
|
||||||
|
For example take two side-squares of a cube and the plane equations
|
||||||
|
formed by feeding the points in counterclockwise, as if looking in from
|
||||||
|
outside the cube:
|
||||||
|
|
||||||
|
0,0,0 0,1,0 0,1,1 0,0,1 <-1:0:0:0>
|
||||||
|
1,0,0 1,1,0 1,1,1 1,0,1 <1:0:0:1>
|
||||||
|
|
||||||
|
They are both projected onto the YZ plane. They look the same:
|
||||||
|
0,0 1,0 1,1 0,1
|
||||||
|
0,0 1,0 1,1 0,1
|
||||||
|
|
||||||
|
But the second square plane has opposite orientation, so we flip the x
|
||||||
|
and y for each point:
|
||||||
|
0,0 1,0 1,1 0,1
|
||||||
|
0,0 0,1 1,1 1,0
|
||||||
|
|
||||||
|
Only now do we feed these two 2-d squares to the tessellation algorithm.
|
||||||
|
The result is 4 triangles. When de-projected back to 3d, they will have
|
||||||
|
the appropriate winding that will match that of the original 3d faces.
|
||||||
|
And the first two triangles will have opposite orientation from the last two.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef enum { XYPLANE, YZPLANE, XZPLANE, NONE } plane_t;
|
||||||
|
struct projection_t {
|
||||||
|
plane_t plane;
|
||||||
|
bool flip;
|
||||||
|
};
|
||||||
|
|
||||||
|
CGAL_Point_2 get_projected_point( CGAL_Point_3 &p3, projection_t projection ) {
|
||||||
|
NT3 x,y;
|
||||||
|
if (projection.plane == XYPLANE) { x = p3.x(); y = p3.y(); }
|
||||||
|
else if (projection.plane == XZPLANE) { x = p3.x(); y = p3.z(); }
|
||||||
|
else if (projection.plane == YZPLANE) { x = p3.y(); y = p3.z(); }
|
||||||
|
else if (projection.plane == NONE) { x = 0; y = 0; }
|
||||||
|
if (projection.flip) return CGAL_Point_2( y,x );
|
||||||
|
return CGAL_Point_2( x,y );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* given 2d point, 3d plane, and 3d->2d projection, 'deproject' from
|
||||||
|
2d back onto a point on the 3d plane. true on failure, false on success */
|
||||||
|
bool deproject( CGAL_Point_2 &p2, projection_t &projection, CGAL_Plane_3 &plane, CGAL_Point_3 &p3 )
|
||||||
|
{
|
||||||
|
NT3 x,y;
|
||||||
|
CGAL_Line_3 l;
|
||||||
|
CGAL_Point_3 p;
|
||||||
|
CGAL_Point_2 pf( p2.x(), p2.y() );
|
||||||
|
if (projection.flip) pf = CGAL_Point_2( p2.y(), p2.x() );
|
||||||
|
if (projection.plane == XYPLANE) {
|
||||||
|
p = CGAL_Point_3( pf.x(), pf.y(), 0 );
|
||||||
|
l = CGAL_Line_3( p, CGAL_Direction_3(0,0,1) );
|
||||||
|
} else if (projection.plane == XZPLANE) {
|
||||||
|
p = CGAL_Point_3( pf.x(), 0, pf.y() );
|
||||||
|
l = CGAL_Line_3( p, CGAL_Direction_3(0,1,0) );
|
||||||
|
} else if (projection.plane == YZPLANE) {
|
||||||
|
p = CGAL_Point_3( 0, pf.x(), pf.y() );
|
||||||
|
l = CGAL_Line_3( p, CGAL_Direction_3(1,0,0) );
|
||||||
|
}
|
||||||
|
CGAL::Object obj = CGAL::intersection( l, plane );
|
||||||
|
const CGAL_Point_3 *point_test = CGAL::object_cast<CGAL_Point_3>(&obj);
|
||||||
|
if (point_test) {
|
||||||
|
p3 = *point_test;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
PRINT("ERROR: deproject failure");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this simple criteria guarantees CGALs triangulation algorithm will
|
||||||
|
terminate (i.e. not lock up and freeze the program) */
|
||||||
|
template <class T> class DummyCriteria {
|
||||||
|
public:
|
||||||
|
typedef double Quality;
|
||||||
|
class Is_bad {
|
||||||
|
public:
|
||||||
|
CGAL::Mesh_2::Face_badness operator()(const Quality) const {
|
||||||
|
return CGAL::Mesh_2::NOT_BAD;
|
||||||
|
}
|
||||||
|
CGAL::Mesh_2::Face_badness operator()(const typename T::Face_handle&, Quality&q) const {
|
||||||
|
q = 1;
|
||||||
|
return CGAL::Mesh_2::NOT_BAD;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Is_bad is_bad_object() const { return Is_bad(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
NT3 sign( const NT3 &n )
|
||||||
|
{
|
||||||
|
if (n>0) return NT3(1);
|
||||||
|
if (n<0) return NT3(-1);
|
||||||
|
return NT3(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wedge, also related to 'determinant', 'signed parallelogram area',
|
||||||
|
'side', 'turn', 'winding', '2d portion of cross-product', etc etc. this
|
||||||
|
function can tell you whether v1 is 'counterclockwise' or 'clockwise'
|
||||||
|
from v2, based on the sign of the result. when the input Vectors are
|
||||||
|
formed from three points, A-B and B-C, it can tell you if the path along
|
||||||
|
the points A->B->C is turning left or right.*/
|
||||||
|
NT3 wedge( CGAL_Vector_2 &v1, CGAL_Vector_2 &v2 ) {
|
||||||
|
return v1.x()*v2.y()-v2.x()*v1.y();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* given a point and a possibly non-simple polygon, determine if the
|
||||||
|
point is inside the polygon or not, using the given winding rule. note
|
||||||
|
that even_odd is not implemented. */
|
||||||
|
typedef enum { NONZERO_WINDING, EVEN_ODD } winding_rule_t;
|
||||||
|
bool inside(CGAL_Point_2 &p1,std::vector<CGAL_Point_2> &pgon, winding_rule_t winding_rule)
|
||||||
|
{
|
||||||
|
NT3 winding_sum = NT3(0);
|
||||||
|
CGAL_Point_2 p2;
|
||||||
|
CGAL_Ray_2 eastray(p1,CGAL_Direction_2(1,0));
|
||||||
|
for (size_t i=0;i<pgon.size();i++) {
|
||||||
|
CGAL_Point_2 tail = pgon[i];
|
||||||
|
CGAL_Point_2 head = pgon[(i+1)%pgon.size()];
|
||||||
|
CGAL_Segment_2 seg( tail, head );
|
||||||
|
CGAL::Object obj = intersection( eastray, seg );
|
||||||
|
const CGAL_Point_2 *point_test = CGAL::object_cast<CGAL_Point_2>(&obj);
|
||||||
|
if (point_test) {
|
||||||
|
p2 = *point_test;
|
||||||
|
CGAL_Vector_2 v1( p1, p2 );
|
||||||
|
CGAL_Vector_2 v2( p2, head );
|
||||||
|
NT3 this_winding = wedge( v1, v2 );
|
||||||
|
winding_sum += sign(this_winding);
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (winding_sum != NT3(0) && winding_rule == NONZERO_WINDING ) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
projection_t find_good_projection( CGAL_Plane_3 &plane )
|
||||||
|
{
|
||||||
|
projection_t goodproj;
|
||||||
|
goodproj.plane = NONE;
|
||||||
|
goodproj.flip = false;
|
||||||
|
NT3 qxy = plane.a()*plane.a()+plane.b()*plane.b();
|
||||||
|
NT3 qyz = plane.b()*plane.b()+plane.c()*plane.c();
|
||||||
|
NT3 qxz = plane.a()*plane.a()+plane.c()*plane.c();
|
||||||
|
NT3 min = std::min(qxy,std::min(qyz,qxz));
|
||||||
|
if (min==qxy) {
|
||||||
|
goodproj.plane = XYPLANE;
|
||||||
|
if (sign(plane.c())>0) goodproj.flip = true;
|
||||||
|
} else if (min==qyz) {
|
||||||
|
goodproj.plane = YZPLANE;
|
||||||
|
if (sign(plane.a())>0) goodproj.flip = true;
|
||||||
|
} else if (min==qxz) {
|
||||||
|
goodproj.plane = XZPLANE;
|
||||||
|
if (sign(plane.b())<0) goodproj.flip = true;
|
||||||
|
} else PRINT("ERROR: failed to find projection");
|
||||||
|
return goodproj;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CGALUtils {
|
||||||
|
/* given a single near-planar 3d polygon with holes, tessellate into a
|
||||||
|
sequence of polygons without holes. as of writing, this means conversion
|
||||||
|
into a sequence of 3d triangles. the given plane should be the same plane
|
||||||
|
holding the polygon and it's holes. */
|
||||||
|
bool tessellate3DFaceWithHolesNew(std::vector<CGAL_Polygon_3> &polygons,
|
||||||
|
Polygons &triangles,
|
||||||
|
CGAL_Plane_3 &plane)
|
||||||
|
{
|
||||||
|
if (polygons.size()==1 && polygons[0].size()==3) {
|
||||||
|
PRINTD("input polygon has 3 points. shortcut tessellation.");
|
||||||
|
Polygon t;
|
||||||
|
t.push_back(Vector3d(CGAL::to_double(polygons[0][0].x()), CGAL::to_double(polygons[0][0].y()), CGAL::to_double(polygons[0][0].z())));
|
||||||
|
t.push_back(Vector3d(CGAL::to_double(polygons[0][1].x()), CGAL::to_double(polygons[0][1].y()), CGAL::to_double(polygons[0][1].z())));
|
||||||
|
t.push_back(Vector3d(CGAL::to_double(polygons[0][2].x()), CGAL::to_double(polygons[0][2].y()), CGAL::to_double(polygons[0][2].z())));
|
||||||
|
triangles.push_back( t );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool err = false;
|
||||||
|
CDT cdt;
|
||||||
|
std::map<CDTPoint,CGAL_Point_3> vertmap;
|
||||||
|
|
||||||
|
PRINTD("finding good projection");
|
||||||
|
projection_t goodproj = find_good_projection( plane );
|
||||||
|
|
||||||
|
PRINTDB("plane %s",plane );
|
||||||
|
PRINTDB("proj: %i %i",goodproj.plane % goodproj.flip);
|
||||||
|
PRINTD("Inserting points and edges into Constrained Delaunay Triangulation");
|
||||||
|
std::vector< std::vector<CGAL_Point_2> > polygons2d;
|
||||||
|
for (size_t i=0;i<polygons.size();i++) {
|
||||||
|
std::vector<Vertex_handle> vhandles;
|
||||||
|
std::vector<CGAL_Point_2> polygon2d;
|
||||||
|
for (size_t j=0;j<polygons[i].size();j++) {
|
||||||
|
CGAL_Point_3 p3 = polygons[i][j];
|
||||||
|
CGAL_Point_2 p2 = get_projected_point( p3, goodproj );
|
||||||
|
CDTPoint cdtpoint = CDTPoint( p2.x(), p2.y() );
|
||||||
|
vertmap[ cdtpoint ] = p3;
|
||||||
|
Vertex_handle vh = cdt.push_back( cdtpoint );
|
||||||
|
vhandles.push_back( vh );
|
||||||
|
polygon2d.push_back( p2 );
|
||||||
|
}
|
||||||
|
polygons2d.push_back( polygon2d );
|
||||||
|
for (size_t k=0;k<vhandles.size();k++) {
|
||||||
|
int vindex1 = (k+0);
|
||||||
|
int vindex2 = (k+1)%vhandles.size();
|
||||||
|
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
|
||||||
|
try {
|
||||||
|
cdt.insert_constraint( vhandles[vindex1], vhandles[vindex2] );
|
||||||
|
} catch (const CGAL::Failure_exception &e) {
|
||||||
|
PRINTB("WARNING: Constraint insertion failure %s", e.what());
|
||||||
|
}
|
||||||
|
CGAL::set_error_behaviour(old_behaviour);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t numholes = polygons2d.size()-1;
|
||||||
|
PRINTDB("seeding %i holes",numholes);
|
||||||
|
std::list<CDTPoint> list_of_seeds;
|
||||||
|
for (size_t i=1;i<polygons2d.size();i++) {
|
||||||
|
std::vector<CGAL_Point_2> &pgon = polygons2d[i];
|
||||||
|
for (size_t j=0;j<pgon.size();j++) {
|
||||||
|
CGAL_Point_2 p1 = pgon[(j+0)];
|
||||||
|
CGAL_Point_2 p2 = pgon[(j+1)%pgon.size()];
|
||||||
|
CGAL_Point_2 p3 = pgon[(j+2)%pgon.size()];
|
||||||
|
CGAL_Point_2 mp = CGAL::midpoint(p1,CGAL::midpoint(p2,p3));
|
||||||
|
if (inside(mp,pgon,NONZERO_WINDING)) {
|
||||||
|
CDTPoint cdtpt( mp.x(), mp.y() );
|
||||||
|
list_of_seeds.push_back( cdtpt );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::list<CDTPoint>::iterator li = list_of_seeds.begin();
|
||||||
|
for (;li!=list_of_seeds.end();li++) {
|
||||||
|
//PRINTB("seed %s",*li);
|
||||||
|
double x = CGAL::to_double( li->x() );
|
||||||
|
double y = CGAL::to_double( li->y() );
|
||||||
|
PRINTDB("seed %f,%f",x%y);
|
||||||
|
}
|
||||||
|
PRINTD("seeding done");
|
||||||
|
|
||||||
|
PRINTD( "meshing" );
|
||||||
|
CGAL::refine_Delaunay_mesh_2_without_edge_refinement( cdt,
|
||||||
|
list_of_seeds.begin(), list_of_seeds.end(),
|
||||||
|
DummyCriteria<CDT>() );
|
||||||
|
|
||||||
|
PRINTD("meshing done");
|
||||||
|
// this fails because it calls is_simple and is_simple fails on many
|
||||||
|
// Nef Polyhedron faces
|
||||||
|
//CGAL::Orientation original_orientation =
|
||||||
|
// CGAL::orientation_2( orienpgon.begin(), orienpgon.end() );
|
||||||
|
|
||||||
|
CDT::Finite_faces_iterator fit;
|
||||||
|
for( fit=cdt.finite_faces_begin(); fit!=cdt.finite_faces_end(); fit++ )
|
||||||
|
{
|
||||||
|
if(fit->is_in_domain()) {
|
||||||
|
CDTPoint p1 = cdt.triangle( fit )[0];
|
||||||
|
CDTPoint p2 = cdt.triangle( fit )[1];
|
||||||
|
CDTPoint p3 = cdt.triangle( fit )[2];
|
||||||
|
CGAL_Point_3 cp1,cp2,cp3;
|
||||||
|
if (vertmap.count(p1)) cp1 = vertmap[p1];
|
||||||
|
else err = deproject( p1, goodproj, plane, cp1 );
|
||||||
|
if (vertmap.count(p2)) cp2 = vertmap[p2];
|
||||||
|
else err = deproject( p2, goodproj, plane, cp2 );
|
||||||
|
if (vertmap.count(p3)) cp3 = vertmap[p3];
|
||||||
|
else err = deproject( p3, goodproj, plane, cp3 );
|
||||||
|
if (err) PRINT("WARNING: 2d->3d deprojection failure");
|
||||||
|
Polygon tri;
|
||||||
|
tri.push_back(Vector3d(CGAL::to_double(cp1.x()), CGAL::to_double(cp1.y()), CGAL::to_double(cp1.z())));
|
||||||
|
tri.push_back(Vector3d(CGAL::to_double(cp2.x()), CGAL::to_double(cp2.y()), CGAL::to_double(cp2.z())));
|
||||||
|
tri.push_back(Vector3d(CGAL::to_double(cp3.x()), CGAL::to_double(cp3.y()), CGAL::to_double(cp3.z())));
|
||||||
|
triangles.push_back( tri );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINTDB("built %i triangles",triangles.size());
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* given a single near-planar 3d polygon with holes, tessellate into a
|
||||||
|
sequence of polygons without holes. as of writing, this means conversion
|
||||||
|
into a sequence of 3d triangles. the given plane should be the same plane
|
||||||
|
holding the polygon and it's holes. */
|
||||||
|
bool tessellate3DFaceWithHoles(std::vector<CGAL_Polygon_3> &polygons,
|
||||||
|
std::vector<CGAL_Polygon_3> &triangles,
|
||||||
|
CGAL_Plane_3 &plane)
|
||||||
|
{
|
||||||
|
if (polygons.size()==1 && polygons[0].size()==3) {
|
||||||
|
PRINTD("input polygon has 3 points. shortcut tessellation.");
|
||||||
|
CGAL_Polygon_3 t;
|
||||||
|
t.push_back(polygons[0][2]);
|
||||||
|
t.push_back(polygons[0][1]);
|
||||||
|
t.push_back(polygons[0][0]);
|
||||||
|
triangles.push_back( t );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool err = false;
|
||||||
|
CDT cdt;
|
||||||
|
std::map<CDTPoint,CGAL_Point_3> vertmap;
|
||||||
|
|
||||||
|
PRINTD("finding good projection");
|
||||||
|
projection_t goodproj = find_good_projection( plane );
|
||||||
|
|
||||||
|
PRINTDB("plane %s",plane );
|
||||||
|
PRINTDB("proj: %i %i",goodproj.plane % goodproj.flip);
|
||||||
|
PRINTD("Inserting points and edges into Constrained Delaunay Triangulation");
|
||||||
|
std::vector< std::vector<CGAL_Point_2> > polygons2d;
|
||||||
|
for (size_t i=0;i<polygons.size();i++) {
|
||||||
|
std::vector<Vertex_handle> vhandles;
|
||||||
|
std::vector<CGAL_Point_2> polygon2d;
|
||||||
|
for (size_t j=0;j<polygons[i].size();j++) {
|
||||||
|
CGAL_Point_3 p3 = polygons[i][j];
|
||||||
|
CGAL_Point_2 p2 = get_projected_point( p3, goodproj );
|
||||||
|
CDTPoint cdtpoint = CDTPoint( p2.x(), p2.y() );
|
||||||
|
vertmap[ cdtpoint ] = p3;
|
||||||
|
Vertex_handle vh = cdt.push_back( cdtpoint );
|
||||||
|
vhandles.push_back( vh );
|
||||||
|
polygon2d.push_back( p2 );
|
||||||
|
}
|
||||||
|
polygons2d.push_back( polygon2d );
|
||||||
|
for (size_t k=0;k<vhandles.size();k++) {
|
||||||
|
int vindex1 = (k+0);
|
||||||
|
int vindex2 = (k+1)%vhandles.size();
|
||||||
|
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
|
||||||
|
try {
|
||||||
|
cdt.insert_constraint( vhandles[vindex1], vhandles[vindex2] );
|
||||||
|
} catch (const CGAL::Failure_exception &e) {
|
||||||
|
PRINTB("WARNING: Constraint insertion failure %s", e.what());
|
||||||
|
}
|
||||||
|
CGAL::set_error_behaviour(old_behaviour);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t numholes = polygons2d.size()-1;
|
||||||
|
PRINTDB("seeding %i holes",numholes);
|
||||||
|
std::list<CDTPoint> list_of_seeds;
|
||||||
|
for (size_t i=1;i<polygons2d.size();i++) {
|
||||||
|
std::vector<CGAL_Point_2> &pgon = polygons2d[i];
|
||||||
|
for (size_t j=0;j<pgon.size();j++) {
|
||||||
|
CGAL_Point_2 p1 = pgon[(j+0)];
|
||||||
|
CGAL_Point_2 p2 = pgon[(j+1)%pgon.size()];
|
||||||
|
CGAL_Point_2 p3 = pgon[(j+2)%pgon.size()];
|
||||||
|
CGAL_Point_2 mp = CGAL::midpoint(p1,CGAL::midpoint(p2,p3));
|
||||||
|
if (inside(mp,pgon,NONZERO_WINDING)) {
|
||||||
|
CDTPoint cdtpt( mp.x(), mp.y() );
|
||||||
|
list_of_seeds.push_back( cdtpt );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::list<CDTPoint>::iterator li = list_of_seeds.begin();
|
||||||
|
for (;li!=list_of_seeds.end();li++) {
|
||||||
|
//PRINTB("seed %s",*li);
|
||||||
|
double x = CGAL::to_double( li->x() );
|
||||||
|
double y = CGAL::to_double( li->y() );
|
||||||
|
PRINTDB("seed %f,%f",x%y);
|
||||||
|
}
|
||||||
|
PRINTD("seeding done");
|
||||||
|
|
||||||
|
PRINTD( "meshing" );
|
||||||
|
CGAL::refine_Delaunay_mesh_2_without_edge_refinement( cdt,
|
||||||
|
list_of_seeds.begin(), list_of_seeds.end(),
|
||||||
|
DummyCriteria<CDT>() );
|
||||||
|
|
||||||
|
PRINTD("meshing done");
|
||||||
|
// this fails because it calls is_simple and is_simple fails on many
|
||||||
|
// Nef Polyhedron faces
|
||||||
|
//CGAL::Orientation original_orientation =
|
||||||
|
// CGAL::orientation_2( orienpgon.begin(), orienpgon.end() );
|
||||||
|
|
||||||
|
CDT::Finite_faces_iterator fit;
|
||||||
|
for( fit=cdt.finite_faces_begin(); fit!=cdt.finite_faces_end(); fit++ )
|
||||||
|
{
|
||||||
|
if(fit->is_in_domain()) {
|
||||||
|
CDTPoint p1 = cdt.triangle( fit )[0];
|
||||||
|
CDTPoint p2 = cdt.triangle( fit )[1];
|
||||||
|
CDTPoint p3 = cdt.triangle( fit )[2];
|
||||||
|
CGAL_Point_3 cp1,cp2,cp3;
|
||||||
|
CGAL_Polygon_3 pgon;
|
||||||
|
if (vertmap.count(p1)) cp1 = vertmap[p1];
|
||||||
|
else err = deproject( p1, goodproj, plane, cp1 );
|
||||||
|
if (vertmap.count(p2)) cp2 = vertmap[p2];
|
||||||
|
else err = deproject( p2, goodproj, plane, cp2 );
|
||||||
|
if (vertmap.count(p3)) cp3 = vertmap[p3];
|
||||||
|
else err = deproject( p3, goodproj, plane, cp3 );
|
||||||
|
if (err) PRINT("WARNING: 2d->3d deprojection failure");
|
||||||
|
pgon.push_back( cp1 );
|
||||||
|
pgon.push_back( cp2 );
|
||||||
|
pgon.push_back( cp3 );
|
||||||
|
triangles.push_back( pgon );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINTDB("built %i triangles",triangles.size());
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
|
@ -1,433 +1,198 @@
|
||||||
/*
|
|
||||||
|
|
||||||
This is our custom tessellator of Nef Polyhedron faces. The problem with
|
|
||||||
Nef faces is that sometimes the 'default' tessellator of Nef Polyhedron
|
|
||||||
doesnt work. This is particularly true with situations where the polygon
|
|
||||||
face is not, actually, 'simple', according to CGAL itself. This can
|
|
||||||
occur on a bad quality STL import but also for other reasons. The
|
|
||||||
resulting Nef face will appear to the average human eye as an ordinary,
|
|
||||||
simple polygon... but in reality it has multiple edges that are
|
|
||||||
slightly-out-of-alignment and sometimes they backtrack on themselves.
|
|
||||||
|
|
||||||
When the triangulator is fed a polygon with self-intersecting edges,
|
|
||||||
it's default behavior is to throw an exception. The other terminology
|
|
||||||
for this is to say that the 'constraints' in the triangulation are
|
|
||||||
'intersecting'. The 'constraints' represent the edges of the polygon.
|
|
||||||
The 'triangulation' is the covering of all the polygon points with
|
|
||||||
triangles.
|
|
||||||
|
|
||||||
How do we allow interseting constraints during triangulation? We use an
|
|
||||||
'Itag' for the triangulation, per the CGAL docs. This allows the
|
|
||||||
triangulator to run without throwing an exception when it encounters
|
|
||||||
self-intersecting polygon edges. The trick here is that when it finds
|
|
||||||
an intersection, it actually creates a new point.
|
|
||||||
|
|
||||||
The triangulator creates new points in 2d, but they aren't matched to
|
|
||||||
any 3d points on our 3d polygon plane. (The plane of the Nef face). How
|
|
||||||
to fix this problem? We actually 'project back up' or 'lift' into the 3d
|
|
||||||
plane from the 2d point. This is handled in the 'deproject()' function.
|
|
||||||
|
|
||||||
There is also the issue of the Simplicity of Nef Polyhedron face
|
|
||||||
polygons. They are often not simple. The intersecting-constraints
|
|
||||||
Triangulation can triangulate non-simple polygons, but of course it's
|
|
||||||
result is also non-simple. This means that CGAL functions like
|
|
||||||
orientation_2() and bounded_side() simply will not work on the resulting
|
|
||||||
polygons because they all require input polygons to pass the
|
|
||||||
'is_simple2()' test. We have to use alternatives in order to create our
|
|
||||||
triangles.
|
|
||||||
|
|
||||||
There is also the question of which underlying number type to use. Some
|
|
||||||
of the CGAL functions simply dont guarantee good results with a type
|
|
||||||
like double. Although much the math here is somewhat simple, like
|
|
||||||
line-line intersection, and involves only simple algebra, the
|
|
||||||
approximations required when using floating-point types can cause the
|
|
||||||
answers to be wrong. For example questions like 'is a point inside a
|
|
||||||
triangle' do not have good answers under floating-point systems where a
|
|
||||||
line may have a slope that is not expressible exactly as a floating
|
|
||||||
point number. There are ways to deal with floating point inaccuracy but
|
|
||||||
it is much, much simpler to use Rational numbers, although potentially
|
|
||||||
much slower in many cases.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "cgalutils.h"
|
#include "cgalutils.h"
|
||||||
#include <CGAL/Delaunay_mesher_no_edge_refinement_2.h>
|
//#include "cgal.h"
|
||||||
#include <CGAL/Delaunay_mesh_face_base_2.h>
|
//#include "tess.h"
|
||||||
|
|
||||||
typedef CGAL_Kernel3 Kernel;
|
#ifdef NDEBUG
|
||||||
//typedef CGAL::Triangulation_vertex_base_2<Kernel> Vb;
|
#define PREV_NDEBUG NDEBUG
|
||||||
typedef CGAL::Triangulation_vertex_base_2<Kernel> Vb;
|
#undef NDEBUG
|
||||||
//typedef CGAL::Constrained_triangulation_face_base_2<Kernel> Fb;
|
#endif
|
||||||
typedef CGAL::Delaunay_mesh_face_base_2<Kernel> Fb;
|
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
|
||||||
typedef CGAL::Triangulation_data_structure_2<Vb,Fb> TDS;
|
#include <CGAL/Triangulation_2_filtered_projection_traits_3.h>
|
||||||
typedef CGAL::Exact_intersections_tag ITAG;
|
#include <CGAL/Triangulation_face_base_with_info_2.h>
|
||||||
typedef CGAL::Constrained_Delaunay_triangulation_2<Kernel,TDS,ITAG> CDT;
|
#ifdef PREV_NDEBUG
|
||||||
//typedef CGAL::Constrained_Delaunay_triangulation_2<Kernel,TDS> CDT;
|
#define NDEBUG PREV_NDEBUG
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef CDT::Vertex_handle Vertex_handle;
|
#include <boost/foreach.hpp>
|
||||||
typedef CDT::Point CDTPoint;
|
|
||||||
|
|
||||||
typedef CGAL::Ray_2<Kernel> CGAL_Ray_2;
|
|
||||||
typedef CGAL::Line_3<Kernel> CGAL_Line_3;
|
|
||||||
typedef CGAL::Point_2<Kernel> CGAL_Point_2;
|
|
||||||
typedef CGAL::Vector_2<Kernel> CGAL_Vector_2;
|
|
||||||
typedef CGAL::Segment_2<Kernel> CGAL_Segment_2;
|
|
||||||
typedef CGAL::Direction_2<Kernel> CGAL_Direction_2;
|
|
||||||
typedef CGAL::Direction_3<Kernel> CGAL_Direction_3;
|
|
||||||
typedef CGAL::Plane_3<Kernel> CGAL_Plane_3;
|
|
||||||
|
|
||||||
/* The idea of 'projection' is how we make 3d points appear as though
|
struct FaceInfo {
|
||||||
they were 2d points to the tessellation algorithm. We take the 3-d plane
|
int nesting_level;
|
||||||
on which the polygon lies, and then 'project' or 'cast its shadow' onto
|
bool in_domain() { return nesting_level%2 == 1; }
|
||||||
one of three standard planes, the xyplane, the yzplane, or the xzplane,
|
|
||||||
depending on which projection will prevent the polygon looking like a
|
|
||||||
flat line. (imagine, the triangle 0,0,1 0,1,1 0,1,0 ... if viewed from
|
|
||||||
the 'top' it looks line a flat line. so we want to view it from the
|
|
||||||
side). Thus we create a sequence of x,y points to feed to the algorithm,
|
|
||||||
but those points might actually be x,z pairs or y,z pairs... it is an
|
|
||||||
illusion we present to the triangulation algorithm by way of 'projection'.
|
|
||||||
We get a resulting sequence of triangles with x,y coordinates, which we
|
|
||||||
then 'deproject' back to x,z or y,z, in 3d space as needed. For example
|
|
||||||
the square 0,0,0 0,0,1 0,1,1 0,1,0 becomes '0,0 0,1 1,1 1,0', is then
|
|
||||||
split into two triangles, 0,0 1,0 1,1 and 0,0 1,1 0,1. those two triangles
|
|
||||||
then are projected back to 3d as 0,0,0 0,1,0 0,1,1 and 0,0 0,1,1 0,0,1.
|
|
||||||
|
|
||||||
There is an additional trick we do with projection related to Polygon
|
|
||||||
orientation and the orientation of our output triangles, and thus, which
|
|
||||||
way they are facing in space (aka their 'normals' or 'oriented side').
|
|
||||||
|
|
||||||
The basic issues is this: every 3d flat polygon can be thought of as
|
|
||||||
having two sides. In Computer Graphics the convention is that the
|
|
||||||
'outside' or 'oriented side' or 'normal' is determined by looking at the
|
|
||||||
triangle in terms of the 'ordering' or 'winding' of the points. If the
|
|
||||||
points come in a 'clockwise' order, you must be looking at the triangle
|
|
||||||
from 'inside'. If the points come in a 'counterclockwise' order, you
|
|
||||||
must be looking at the triangle from the outside. For example, the
|
|
||||||
triangle 0,0,0 1,0,0 0,1,0, when viewed from the 'top', has points in a
|
|
||||||
counterclockwise order, so the 'up' side is the 'normal' or 'outside'.
|
|
||||||
if you look at that same triangle from the 'bottom' side, the points
|
|
||||||
will appear to be 'clockwise', so the 'down' side is the 'inside', and is the
|
|
||||||
opposite of the 'normal' side.
|
|
||||||
|
|
||||||
How do we keep track of all that when doing a triangulation? We could
|
|
||||||
check each triangle as it was generated, and fix it's orientation before
|
|
||||||
we feed it back to our output list. That is done by, for example, checking
|
|
||||||
the orientation of the input polygon and then forcing the triangle to
|
|
||||||
match that orientation during output. This is what CGAL's Nef Polyhedron
|
|
||||||
does, you can read it inside /usr/include/CGAL/Nef_polyhedron_3.h.
|
|
||||||
|
|
||||||
Or.... we could actually add an additional 'projection' to the incoming
|
|
||||||
polygon points so that our triangulation algorithm is guaranteed to
|
|
||||||
create triangles with the proper orientation in the first place. How?
|
|
||||||
First, we assume that the triangulation algorithm will always produce
|
|
||||||
'counterclockwise' triangles in our plain old x-y plane.
|
|
||||||
|
|
||||||
The method is based on the following curious fact: That is, if you take
|
|
||||||
the points of a polygon, and flip the x,y coordinate of each point,
|
|
||||||
making y:=x and x:=y, then you essentially get a 'mirror image' of the
|
|
||||||
original polygon... but the orientation will be flipped. Given a
|
|
||||||
clockwise polygon, the 'flip' will result in a 'counterclockwise'
|
|
||||||
polygon mirror-image and vice versa.
|
|
||||||
|
|
||||||
Now, there is a second curious fact that helps us here. In 3d, we are
|
|
||||||
using the plane equation of ax+by+cz+d=0, where a,b,c determine its
|
|
||||||
direction. If you notice, there are actually mutiple sets of numbers
|
|
||||||
a:b:c that will describe the exact same plane. For example the 'ground'
|
|
||||||
plane, called the XYplane, where z is everywhere 0, has the equation
|
|
||||||
0x+0y+1z+0=0, simplifying to a solution for x,y,z of z=0 and x,y = any
|
|
||||||
numbers in your number system. However you can also express this as
|
|
||||||
0x+0y+-1z=0. The x,y,z solution is the same: z is everywhere 0, x and y
|
|
||||||
are any number, even though a,b,c are different. We can say that the
|
|
||||||
plane is 'oriented' differently, if we wish.
|
|
||||||
|
|
||||||
But how can we link that concept to the points on the polygon? Well, if
|
|
||||||
you generate a plane using the standard plane-equation generation
|
|
||||||
formula, given three points M,N,P, then you will get a plane equation
|
|
||||||
with <a:b:c:d>. However if you feed the points in the reverse order,
|
|
||||||
P,N,M, so that they are now oriented in the opposite order, you will get
|
|
||||||
a plane equation with the signs flipped. <-a:-b:-c:-d> This means you
|
|
||||||
can essentially consider that a plane has an 'orientation' based on it's
|
|
||||||
equation, by looking at the signs of a,b,c relative to some other
|
|
||||||
quantity.
|
|
||||||
|
|
||||||
This means that you can 'flip' the projection of the input polygon
|
|
||||||
points so that the projection will match the orientation of the input
|
|
||||||
plane, thus guaranteeing that the output triangles will be oriented in
|
|
||||||
the same direction as the input polygon was. In other words, even though
|
|
||||||
we technically 'lose information' when we project from 3d->2d, we can
|
|
||||||
actually keep the concept of 'orientation' through the whole
|
|
||||||
triangulation process, and not have to recalculate the proper
|
|
||||||
orientation during output.
|
|
||||||
|
|
||||||
For example take two side-squares of a cube and the plane equations
|
|
||||||
formed by feeding the points in counterclockwise, as if looking in from
|
|
||||||
outside the cube:
|
|
||||||
|
|
||||||
0,0,0 0,1,0 0,1,1 0,0,1 <-1:0:0:0>
|
|
||||||
1,0,0 1,1,0 1,1,1 1,0,1 <1:0:0:1>
|
|
||||||
|
|
||||||
They are both projected onto the YZ plane. They look the same:
|
|
||||||
0,0 1,0 1,1 0,1
|
|
||||||
0,0 1,0 1,1 0,1
|
|
||||||
|
|
||||||
But the second square plane has opposite orientation, so we flip the x
|
|
||||||
and y for each point:
|
|
||||||
0,0 1,0 1,1 0,1
|
|
||||||
0,0 0,1 1,1 1,0
|
|
||||||
|
|
||||||
Only now do we feed these two 2-d squares to the tessellation algorithm.
|
|
||||||
The result is 4 triangles. When de-projected back to 3d, they will have
|
|
||||||
the appropriate winding that will match that of the original 3d faces.
|
|
||||||
And the first two triangles will have opposite orientation from the last two.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef enum { XYPLANE, YZPLANE, XZPLANE, NONE } plane_t;
|
|
||||||
struct projection_t {
|
|
||||||
plane_t plane;
|
|
||||||
bool flip;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
CGAL_Point_2 get_projected_point( CGAL_Point_3 &p3, projection_t projection ) {
|
typedef CGAL::Triangulation_2_filtered_projection_traits_3<K> Projection;
|
||||||
NT3 x,y;
|
typedef CGAL::Triangulation_face_base_with_info_2<FaceInfo, K> Fbb;
|
||||||
if (projection.plane == XYPLANE) { x = p3.x(); y = p3.y(); }
|
typedef CGAL::Triangulation_data_structure_2<
|
||||||
else if (projection.plane == XZPLANE) { x = p3.x(); y = p3.z(); }
|
CGAL::Triangulation_vertex_base_2<Projection>,
|
||||||
else if (projection.plane == YZPLANE) { x = p3.y(); y = p3.z(); }
|
CGAL::Constrained_triangulation_face_base_2<Projection, Fbb> > Tds;
|
||||||
else if (projection.plane == NONE) { x = 0; y = 0; }
|
typedef CGAL::Constrained_Delaunay_triangulation_2<
|
||||||
if (projection.flip) return CGAL_Point_2( y,x );
|
Projection, Tds, CGAL::Exact_predicates_tag> CDT;
|
||||||
return CGAL_Point_2( x,y );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* given 2d point, 3d plane, and 3d->2d projection, 'deproject' from
|
|
||||||
2d back onto a point on the 3d plane. true on failure, false on success */
|
static void mark_domains(CDT &ct,
|
||||||
bool deproject( CGAL_Point_2 &p2, projection_t &projection, CGAL_Plane_3 &plane, CGAL_Point_3 &p3 )
|
CDT::Face_handle start,
|
||||||
|
int index,
|
||||||
|
std::list<CDT::Edge>& border)
|
||||||
{
|
{
|
||||||
NT3 x,y;
|
if (start->info().nesting_level != -1) return;
|
||||||
CGAL_Line_3 l;
|
std::list<CDT::Face_handle> queue;
|
||||||
CGAL_Point_3 p;
|
queue.push_back(start);
|
||||||
CGAL_Point_2 pf( p2.x(), p2.y() );
|
while (!queue.empty()) {
|
||||||
if (projection.flip) pf = CGAL_Point_2( p2.y(), p2.x() );
|
CDT::Face_handle fh = queue.front();
|
||||||
if (projection.plane == XYPLANE) {
|
queue.pop_front();
|
||||||
p = CGAL_Point_3( pf.x(), pf.y(), 0 );
|
if (fh->info().nesting_level == -1) {
|
||||||
l = CGAL_Line_3( p, CGAL_Direction_3(0,0,1) );
|
fh->info().nesting_level = index;
|
||||||
} else if (projection.plane == XZPLANE) {
|
for (int i = 0; i < 3; i++) {
|
||||||
p = CGAL_Point_3( pf.x(), 0, pf.y() );
|
CDT::Edge e(fh,i);
|
||||||
l = CGAL_Line_3( p, CGAL_Direction_3(0,1,0) );
|
CDT::Face_handle n = fh->neighbor(i);
|
||||||
} else if (projection.plane == YZPLANE) {
|
if (n->info().nesting_level == -1) {
|
||||||
p = CGAL_Point_3( 0, pf.x(), pf.y() );
|
if (ct.is_constrained(e)) border.push_back(e);
|
||||||
l = CGAL_Line_3( p, CGAL_Direction_3(1,0,0) );
|
else queue.push_back(n);
|
||||||
}
|
}
|
||||||
CGAL::Object obj = CGAL::intersection( l, plane );
|
}
|
||||||
const CGAL_Point_3 *point_test = CGAL::object_cast<CGAL_Point_3>(&obj);
|
}
|
||||||
if (point_test) {
|
}
|
||||||
p3 = *point_test;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
PRINT("ERROR: deproject failure");
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* this simple criteria guarantees CGALs triangulation algorithm will
|
|
||||||
terminate (i.e. not lock up and freeze the program) */
|
|
||||||
template <class T> class DummyCriteria {
|
|
||||||
public:
|
|
||||||
typedef double Quality;
|
|
||||||
class Is_bad {
|
|
||||||
public:
|
|
||||||
CGAL::Mesh_2::Face_badness operator()(const Quality) const {
|
|
||||||
return CGAL::Mesh_2::NOT_BAD;
|
|
||||||
}
|
|
||||||
CGAL::Mesh_2::Face_badness operator()(const typename T::Face_handle&, Quality&q) const {
|
|
||||||
q = 1;
|
|
||||||
return CGAL::Mesh_2::NOT_BAD;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Is_bad is_bad_object() const { return Is_bad(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
NT3 sign( const NT3 &n )
|
//explore set of facets connected with non constrained edges,
|
||||||
|
//and attribute to each such set a nesting level.
|
||||||
|
//We start from facets incident to the infinite vertex, with a nesting
|
||||||
|
//level of 0. Then we recursively consider the non-explored facets incident
|
||||||
|
//to constrained edges bounding the former set and increase the nesting level by 1.
|
||||||
|
//Facets in the domain are those with an odd nesting level.
|
||||||
|
static void mark_domains(CDT& cdt)
|
||||||
{
|
{
|
||||||
if (n>0) return NT3(1);
|
for(CDT::All_faces_iterator it = cdt.all_faces_begin(); it != cdt.all_faces_end(); ++it) {
|
||||||
if (n<0) return NT3(-1);
|
it->info().nesting_level = -1;
|
||||||
return NT3(0);
|
}
|
||||||
}
|
std::list<CDT::Edge> border;
|
||||||
|
mark_domains(cdt, cdt.infinite_face(), 0, border);
|
||||||
/* wedge, also related to 'determinant', 'signed parallelogram area',
|
while (!border.empty()) {
|
||||||
'side', 'turn', 'winding', '2d portion of cross-product', etc etc. this
|
CDT::Edge e = border.front();
|
||||||
function can tell you whether v1 is 'counterclockwise' or 'clockwise'
|
border.pop_front();
|
||||||
from v2, based on the sign of the result. when the input Vectors are
|
CDT::Face_handle n = e.first->neighbor(e.second);
|
||||||
formed from three points, A-B and B-C, it can tell you if the path along
|
if (n->info().nesting_level == -1) {
|
||||||
the points A->B->C is turning left or right.*/
|
mark_domains(cdt, n, e.first->info().nesting_level+1, border);
|
||||||
NT3 wedge( CGAL_Vector_2 &v1, CGAL_Vector_2 &v2 ) {
|
}
|
||||||
return v1.x()*v2.y()-v2.x()*v1.y();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* given a point and a possibly non-simple polygon, determine if the
|
|
||||||
point is inside the polygon or not, using the given winding rule. note
|
|
||||||
that even_odd is not implemented. */
|
|
||||||
typedef enum { NONZERO_WINDING, EVEN_ODD } winding_rule_t;
|
|
||||||
bool inside(CGAL_Point_2 &p1,std::vector<CGAL_Point_2> &pgon, winding_rule_t winding_rule)
|
|
||||||
{
|
|
||||||
NT3 winding_sum = NT3(0);
|
|
||||||
CGAL_Point_2 p2;
|
|
||||||
CGAL_Ray_2 eastray(p1,CGAL_Direction_2(1,0));
|
|
||||||
for (size_t i=0;i<pgon.size();i++) {
|
|
||||||
CGAL_Point_2 tail = pgon[i];
|
|
||||||
CGAL_Point_2 head = pgon[(i+1)%pgon.size()];
|
|
||||||
CGAL_Segment_2 seg( tail, head );
|
|
||||||
CGAL::Object obj = intersection( eastray, seg );
|
|
||||||
const CGAL_Point_2 *point_test = CGAL::object_cast<CGAL_Point_2>(&obj);
|
|
||||||
if (point_test) {
|
|
||||||
p2 = *point_test;
|
|
||||||
CGAL_Vector_2 v1( p1, p2 );
|
|
||||||
CGAL_Vector_2 v2( p2, head );
|
|
||||||
NT3 this_winding = wedge( v1, v2 );
|
|
||||||
winding_sum += sign(this_winding);
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (winding_sum != NT3(0) && winding_rule == NONZERO_WINDING ) return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
projection_t find_good_projection( CGAL_Plane_3 &plane )
|
|
||||||
{
|
|
||||||
projection_t goodproj;
|
|
||||||
goodproj.plane = NONE;
|
|
||||||
goodproj.flip = false;
|
|
||||||
NT3 qxy = plane.a()*plane.a()+plane.b()*plane.b();
|
|
||||||
NT3 qyz = plane.b()*plane.b()+plane.c()*plane.c();
|
|
||||||
NT3 qxz = plane.a()*plane.a()+plane.c()*plane.c();
|
|
||||||
NT3 min = std::min(qxy,std::min(qyz,qxz));
|
|
||||||
if (min==qxy) {
|
|
||||||
goodproj.plane = XYPLANE;
|
|
||||||
if (sign(plane.c())>0) goodproj.flip = true;
|
|
||||||
} else if (min==qyz) {
|
|
||||||
goodproj.plane = YZPLANE;
|
|
||||||
if (sign(plane.a())>0) goodproj.flip = true;
|
|
||||||
} else if (min==qxz) {
|
|
||||||
goodproj.plane = XZPLANE;
|
|
||||||
if (sign(plane.b())<0) goodproj.flip = true;
|
|
||||||
} else PRINT("ERROR: failed to find projection");
|
|
||||||
return goodproj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace CGALUtils {
|
namespace CGALUtils {
|
||||||
/* given a single near-planar 3d polygon with holes, tessellate into a
|
/*!
|
||||||
sequence of polygons without holes. as of writing, this means conversion
|
polygons define a polygon, potentially with holes. Each contour
|
||||||
into a sequence of 3d triangles. the given plane should be the same plane
|
should be added as a separate PolygonK instance.
|
||||||
holding the polygon and it's holes. */
|
The tessellator will handle almost planar polygons.
|
||||||
bool tessellate3DFaceWithHoles(std::vector<CGAL_Polygon_3> &polygons,
|
|
||||||
std::vector<CGAL_Polygon_3> &triangles,
|
If the normal is given, we will assume this as the normal vector of the polygon.
|
||||||
CGAL_Plane_3 &plane)
|
Otherwise, we will try to calculate it using Newell's method.
|
||||||
|
|
||||||
|
The resulting triangles is added to the given triangles vector.
|
||||||
|
*/
|
||||||
|
bool tessellatePolygonWithHoles(const PolyholeK &polygons,
|
||||||
|
Polygons &triangles,
|
||||||
|
const K::Vector_3 *normal)
|
||||||
{
|
{
|
||||||
if (polygons.size()==1 && polygons[0].size()==3) {
|
// No polygon. FIXME: Will this ever happen or can we assert here?
|
||||||
|
if (polygons.empty()) return false;
|
||||||
|
|
||||||
|
// No hole
|
||||||
|
if (polygons.size() == 1) return tessellatePolygon(polygons.front(), triangles, normal);
|
||||||
|
|
||||||
|
K::Vector_3 normalvec;
|
||||||
|
if (normal) {
|
||||||
|
normalvec = *normal;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Calculate best guess at face normal using Newell's method
|
||||||
|
CGAL::normal_vector_newell_3(polygons.front().begin(), polygons.front().end(), normalvec);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass the normal vector to the (undocumented)
|
||||||
|
// CGAL::Triangulation_2_filtered_projection_traits_3. This
|
||||||
|
// trait deals with projection from 3D to 2D using the normal
|
||||||
|
// vector as a hint, and allows for near-planar polygons to be passed to
|
||||||
|
// the Constrained Delaunay Triangulator.
|
||||||
|
Projection actualProjection(normalvec);
|
||||||
|
CDT cdt(actualProjection);
|
||||||
|
BOOST_FOREACH(const PolygonK &poly, polygons) {
|
||||||
|
for (size_t i=0;i<poly.size(); i++) {
|
||||||
|
cdt.insert_constraint(poly[i], poly[(i+1)%poly.size()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Mark facets that are inside the domain bounded by the polygon
|
||||||
|
mark_domains(cdt);
|
||||||
|
|
||||||
|
// Iterate over the resulting faces
|
||||||
|
for (CDT::Finite_faces_iterator fit = cdt.finite_faces_begin();
|
||||||
|
fit != cdt.finite_faces_end(); fit++) {
|
||||||
|
if (fit->info().in_domain()) {
|
||||||
|
Polygon tri;
|
||||||
|
for (int i=0;i<3;i++) {
|
||||||
|
Vertex3K v = cdt.triangle(fit)[i];
|
||||||
|
tri.push_back(Vector3d(v.x(), v.y(), v.z()));
|
||||||
|
}
|
||||||
|
triangles.push_back(tri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tessellatePolygon(const PolygonK &polygon,
|
||||||
|
Polygons &triangles,
|
||||||
|
const K::Vector_3 *normal)
|
||||||
|
{
|
||||||
|
if (polygon.size() == 3) {
|
||||||
PRINTD("input polygon has 3 points. shortcut tessellation.");
|
PRINTD("input polygon has 3 points. shortcut tessellation.");
|
||||||
CGAL_Polygon_3 t;
|
Polygon t;
|
||||||
t.push_back(polygons[0][2]);
|
t.push_back(Vector3d(polygon[0].x(), polygon[0].y(), polygon[0].z()));
|
||||||
t.push_back(polygons[0][1]);
|
t.push_back(Vector3d(polygon[1].x(), polygon[1].y(), polygon[1].z()));
|
||||||
t.push_back(polygons[0][0]);
|
t.push_back(Vector3d(polygon[2].x(), polygon[2].y(), polygon[2].z()));
|
||||||
triangles.push_back( t );
|
triangles.push_back(t);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool err = false;
|
|
||||||
CDT cdt;
|
|
||||||
std::map<CDTPoint,CGAL_Point_3> vertmap;
|
|
||||||
|
|
||||||
PRINTD("finding good projection");
|
K::Vector_3 normalvec;
|
||||||
projection_t goodproj = find_good_projection( plane );
|
if (normal) {
|
||||||
|
normalvec = *normal;
|
||||||
PRINTDB("plane %s",plane );
|
|
||||||
PRINTDB("proj: %i %i",goodproj.plane % goodproj.flip);
|
|
||||||
PRINTD("Inserting points and edges into Constrained Delaunay Triangulation");
|
|
||||||
std::vector< std::vector<CGAL_Point_2> > polygons2d;
|
|
||||||
for (size_t i=0;i<polygons.size();i++) {
|
|
||||||
std::vector<Vertex_handle> vhandles;
|
|
||||||
std::vector<CGAL_Point_2> polygon2d;
|
|
||||||
for (size_t j=0;j<polygons[i].size();j++) {
|
|
||||||
CGAL_Point_3 p3 = polygons[i][j];
|
|
||||||
CGAL_Point_2 p2 = get_projected_point( p3, goodproj );
|
|
||||||
CDTPoint cdtpoint = CDTPoint( p2.x(), p2.y() );
|
|
||||||
vertmap[ cdtpoint ] = p3;
|
|
||||||
Vertex_handle vh = cdt.push_back( cdtpoint );
|
|
||||||
vhandles.push_back( vh );
|
|
||||||
polygon2d.push_back( p2 );
|
|
||||||
}
|
|
||||||
polygons2d.push_back( polygon2d );
|
|
||||||
for (size_t k=0;k<vhandles.size();k++) {
|
|
||||||
int vindex1 = (k+0);
|
|
||||||
int vindex2 = (k+1)%vhandles.size();
|
|
||||||
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
|
|
||||||
try {
|
|
||||||
cdt.insert_constraint( vhandles[vindex1], vhandles[vindex2] );
|
|
||||||
} catch (const CGAL::Failure_exception &e) {
|
|
||||||
PRINTB("WARNING: Constraint insertion failure %s", e.what());
|
|
||||||
}
|
|
||||||
CGAL::set_error_behaviour(old_behaviour);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
size_t numholes = polygons2d.size()-1;
|
// Calculate best guess at face normal using Newell's method
|
||||||
PRINTDB("seeding %i holes",numholes);
|
CGAL::normal_vector_newell_3(polygon.begin(), polygon.end(), normalvec);
|
||||||
std::list<CDTPoint> list_of_seeds;
|
|
||||||
for (size_t i=1;i<polygons2d.size();i++) {
|
|
||||||
std::vector<CGAL_Point_2> &pgon = polygons2d[i];
|
|
||||||
for (size_t j=0;j<pgon.size();j++) {
|
|
||||||
CGAL_Point_2 p1 = pgon[(j+0)];
|
|
||||||
CGAL_Point_2 p2 = pgon[(j+1)%pgon.size()];
|
|
||||||
CGAL_Point_2 p3 = pgon[(j+2)%pgon.size()];
|
|
||||||
CGAL_Point_2 mp = CGAL::midpoint(p1,CGAL::midpoint(p2,p3));
|
|
||||||
if (inside(mp,pgon,NONZERO_WINDING)) {
|
|
||||||
CDTPoint cdtpt( mp.x(), mp.y() );
|
|
||||||
list_of_seeds.push_back( cdtpt );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
std::list<CDTPoint>::iterator li = list_of_seeds.begin();
|
|
||||||
for (;li!=list_of_seeds.end();li++) {
|
// Pass the normal vector to the (undocumented)
|
||||||
//PRINTB("seed %s",*li);
|
// CGAL::Triangulation_2_filtered_projection_traits_3. This
|
||||||
double x = CGAL::to_double( li->x() );
|
// trait deals with projection from 3D to 2D using the normal
|
||||||
double y = CGAL::to_double( li->y() );
|
// vector as a hint, and allows for near-planar polygons to be passed to
|
||||||
PRINTDB("seed %f,%f",x%y);
|
// the Constrained Delaunay Triangulator.
|
||||||
|
Projection actualProjection(normalvec);
|
||||||
|
CDT cdt(actualProjection);
|
||||||
|
for (size_t i=0;i<polygon.size(); i++) {
|
||||||
|
cdt.insert_constraint(polygon[i], polygon[(i+1)%polygon.size()]);
|
||||||
}
|
}
|
||||||
PRINTD("seeding done");
|
|
||||||
|
//Mark facets that are inside the domain bounded by the polygon
|
||||||
PRINTD( "meshing" );
|
mark_domains(cdt);
|
||||||
CGAL::refine_Delaunay_mesh_2_without_edge_refinement( cdt,
|
|
||||||
list_of_seeds.begin(), list_of_seeds.end(),
|
|
||||||
DummyCriteria<CDT>() );
|
|
||||||
|
|
||||||
PRINTD("meshing done");
|
|
||||||
// this fails because it calls is_simple and is_simple fails on many
|
|
||||||
// Nef Polyhedron faces
|
|
||||||
//CGAL::Orientation original_orientation =
|
|
||||||
// CGAL::orientation_2( orienpgon.begin(), orienpgon.end() );
|
|
||||||
|
|
||||||
|
// Iterate over the resulting faces
|
||||||
CDT::Finite_faces_iterator fit;
|
CDT::Finite_faces_iterator fit;
|
||||||
for( fit=cdt.finite_faces_begin(); fit!=cdt.finite_faces_end(); fit++ )
|
for (fit=cdt.finite_faces_begin(); fit!=cdt.finite_faces_end(); fit++) {
|
||||||
{
|
if (fit->info().in_domain()) {
|
||||||
if(fit->is_in_domain()) {
|
Polygon tri;
|
||||||
CDTPoint p1 = cdt.triangle( fit )[0];
|
for (int i=0;i<3;i++) {
|
||||||
CDTPoint p2 = cdt.triangle( fit )[1];
|
K::Point_3 v = cdt.triangle(fit)[i];
|
||||||
CDTPoint p3 = cdt.triangle( fit )[2];
|
tri.push_back(Vector3d(v.x(), v.y(), v.z()));
|
||||||
CGAL_Point_3 cp1,cp2,cp3;
|
}
|
||||||
CGAL_Polygon_3 pgon;
|
triangles.push_back(tri);
|
||||||
if (vertmap.count(p1)) cp1 = vertmap[p1];
|
|
||||||
else err = deproject( p1, goodproj, plane, cp1 );
|
|
||||||
if (vertmap.count(p2)) cp2 = vertmap[p2];
|
|
||||||
else err = deproject( p2, goodproj, plane, cp2 );
|
|
||||||
if (vertmap.count(p3)) cp3 = vertmap[p3];
|
|
||||||
else err = deproject( p3, goodproj, plane, cp3 );
|
|
||||||
if (err) PRINT("WARNING: 2d->3d deprojection failure");
|
|
||||||
pgon.push_back( cp1 );
|
|
||||||
pgon.push_back( cp2 );
|
|
||||||
pgon.push_back( cp3 );
|
|
||||||
triangles.push_back( pgon );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PRINTDB("built %i triangles",triangles.size());
|
return false;
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
}; // namespace CGALUtils
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue