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
|
||||
/OpenSCAD.app
|
||||
*/#*#
|
||||
/locale/*/*/*.mo
|
||||
/locale/POTFILES
|
||||
/nbproject
|
||||
/openscad.pro.user
|
||||
/openscad
|
||||
/mingw32
|
||||
/mingw64
|
||||
/tests/openscad_nogui
|
||||
testdata/scad/features/import_dxf-tests.scad
|
||||
testdata/scad/features/import_stl-tests.scad
|
||||
|
@ -25,4 +26,4 @@ testdata/scad/misc/use-tests.scad
|
|||
/mingw32
|
||||
/mingw64
|
||||
**/project.xcworkspace
|
||||
**/xcuserdata
|
||||
**/xcuserdata
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[![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)
|
||||
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/openscad/openscad/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
|
||||
|
||||
# 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)
|
||||
|
@ -212,15 +213,16 @@ complete, build OpenSCAD and package it to an installer:
|
|||
If you wish you can only build the openscad.exe binary:
|
||||
|
||||
cd mingw32
|
||||
qmake .. CONFIG+=mingw-cross-env
|
||||
qmake ../openscad.pro CONFIG+=mingw-cross-env
|
||||
make
|
||||
|
||||
For a 64-bit Windows cross-build, replace 32 with 64 in the above instructions.
|
||||
|
||||
### Compilation
|
||||
|
||||
First, run 'qmake' from Qt4 to generate a Makefile. On some systems you need to
|
||||
run 'qmake4', 'qmake-qt4' or something alike to run the qt4 version of the tool.
|
||||
First, run 'qmake openscad.pro' from Qt4 to generate a Makefile. On some systems
|
||||
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
|
||||
'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
|
||||
macx: DEFINES += __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES=0
|
||||
|
||||
# MXE cross build
|
||||
CONFIG(mingw-cross-env) {
|
||||
DEFINES += BOOST_STATIC
|
||||
DEFINES += BOOST_THREAD_USE_LIB
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
isEmpty(BOOST_LINK_FLAGS):win* {
|
||||
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
|
||||
# MSYS2
|
||||
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
|
||||
|
|
10
cgal.pri
10
cgal.pri
|
@ -6,7 +6,6 @@ cgal {
|
|||
CGAL_DIR = $$(CGALDIR)
|
||||
!isEmpty(CGAL_DIR) {
|
||||
QMAKE_INCDIR += $$CGAL_DIR/include
|
||||
win*: QMAKE_INCDIR += $$CGAL_DIR/auxiliary/gmp/include
|
||||
QMAKE_LIBDIR += $$CGAL_DIR/lib
|
||||
message("CGAL location: $$CGAL_DIR")
|
||||
}
|
||||
|
@ -19,14 +18,13 @@ cgal {
|
|||
*-g++* {
|
||||
QMAKE_CXXFLAGS += -frounding-math
|
||||
}
|
||||
LIBS += $$CGAL_DIR/auxiliary/gmp/lib/libmpfr-4.lib -lCGAL-vc110-mt-gd
|
||||
} else {
|
||||
LIBS += -lgmp -lmpfr -lCGAL
|
||||
QMAKE_CXXFLAGS += -frounding-math
|
||||
}
|
||||
LIBS += -lCGAL -lmpfr -lgmp
|
||||
}
|
||||
|
||||
*clang* {
|
||||
QMAKE_CXXFLAGS -= -frounding-math
|
||||
}
|
||||
*clang* {
|
||||
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",
|
||||
"index" : 1100,
|
||||
"paper" : "#272822",
|
||||
"text" : "#ffffff",
|
||||
"paper" : "#222222",
|
||||
"text" : "#e0e0e0",
|
||||
"caret" : {
|
||||
"width" : 2,
|
||||
"foreground" : "#ffff00",
|
||||
"line-background" : "#68e1687f"
|
||||
"line-background" : "#303030"
|
||||
},
|
||||
"colors" : {
|
||||
"keyword1" : "#f12971",
|
||||
"keyword1" : "#90ee90",
|
||||
"keyword2" : "#56dbf0",
|
||||
"keyword3" : "#56d8f0",
|
||||
"comment" : "#ccdf32",
|
||||
"number" : "#af7dff",
|
||||
"keyword3" : "#add8e6",
|
||||
"comment" : "#808080",
|
||||
"commentline" : "#808080",
|
||||
"commentdoc" : "#808080",
|
||||
"commentdockeyword" : "#808080",
|
||||
"number" : "#ff0000",
|
||||
"string" : "#e6db74",
|
||||
"operator" : "#d8d8d8",
|
||||
"commentline" : "#e6db74",
|
||||
"selection-foreground" : "#ffff00",
|
||||
"selection-background" : "#a0a0ff",
|
||||
"margin-background" : "#14141496",
|
||||
"margin-foreground" : "#fff",
|
||||
"matched-brace-background" : "#333",
|
||||
"matched-brace-foreground" : "#fff",
|
||||
"unmatched-brace-background" : "#333",
|
||||
"unmatched-brace-foreground" : "#fff",
|
||||
"operator" : "#e8b609",
|
||||
"whitespace-foreground" : "#e0e0e0",
|
||||
"selection-foreground" : "#ffffff",
|
||||
"selection-background" : "#4a90d9",
|
||||
"margin-background" : "#272822",
|
||||
"margin-foreground" : "#e0e0e0",
|
||||
"matched-brace-background" : "#505050",
|
||||
"matched-brace-foreground" : "#ffffff",
|
||||
"unmatched-brace-background" : "#dc322f",
|
||||
"unmatched-brace-foreground" : "#fdf6e3",
|
||||
"error-marker" : "#ff0000",
|
||||
"error-indicator" : "#60ff0000",
|
||||
"error-indicator-outline" : "#ff000000",
|
||||
"edge" : "#ffffff"
|
||||
}
|
||||
}
|
|
@ -1,31 +1,36 @@
|
|||
{
|
||||
"name" : "For Light Background",
|
||||
"index" : 1000,
|
||||
"paper" : "#fff",
|
||||
"paper" : "#ffffff",
|
||||
"text" : "#272822",
|
||||
"caret" : {
|
||||
"width" : 2,
|
||||
"foreground" : "#000000",
|
||||
"line-background" : "#ffe4e4"
|
||||
"line-background" : "#f8f8f8"
|
||||
},
|
||||
"colors" : {
|
||||
"keyword1" : "Green",
|
||||
"keyword2" : "Green",
|
||||
"keyword3" : "DarkBlue",
|
||||
"comment" : "DarkCyan",
|
||||
"commentline" : "DarkCyan",
|
||||
"commentdoc" : "DarkCyan",
|
||||
"commentdockeyword" : "DarkCyan",
|
||||
"number" : "DarkRed",
|
||||
"string" : "DarkMagenta",
|
||||
"operator" : "Blue",
|
||||
"commentline" : "DarkCyan",
|
||||
"selection-foreground" : "#ffff00",
|
||||
"selection-background" : "#a0a0ff",
|
||||
"margin-background" : "#ccc",
|
||||
"margin-foreground" : "#111",
|
||||
"matched-brace-background" : "#333",
|
||||
"matched-brace-foreground" : "#fff",
|
||||
"unmatched-brace-background" : "#333",
|
||||
"unmatched-brace-foreground" : "#fff",
|
||||
"whitespace-foreground" : "#272822",
|
||||
"selection-foreground" : "#ffffff",
|
||||
"selection-background" : "#4a90d9",
|
||||
"margin-background" : "#f8f8f8",
|
||||
"margin-foreground" : "#000000",
|
||||
"matched-brace-background" : "#c7f6cb",
|
||||
"matched-brace-foreground" : "Blue",
|
||||
"unmatched-brace-background" : "#ffcdcc",
|
||||
"unmatched-brace-foreground" : "Blue",
|
||||
"error-marker" : "#ff0000",
|
||||
"error-indicator" : "#60ff0000",
|
||||
"error-indicator-outline" : "#ff000000",
|
||||
"edge" : "#ffffff"
|
||||
}
|
||||
}
|
|
@ -5,27 +5,32 @@
|
|||
"text" : "#f8f8f2",
|
||||
"caret" : {
|
||||
"width" : 2,
|
||||
"foreground" : "#ffff00",
|
||||
"line-background" : "#3e3d32"
|
||||
"foreground" : "#f8f8f2",
|
||||
"line-background" : "#49483e"
|
||||
},
|
||||
"colors" : {
|
||||
"keyword1" : "#66c3b3",
|
||||
"keyword2" : "#79abff",
|
||||
"keyword3" : "#ffffff",
|
||||
"comment" : "#ccdf32",
|
||||
"number" : "#7fb347",
|
||||
"string" : "#e6db74",
|
||||
"operator" : "#d8d8d8",
|
||||
"keyword1" : "#f92672",
|
||||
"keyword2" : "#a6e22e",
|
||||
"keyword3" : "#66d9ef",
|
||||
"comment" : "#75715e",
|
||||
"commentline" : "#75715e",
|
||||
"selection-foreground" : "#ffff00",
|
||||
"selection-background" : "#a0a0ff",
|
||||
"margin-background" : "#757575",
|
||||
"commentdoc" : "#75715e",
|
||||
"commentdockeyword" : "#7b9a3c",
|
||||
"number" : "#ae81ff",
|
||||
"string" : "#e6db74",
|
||||
"operator" : "#f8f8f2",
|
||||
"whitespace-foreground" : "#f8f8f2",
|
||||
"selection-foreground" : "#272822",
|
||||
"selection-background" : "#f8f8f2",
|
||||
"margin-background" : "#3e3d32",
|
||||
"margin-foreground" : "#f8f8f2",
|
||||
"matched-brace-background" : "#333",
|
||||
"matched-brace-foreground" : "#fff",
|
||||
"unmatched-brace-background" : "#333",
|
||||
"unmatched-brace-foreground" : "#fff",
|
||||
"matched-brace-background" : "#606060",
|
||||
"matched-brace-foreground" : "#ffff00",
|
||||
"unmatched-brace-background" : "#b06060",
|
||||
"unmatched-brace-foreground" : "#ffff00",
|
||||
"error-marker" : "#ff0000",
|
||||
"error-indicator" : "#80ffe0e0",
|
||||
"error-indicator-outline" : "#ff000000",
|
||||
"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(boost.pri)
|
||||
include(glib-2.0.pri)
|
||||
include(gettext.pri)
|
||||
include(sparkle.pri)
|
||||
include(harfbuzz.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
|
||||
# which eigen to use:
|
||||
# Detect eigen3
|
||||
#
|
||||
# Priority
|
||||
# 0. EIGENDIR if set (also EIGEN2DIR for backwards compatability)
|
||||
# 0. EIGENDIR if set
|
||||
# 1. OPENSCAD_LIBRARIES eigen3
|
||||
# 2. OPENSCAD_LIBRARIES eigen2
|
||||
# 3. system's standard include paths for eigen3
|
||||
# 4. system's standard include paths for eigen2
|
||||
|
||||
eigen {
|
||||
|
||||
# read environment variables
|
||||
OPENSCAD_LIBRARIES_DIR = $$(OPENSCAD_LIBRARIES)
|
||||
EIGEN2_DIR = $$(EIGEN2DIR)
|
||||
EIGEN_DIR = $$(EIGENDIR)
|
||||
|
||||
# Optionally specify location of Eigen3 using the
|
||||
|
@ -23,20 +19,8 @@ EIGEN_DIR = $$(EIGENDIR)
|
|||
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) {
|
||||
EIGEN_INCLUDEPATH = $$EIGEN_DIR
|
||||
message("User set EIGEN location: $$EIGEN_INCLUDEPATH")
|
||||
|
@ -47,17 +31,6 @@ isEmpty(EIGEN_INCLUDEPATH) {
|
|||
freebsd-g++: EIGEN_INCLUDEPATH = /usr/local/include/eigen3
|
||||
netbsd*: EIGEN_INCLUDEPATH = /usr/pkg/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) {
|
||||
|
@ -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\\..*) {
|
||||
QMAKE_INCDIR = $$EIGEN_INCLUDEPATH $$QMAKE_INCDIR
|
||||
} 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
|
||||
win32:LIBS += -lglew32s
|
||||
CONFIG(mingw-cross-env):DEFINES += GLEW_STATIC
|
||||
CONFIG(mingw-cross-env): {
|
||||
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
|
||||
# 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.
|
||||
#
|
||||
# http://en.wikibooks.org/wiki/OpenSCAD_User_Manual
|
||||
|
@ -74,8 +82,10 @@ macx {
|
|||
TARGET = OpenSCAD
|
||||
}
|
||||
else {
|
||||
TARGET = openscad
|
||||
TARGET = openscad$${SUFFIX}
|
||||
}
|
||||
FULLNAME = openscad$${SUFFIX}
|
||||
!isEmpty(SUFFIX): DEFINES += INSTALL_SUFFIX="\"\\\"$${SUFFIX}\\\"\""
|
||||
|
||||
macx {
|
||||
ICON = icons/OpenSCAD.icns
|
||||
|
@ -89,11 +99,18 @@ macx {
|
|||
|
||||
win* {
|
||||
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
|
||||
QT += opengl
|
||||
QT += opengl concurrent
|
||||
|
||||
# see http://fedoraproject.org/wiki/UnderstandingDSOLinkChange
|
||||
# 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-variable
|
||||
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
|
||||
QMAKE_CXXFLAGS_WARN_ON += -Wno-sign-compare
|
||||
}
|
||||
|
@ -160,6 +179,7 @@ CONFIG += glib-2.0
|
|||
CONFIG += harfbuzz
|
||||
CONFIG += freetype
|
||||
CONFIG += fontconfig
|
||||
CONFIG += gettext
|
||||
|
||||
#Uncomment the following line to enable the QScintilla editor
|
||||
CONFIG += scintilla
|
||||
|
@ -190,7 +210,12 @@ win* {
|
|||
|
||||
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/OpenCSGWarningDialog.ui \
|
||||
src/AboutDialog.ui \
|
||||
|
@ -204,6 +229,7 @@ HEADERS += src/typedefs.h \
|
|||
src/ProgressWidget.h \
|
||||
src/parsersettings.h \
|
||||
src/renderer.h \
|
||||
src/settings.h \
|
||||
src/rendersettings.h \
|
||||
src/colormap.h \
|
||||
src/ThrownTogetherRenderer.h \
|
||||
|
@ -216,6 +242,7 @@ HEADERS += src/typedefs.h \
|
|||
src/OpenCSGWarningDialog.h \
|
||||
src/AboutDialog.h \
|
||||
src/FontListDialog.h \
|
||||
src/FontListTableView.h \
|
||||
src/builtin.h \
|
||||
src/calc.h \
|
||||
src/context.h \
|
||||
|
@ -227,7 +254,9 @@ HEADERS += src/typedefs.h \
|
|||
src/dxfdim.h \
|
||||
src/export.h \
|
||||
src/expression.h \
|
||||
src/stackcheck.h \
|
||||
src/function.h \
|
||||
src/exceptions.h \
|
||||
src/grid.h \
|
||||
src/highlighter.h \
|
||||
src/localscope.h \
|
||||
|
@ -303,6 +332,7 @@ SOURCES += src/version_check.cc \
|
|||
src/handle_dep.cc \
|
||||
src/value.cc \
|
||||
src/expr.cc \
|
||||
src/stackcheck.cc \
|
||||
src/func.cc \
|
||||
src/localscope.cc \
|
||||
src/module.cc \
|
||||
|
@ -352,6 +382,7 @@ SOURCES += src/version_check.cc \
|
|||
src/FreetypeRenderer.cc \
|
||||
src/FontCache.cc \
|
||||
\
|
||||
src/settings.cc \
|
||||
src/rendersettings.cc \
|
||||
src/highlighter.cc \
|
||||
src/Preferences.cc \
|
||||
|
@ -382,6 +413,7 @@ SOURCES += src/version_check.cc \
|
|||
src/UIUtils.cc \
|
||||
src/Dock.cc \
|
||||
src/FontListDialog.cc \
|
||||
src/FontListTableView.cc \
|
||||
src/launchingscreen.cc \
|
||||
src/legacyeditor.cc \
|
||||
src/LibraryInfoDialog.cc
|
||||
|
@ -422,6 +454,8 @@ HEADERS += src/cgal.h \
|
|||
|
||||
SOURCES += src/cgalutils.cc \
|
||||
src/cgalutils-tess.cc \
|
||||
src/cgalutils-polyhedron.cc \
|
||||
src/cgalutils-tess-old.cc \
|
||||
src/CGALCache.cc \
|
||||
src/CGALRenderer.cc \
|
||||
src/CGAL_Nef_polyhedron.cc \
|
||||
|
@ -450,42 +484,60 @@ isEmpty(PREFIX):PREFIX = /usr/local
|
|||
target.path = $$PREFIX/bin/
|
||||
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/*
|
||||
INSTALLS += examples
|
||||
|
||||
libraries.path = $$PREFIX/share/openscad/libraries/
|
||||
libraries.path = "$$PREFIX/share/$${FULLNAME}/libraries/"
|
||||
libraries.files = libraries/*
|
||||
INSTALLS += libraries
|
||||
|
||||
fonts.path = $$PREFIX/share/openscad/fonts/
|
||||
fonts.path = "$$PREFIX/share/$${FULLNAME}/fonts/"
|
||||
fonts.files = fonts/*
|
||||
INSTALLS += fonts
|
||||
|
||||
colorschemes.path = $$PREFIX/share/openscad/color-schemes/
|
||||
colorschemes.path = "$$PREFIX/share/$${FULLNAME}/color-schemes/"
|
||||
colorschemes.files = color-schemes/*
|
||||
INSTALLS += colorschemes
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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]
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4) {
|
||||
win32|macx:LIBS += -lqscintilla2
|
||||
else:LIBS += -lqt5scintilla2
|
||||
CONFIG(debug, debug|release) {
|
||||
mac: {
|
||||
#LIBS += -lqscintilla2_debug
|
||||
LIBS += -lqscintilla2
|
||||
} else {
|
||||
win32: {
|
||||
LIBS += -lqscintilla2d
|
||||
} else {
|
||||
greaterThan(QT_MAJOR_VERSION, 4) {
|
||||
LIBS += -lqt5scintilla2
|
||||
} else {
|
||||
LIBS += -lqscintilla2
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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 libraries
|
||||
File /r /x mingw-cross-env fonts
|
||||
File /r /x mingw-cross-env locale
|
||||
File /r /x mingw-cross-env color-schemes
|
||||
${registerExtension} "$INSTDIR\openscad.exe" ".scad" "OpenSCAD_File"
|
||||
CreateShortCut $SMPROGRAMS\OpenSCAD.lnk $INSTDIR\openscad.exe
|
||||
|
@ -31,6 +32,7 @@ RMDir /r $INSTDIR\fonts
|
|||
RMDir /r $INSTDIR\color-schemes
|
||||
RMDir /r $INSTDIR\examples
|
||||
RMDir /r $INSTDIR\libraries\mcad
|
||||
RMDir /r $INSTDIR\locale
|
||||
Delete $INSTDIR\libraries\boxes.scad
|
||||
Delete $INSTDIR\libraries\shapes.scad
|
||||
RMDir $INSTDIR\libraries
|
||||
|
|
|
@ -325,10 +325,10 @@ build_boost()
|
|||
fi
|
||||
if $USING_LLVM; then
|
||||
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
|
||||
BOOST_TOOLSET="toolset=clang"
|
||||
echo "using clang ;" >> tools/build/v2/user-config.jam
|
||||
echo "using clang ;" >> tools/build/user-config.jam
|
||||
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
|
||||
install_name_tool -id $DEPLOYDIR/lib/libboost_thread.dylib $DEPLOYDIR/lib/libboost_thread.dylib
|
||||
|
@ -356,8 +356,9 @@ build_cgal()
|
|||
cd $BASEDIR/src
|
||||
rm -rf CGAL-$version
|
||||
if [ ! -f CGAL-$version.tar.gz ]; then
|
||||
# 4.5
|
||||
curl -O https://gforge.inria.fr/frs/download.php/file/34149/CGAL-$version.tar.gz
|
||||
# 4.5.1
|
||||
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.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
|
||||
|
@ -450,6 +451,8 @@ build_eigen()
|
|||
elif [ $version = "3.1.4" ]; then EIGENDIR=eigen-eigen-36bf2ceaf8f5;
|
||||
elif [ $version = "3.2.0" ]; then EIGENDIR=eigen-eigen-ffa86ffb5570;
|
||||
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
|
||||
|
||||
if [ $EIGENDIR = "none" ]; then
|
||||
|
@ -515,7 +518,7 @@ build_freetype()
|
|||
cd "$BASEDIR"/src
|
||||
rm -rf "freetype-$version"
|
||||
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
|
||||
tar xzf "freetype-$version.tar.gz"
|
||||
cd "freetype-$version"
|
||||
|
@ -541,7 +544,7 @@ build_libxml2()
|
|||
fi
|
||||
tar xzf "libxml2-$version.tar.gz"
|
||||
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 install
|
||||
}
|
||||
|
@ -655,7 +658,7 @@ build_ragel()
|
|||
cd "$BASEDIR"/src
|
||||
rm -rf "ragel-$version"
|
||||
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
|
||||
tar xzf "ragel-$version.tar.gz"
|
||||
cd "ragel-$version"
|
||||
|
@ -686,7 +689,7 @@ build_harfbuzz()
|
|||
# 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/^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 install
|
||||
}
|
||||
|
@ -770,26 +773,26 @@ fi
|
|||
|
||||
echo "Using basedir:" $BASEDIR
|
||||
mkdir -p $SRCDIR $DEPLOYDIR
|
||||
build_qt5 5.3.1
|
||||
build_qt5 5.4.0
|
||||
build_qscintilla 2.8.4
|
||||
# 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_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
|
||||
build_cgal 4.5
|
||||
build_glew 1.10.0
|
||||
build_gettext 0.18.3.2
|
||||
build_libffi 3.1
|
||||
build_glib2 2.40.0
|
||||
build_cgal 4.5.1
|
||||
build_glew 1.11.0
|
||||
build_gettext 0.19.4
|
||||
build_libffi 3.2.1
|
||||
build_glib2 2.42.1
|
||||
build_opencsg 1.4.0
|
||||
build_freetype 2.5.3 --without-png
|
||||
build_freetype 2.5.4 --without-png
|
||||
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_LIBS="-L$DEPLOYDIR/lib -lfreetype"
|
||||
build_libxml2 2.9.1
|
||||
build_libxml2 2.9.2
|
||||
build_fontconfig 2.11.1
|
||||
if $OPTION_DEPLOY; then
|
||||
# build_sparkle andymatuschak 0ed83cf9f2eeb425d4fdd141c01a29d843970c20
|
||||
|
|
|
@ -254,8 +254,8 @@ case $OS in
|
|||
echo "cant find $TARGET/openscad.exe. build failed. stopping."
|
||||
exit
|
||||
fi
|
||||
# make console pipe-able openscad.com - see winconsole.pri for info
|
||||
qmake CONFIG+=winconsole ../openscad.pro
|
||||
# make console pipe-able openscad.com - see winconsole.pro for info
|
||||
qmake ../winconsole.pro
|
||||
make
|
||||
if [ ! -e $TARGET/openscad.com ]; then
|
||||
echo "cant find $TARGET/openscad.com. build failed. stopping."
|
||||
|
@ -280,7 +280,6 @@ if [[ $? != 0 ]]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
echo "Building test suite..."
|
||||
|
||||
if [ $BUILD_TESTS ]; then
|
||||
|
@ -326,6 +325,7 @@ case $OS in
|
|||
EXAMPLESDIR=OpenSCAD.app/Contents/Resources/examples
|
||||
LIBRARYDIR=OpenSCAD.app/Contents/Resources/libraries
|
||||
FONTDIR=OpenSCAD.app/Contents/Resources/fonts
|
||||
TRANSLATIONDIR=OpenSCAD.app/Contents/Resources/locale
|
||||
COLORSCHEMESDIR=OpenSCAD.app/Contents/Resources/color-schemes
|
||||
;;
|
||||
UNIX_CROSS_WIN)
|
||||
|
@ -333,6 +333,7 @@ case $OS in
|
|||
EXAMPLESDIR=$DEPLOYDIR/openscad-$VERSION/examples/
|
||||
LIBRARYDIR=$DEPLOYDIR/openscad-$VERSION/libraries/
|
||||
FONTDIR=$DEPLOYDIR/openscad-$VERSION/fonts/
|
||||
TRANSLATIONDIR=$DEPLOYDIR/openscad-$VERSION/locale/
|
||||
COLORSCHEMESDIR=$DEPLOYDIR/openscad-$VERSION/color-schemes/
|
||||
rm -rf $DEPLOYDIR/openscad-$VERSION
|
||||
mkdir $DEPLOYDIR/openscad-$VERSION
|
||||
|
@ -341,6 +342,7 @@ case $OS in
|
|||
EXAMPLESDIR=openscad-$VERSION/examples/
|
||||
LIBRARYDIR=openscad-$VERSION/libraries/
|
||||
FONTDIR=openscad-$VERSION/fonts/
|
||||
TRANSLATIONDIR=openscad-$VERSION/locale/
|
||||
COLORSCHEMESDIR=openscad-$VERSION/color-schemes/
|
||||
rm -rf openscad-$VERSION
|
||||
mkdir openscad-$VERSION
|
||||
|
@ -386,6 +388,13 @@ if [ -n $LIBRARYDIR ]; then
|
|||
rm -f libraries.tar
|
||||
chmod -R u=rwx,go=r,+X $LIBRARYDIR/*
|
||||
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.."
|
||||
|
||||
|
|
|
@ -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
|
||||
# Exclude tests known the cause issues on Travis
|
||||
# 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
|
||||
echo "Test failure"
|
||||
exit 1
|
||||
|
|
|
@ -1,22 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "openscad.h"
|
||||
#include "qtgettext.h"
|
||||
#include "ui_AboutDialog.h"
|
||||
|
||||
#define STRINGIFY(x) #x
|
||||
#define TOSTRING(x) STRINGIFY(x)
|
||||
|
||||
class AboutDialog : public QDialog, public Ui::AboutDialog
|
||||
{
|
||||
Q_OBJECT;
|
||||
public:
|
||||
AboutDialog(QWidget *) {
|
||||
setupUi(this);
|
||||
this->setWindowTitle( QString("About OpenSCAD ") + QString(TOSTRING( OPENSCAD_VERSION)) );
|
||||
this->aboutText->setOpenExternalLinks(true);
|
||||
this->setWindowTitle( QString(_("About OpenSCAD")) + " " + openscad_versionnumber.c_str());
|
||||
QUrl flattr_qurl(":icons/flattr.png" );
|
||||
this->aboutText->loadResource( QTextDocument::ImageResource, flattr_qurl );
|
||||
QString tmp = this->aboutText->toHtml();
|
||||
tmp.replace("__VERSION__",QString(TOSTRING(OPENSCAD_VERSION)));
|
||||
tmp.replace("__VERSION__", openscad_versionnumber.c_str());
|
||||
this->aboutText->setHtml(tmp);
|
||||
}
|
||||
|
||||
public slots:
|
||||
void on_okPushButton_clicked() { accept(); }
|
||||
};
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
</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>
|
||||
|
@ -149,9 +149,9 @@ benhowes, 5263, Craig Trader, Miro Hrončok, Tony Theodore ... and many others
|
|||
</p>
|
||||
|
||||
<lu>
|
||||
<li><a href="http://www.github.com">Github</a>
|
||||
<li><a href="http://rocklinux.net/pipermail/openscad/">Rock Linux</a>
|
||||
<li><a href="http://www.thingiverse.com">Thingiverse</a>
|
||||
<li><a href="http://www.github.com">Source code repos and website hosted on Github</a>
|
||||
<li><a href="http://jesusabdullah.net">Downloads hosted by Joshua Holbrook</a>
|
||||
<li><a href="https://travis-ci.org/">CI hosted on Travis-CI</a>
|
||||
</lu>
|
||||
|
||||
<p>
|
||||
|
|
|
@ -6,16 +6,98 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>567</width>
|
||||
<height>359</height>
|
||||
<width>628</width>
|
||||
<height>419</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>About OpenSCAD</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<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">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>400</width>
|
||||
<height>200</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
|
@ -24,8 +106,31 @@
|
|||
<string>qrc:/src/AboutDialog.html</string>
|
||||
</url>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</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>
|
||||
</widget>
|
||||
<resources>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#include <Carbon/Carbon.h>
|
||||
#include <AppleEvents.h>
|
||||
#include <MacTypes.h>
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#include <QApplication>
|
||||
#include "MainWindow.h"
|
||||
|
||||
|
|
|
@ -48,6 +48,11 @@ size_t CGAL_Nef_polyhedron::memsize() const
|
|||
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
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ public:
|
|||
virtual std::string dump() const;
|
||||
virtual unsigned int getDimension() const { return 3; }
|
||||
// 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); }
|
||||
|
||||
void reset() { p3.reset(); }
|
||||
|
|
|
@ -46,7 +46,7 @@ void CGAL_Nef_polyhedron::transform( const Transform3d &matrix )
|
|||
{
|
||||
if (!this->isEmpty()) {
|
||||
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();
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -95,7 +95,13 @@ static shared_ptr<CSGTerm> evaluate_csg_term_from_geometry(const State &state,
|
|||
{
|
||||
std::stringstream stream;
|
||||
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()) {
|
||||
t->flag = CSGTerm::FLAG_HIGHLIGHT;
|
||||
highlights.push_back(t);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "printutils.h"
|
||||
|
||||
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()");
|
||||
if (this->type == Camera::GIMBAL) {
|
||||
|
@ -101,25 +101,34 @@ void Camera::viewAll(const BoundingBox &bbox, float scalefactor)
|
|||
|
||||
void Camera::zoom(int delta)
|
||||
{
|
||||
if (this->projection == PERSPECTIVE) {
|
||||
this->viewer_distance *= pow(0.9, delta / 120.0);
|
||||
}
|
||||
else {
|
||||
this->height *= pow(0.9, delta / 120.0);
|
||||
}
|
||||
this->viewer_distance *= pow(0.9, delta / 120.0);
|
||||
this->height = this->viewer_distance;
|
||||
}
|
||||
|
||||
void Camera::setProjection(ProjectionType type)
|
||||
{
|
||||
if (this->projection != type) {
|
||||
switch (type) {
|
||||
case PERSPECTIVE:
|
||||
this->viewer_distance = this->height;
|
||||
break;
|
||||
case ORTHOGONAL:
|
||||
this->height = this->viewer_distance;
|
||||
break;
|
||||
}
|
||||
this->projection = type;
|
||||
}
|
||||
this->projection = type;
|
||||
}
|
||||
|
||||
void Camera::resetView()
|
||||
{
|
||||
type = Camera::GIMBAL;
|
||||
object_rot << 35, 0, -25;
|
||||
object_trans << 0, 0, 0;
|
||||
height = 140;
|
||||
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 setProjection(ProjectionType type);
|
||||
void zoom(int delta);
|
||||
double zoomValue();
|
||||
void resetView();
|
||||
void viewAll(const BoundingBox &bbox, float scalefactor = 1.0f);
|
||||
std::string statusText();
|
||||
|
||||
// Vectorcam
|
||||
Eigen::Vector3d eye;
|
||||
|
@ -40,14 +43,10 @@ public:
|
|||
// Gimbalcam
|
||||
Eigen::Vector3d object_trans;
|
||||
Eigen::Vector3d object_rot;
|
||||
double viewer_distance;
|
||||
|
||||
// Perspective settings
|
||||
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
|
||||
// bounding box.
|
||||
bool viewall;
|
||||
|
@ -58,4 +57,10 @@ public:
|
|||
|
||||
unsigned int pixel_width;
|
||||
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
|
||||
{
|
||||
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;
|
||||
}
|
||||
OffscreenView *glview;
|
||||
|
@ -43,12 +38,6 @@ public:
|
|||
CSGTermEvaluator evaluator(tree, &geomevaluator);
|
||||
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)...");
|
||||
call_progress_function();
|
||||
CSGTermNormalizer normalizer( normalizelimit );
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <boost/filesystem.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include "boosty.h"
|
||||
#include "FontCache.h"
|
||||
#include "PlatformUtils.h"
|
||||
#include "parsersettings.h"
|
||||
|
@ -80,8 +81,20 @@ const std::string &FontInfo::get_file() const
|
|||
}
|
||||
|
||||
FontCache * FontCache::self = NULL;
|
||||
FontCache::InitHandlerFunc *FontCache::cb_handler = FontCache::defaultInitHandler;
|
||||
void *FontCache::cb_userdata = NULL;
|
||||
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()
|
||||
{
|
||||
this->init_ok = false;
|
||||
|
@ -89,7 +102,7 @@ FontCache::FontCache()
|
|||
// If we've got a bundled fonts.conf, initialize fontconfig with our own config
|
||||
// by overriding the built-in fontconfig path.
|
||||
// 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")) {
|
||||
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
|
||||
this->config = FcInitLoadConfig();
|
||||
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;
|
||||
}
|
||||
|
||||
// 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)) {
|
||||
FcConfigParseAndLoad(this->config, reinterpret_cast<const FcChar8 *>(boosty::stringy(builtinfontpath).c_str()), false);
|
||||
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
|
||||
FcConfigBuildFonts(this->config);
|
||||
FontCacheInitializer initializer(this->config);
|
||||
cb_handler(&initializer, cb_userdata);
|
||||
|
||||
// For use by LibraryInfo
|
||||
FcStrList *dirs = FcConfigGetFontDirs(this->config);
|
||||
|
@ -142,7 +155,7 @@ FontCache::FontCache()
|
|||
|
||||
const FT_Error error = FT_Init_FreeType(&this->library);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -161,6 +174,12 @@ FontCache * FontCache::instance()
|
|||
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)
|
||||
{
|
||||
if (!FcConfigAppFontAddFile(this->config, reinterpret_cast<const FcChar8 *> (path.c_str()))) {
|
||||
|
|
|
@ -59,6 +59,19 @@ private:
|
|||
|
||||
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 {
|
||||
public:
|
||||
const static std::string DEFAULT_FONT;
|
||||
|
@ -75,12 +88,20 @@ public:
|
|||
FontInfoList *list_fonts() const;
|
||||
|
||||
static FontCache *instance();
|
||||
|
||||
typedef void (InitHandlerFunc)(FontCacheInitializer *initializer, void *userdata);
|
||||
static void registerProgressHandler(InitHandlerFunc *handler, void *userdata = NULL);
|
||||
|
||||
private:
|
||||
typedef std::pair<FT_Face, time_t> cache_entry_t;
|
||||
typedef std::map<std::string, cache_entry_t> cache_t;
|
||||
|
||||
static FontCache *self;
|
||||
|
||||
static InitHandlerFunc *cb_handler;
|
||||
static void *cb_userdata;
|
||||
|
||||
static void defaultInitHandler(FontCacheInitializer *delegate, void *userdata);
|
||||
|
||||
bool init_ok;
|
||||
cache_t cache;
|
||||
FcConfig *config;
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <QClipboard>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include "qtgettext.h"
|
||||
#include "FontListDialog.h"
|
||||
#include "FontCache.h"
|
||||
|
||||
|
@ -59,14 +60,16 @@ void FontListDialog::selection_changed(const QItemSelection ¤t, const QIte
|
|||
{
|
||||
if (current.count() == 0) {
|
||||
copyButton->setEnabled(false);
|
||||
tableView->setDragText("");
|
||||
return;
|
||||
}
|
||||
|
||||
const QModelIndex &idx = proxy->mapToSource(current.indexes().at(0));
|
||||
const QString name = model->item(idx.row(), 0)->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);
|
||||
tableView->setDragText(selection);
|
||||
}
|
||||
|
||||
void FontListDialog::update_font_list()
|
||||
|
@ -116,3 +119,28 @@ void FontListDialog::update_font_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 <QSortFilterProxyModel>
|
||||
|
||||
#include "qtgettext.h"
|
||||
#include "ui_FontListDialog.h"
|
||||
|
||||
#define STRINGIFY(x) #x
|
||||
#define TOSTRING(x) STRINGIFY(x)
|
||||
|
||||
class FontListDialog : public QDialog, public Ui::FontListDialog
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
@ -26,6 +24,8 @@ signals:
|
|||
void font_selected(const QString font);
|
||||
|
||||
private:
|
||||
QString quote(const QString& text);
|
||||
|
||||
QString selection;
|
||||
QStandardItemModel *model;
|
||||
QSortFilterProxyModel *proxy;
|
||||
|
|
|
@ -35,9 +35,6 @@
|
|||
</item>
|
||||
<item row="4" column="3">
|
||||
<widget class="QPushButton" name="copyButton">
|
||||
<property name="toolTip">
|
||||
<string>Paste font selector to Editor Window</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Copy to Clipboard</string>
|
||||
</property>
|
||||
|
@ -70,7 +67,17 @@
|
|||
</widget>
|
||||
</item>
|
||||
<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 row="0" column="0" colspan="5">
|
||||
<widget class="QLabel" name="label">
|
||||
|
@ -103,6 +110,13 @@
|
|||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>FontListTableView</class>
|
||||
<extends>QTableView</extends>
|
||||
<header>FontListTableView.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../openscad.qrc"/>
|
||||
</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();
|
||||
|
||||
switch (this->cam.type) {
|
||||
case Camera::GIMBAL:
|
||||
case Camera::GIMBAL: {
|
||||
double eyeY = 0.0;
|
||||
switch (this->cam.projection) {
|
||||
case Camera::PERSPECTIVE: {
|
||||
double dist = cam.viewer_distance;
|
||||
gluPerspective(cam.fov, aspectratio, 0.1*dist, 100*dist);
|
||||
eyeY = cam.zoomValue();
|
||||
gluPerspective(cam.fov, aspectratio, 0.1 * eyeY, 100 * eyeY);
|
||||
break;
|
||||
}
|
||||
case Camera::ORTHOGONAL: {
|
||||
glOrtho(-cam.height/2*aspectratio, cam.height*aspectratio/2,
|
||||
-cam.height/2, cam.height/2,
|
||||
eyeY = cam.zoomValue();
|
||||
glOrtho(-eyeY/2*aspectratio, eyeY*aspectratio/2,
|
||||
-eyeY/2, eyeY/2,
|
||||
-far_far_away, +far_far_away);
|
||||
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, 1.0);
|
||||
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.y(), 0.0, 1.0, 0.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;
|
||||
}
|
||||
case Camera::VECTOR: {
|
||||
switch (this->cam.projection) {
|
||||
case Camera::PERSPECTIVE: {
|
||||
|
@ -123,8 +125,9 @@ void GLView::setupCamera()
|
|||
break;
|
||||
}
|
||||
case Camera::ORTHOGONAL: {
|
||||
glOrtho(-cam.height/2*aspectratio, cam.height*aspectratio/2,
|
||||
-cam.height/2, cam.height/2,
|
||||
double height = cam.zoomValue();
|
||||
glOrtho(-height/2*aspectratio, height*aspectratio/2,
|
||||
-height/2, height/2,
|
||||
-far_far_away, +far_far_away);
|
||||
break;
|
||||
}
|
||||
|
@ -150,18 +153,24 @@ void GLView::setupCamera()
|
|||
|
||||
void GLView::paintGL()
|
||||
{
|
||||
glEnable(GL_LIGHTING);
|
||||
|
||||
setupCamera();
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
Color4f bgcol = ColorMap::getColor(*this->colorscheme, BACKGROUND_COLOR);
|
||||
Color4f bgcontrast = ColorMap::getContrastColor(bgcol);
|
||||
glClearColor(bgcol[0], bgcol[1], bgcol[2], 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
// Only for GIMBAL cam
|
||||
if (showcrosshairs) GLView::showCrosshairs();
|
||||
if (showaxes) GLView::showAxes();
|
||||
setupCamera();
|
||||
if (this->cam.type) {
|
||||
// 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);
|
||||
glCullFace(GL_BACK);
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
@ -174,10 +183,11 @@ void GLView::paintGL()
|
|||
OpenCSG::setContext(this->opencsg_id);
|
||||
#endif
|
||||
this->renderer->draw(showfaces, showedges);
|
||||
}
|
||||
}
|
||||
|
||||
// Only for GIMBAL
|
||||
if (showaxes) GLView::showSmallaxes();
|
||||
glDisable(GL_LIGHTING);
|
||||
if (showaxes) GLView::showSmallaxes(bgcontrast);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_OPENCSG
|
||||
|
@ -358,7 +368,7 @@ void GLView::initializeGL()
|
|||
#endif
|
||||
}
|
||||
|
||||
void GLView::showSmallaxes()
|
||||
void GLView::showSmallaxes(const Color4f &col)
|
||||
{
|
||||
// Fixme - this doesnt work in Vector Camera mode
|
||||
|
||||
|
@ -423,14 +433,9 @@ void GLView::showSmallaxes()
|
|||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
// FIXME: This was an attempt to keep contrast with background, but is suboptimal
|
||||
// (e.g. nearly invisible against a gray background).
|
||||
// int r,g,b;
|
||||
// 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);
|
||||
glColor3f(col[0], col[1], col[2]);
|
||||
|
||||
float d = 3*dpi;
|
||||
glBegin(GL_LINES);
|
||||
// X Label
|
||||
glVertex3d(xlabel_x-d, xlabel_y-d, 0); glVertex3d(xlabel_x+d, xlabel_y+d, 0);
|
||||
|
@ -447,36 +452,48 @@ void GLView::showSmallaxes()
|
|||
glEnd();
|
||||
}
|
||||
|
||||
void GLView::showAxes()
|
||||
void GLView::showAxes(const Color4f &col)
|
||||
{
|
||||
double l = cam.zoomValue();
|
||||
|
||||
// FIXME: doesn't work under Vector Camera
|
||||
// Large gray axis cross inline with the model
|
||||
// FIXME: This is always gray - adjust color to keep contrast with background
|
||||
glLineWidth(this->getDPI());
|
||||
glColor3d(0.5, 0.5, 0.5);
|
||||
glColor3f(col[0], col[1], col[2]);
|
||||
|
||||
glBegin(GL_LINES);
|
||||
double l = cam.projection == Camera::PERSPECTIVE ? cam.viewer_distance : cam.height;
|
||||
glVertex3d(-l, 0, 0);
|
||||
glVertex3d(0, 0, 0);
|
||||
glVertex3d(+l, 0, 0);
|
||||
glVertex3d(0, -l, 0);
|
||||
glVertex3d(0, 0, 0);
|
||||
glVertex3d(0, +l, 0);
|
||||
glVertex3d(0, 0, -l);
|
||||
glVertex3d(0, 0, 0);
|
||||
glVertex3d(0, 0, +l);
|
||||
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()
|
||||
{
|
||||
// FIXME: this might not work with Vector camera
|
||||
// FIXME: Crosshairs and axes are lighted, this doesn't make sense and causes them
|
||||
// to change color based on view orientation.
|
||||
glLineWidth(3);
|
||||
glLineWidth(this->getDPI());
|
||||
Color4f col = ColorMap::getColor(*this->colorscheme, CROSSHAIR_COLOR);
|
||||
glColor3f(col[0], col[1], col[2]);
|
||||
glBegin(GL_LINES);
|
||||
for (double xf = -1; xf <= +1; xf += 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);
|
||||
}
|
||||
|
|
|
@ -42,10 +42,6 @@ public:
|
|||
void setCamera(const Camera &cam);
|
||||
void setupCamera();
|
||||
|
||||
void showCrosshairs();
|
||||
void showAxes();
|
||||
void showSmallaxes();
|
||||
|
||||
void setColorScheme(const ColorScheme &cs);
|
||||
void setColorScheme(const std::string &cs);
|
||||
void updateColorScheme();
|
||||
|
@ -76,4 +72,8 @@ public:
|
|||
bool opencsg_support;
|
||||
int opencsg_id;
|
||||
#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);
|
||||
ps->setConvexity(N->getConvexity());
|
||||
this->root.reset(ps);
|
||||
bool err = CGALUtils::createPolySetFromNefPolyhedron3(*N->p3, *ps);
|
||||
if (err) {
|
||||
PRINT("ERROR: Nef->PolySet failed");
|
||||
}
|
||||
if (!N->isEmpty()) {
|
||||
bool err = CGALUtils::createPolySetFromNefPolyhedron3(*N->p3, *ps);
|
||||
if (err) {
|
||||
PRINT("ERROR: Nef->PolySet failed");
|
||||
}
|
||||
}
|
||||
|
||||
smartCacheInsert(node, this->root);
|
||||
}
|
||||
|
@ -88,8 +90,12 @@ GeometryEvaluator::ResultObject GeometryEvaluator::applyToChildren(const Abstrac
|
|||
}
|
||||
}
|
||||
}
|
||||
if (dim == 2) return ResultObject(applyToChildren2D(node, op));
|
||||
else if (dim == 3) return applyToChildren3D(node, op);
|
||||
if (dim == 2) {
|
||||
Polygon2d *p2d = applyToChildren2D(node, op);
|
||||
assert(p2d);
|
||||
return ResultObject(p2d);
|
||||
}
|
||||
else if (dim == 3) return applyToChildren3D(node, op);
|
||||
return ResultObject();
|
||||
}
|
||||
|
||||
|
@ -119,16 +125,23 @@ GeometryEvaluator::ResultObject GeometryEvaluator::applyToChildren3D(const Abstr
|
|||
|
||||
if (op == OPENSCAD_MINKOWSKI) return ResultObject(CGALUtils::applyMinkowski(children));
|
||||
|
||||
CGAL_Nef_polyhedron *N = new CGAL_Nef_polyhedron;
|
||||
CGALUtils::applyOperator(children, *N, op);
|
||||
CGAL_Nef_polyhedron *N = CGALUtils::applyOperator(children, op);
|
||||
// FIXME: Clarify when we can return NULL and what that means
|
||||
if (!N) N = new CGAL_Nef_polyhedron;
|
||||
return ResultObject(N);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
Apply 2D hull.
|
||||
|
||||
May return an empty geometry but will not return NULL.
|
||||
*/
|
||||
Polygon2d *GeometryEvaluator::applyHull2D(const AbstractNode &node)
|
||||
{
|
||||
std::vector<const Polygon2d *> children = collectChildren2D(node);
|
||||
Polygon2d *geometry = NULL;
|
||||
Polygon2d *geometry = new Polygon2d();
|
||||
|
||||
typedef CGAL::Point_2<CGAL::Cartesian<double> > CGALPoint2;
|
||||
// Collect point cloud
|
||||
|
@ -150,7 +163,6 @@ Polygon2d *GeometryEvaluator::applyHull2D(const AbstractNode &node)
|
|||
BOOST_FOREACH(const CGALPoint2 &p, result) {
|
||||
outline.vertices.push_back(Vector2d(p[0], p[1]));
|
||||
}
|
||||
geometry = new Polygon2d();
|
||||
geometry->addOutline(outline);
|
||||
}
|
||||
return geometry;
|
||||
|
@ -271,12 +283,12 @@ Geometry::ChildList GeometryEvaluator::collectChildren3D(const AbstractNode &nod
|
|||
smartCacheInsert(*chnode, chgeom);
|
||||
|
||||
if (chgeom) {
|
||||
if (chgeom->isEmpty() || chgeom->getDimension() == 3) {
|
||||
children.push_back(item);
|
||||
}
|
||||
else {
|
||||
if (chgeom->getDimension() == 2) {
|
||||
PRINT("WARNING: Ignoring 2D child object for 3D operation");
|
||||
}
|
||||
else if (chgeom->isEmpty() || chgeom->getDimension() == 3) {
|
||||
children.push_back(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
return children;
|
||||
|
@ -345,6 +357,7 @@ void GeometryEvaluator::addToParent(const State &state,
|
|||
// Root node, insert into cache
|
||||
smartCacheInsert(node, 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);
|
||||
// ClipperLib documentation: The formula for the number of steps in a full
|
||||
// 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));
|
||||
const Polygon2d *result = ClipperUtils::applyOffset(*polygon, node.delta, node.join_type, node.miter_limit, arc_tolerance);
|
||||
assert(result);
|
||||
|
@ -443,6 +456,7 @@ Response GeometryEvaluator::visit(State &state, const LeafNode &node)
|
|||
shared_ptr<const Geometry> geom;
|
||||
if (!isSmartCached(node)) {
|
||||
const Geometry *geometry = node.createGeometry();
|
||||
assert(geometry);
|
||||
if (const Polygon2d *polygon = dynamic_cast<const Polygon2d*>(geometry)) {
|
||||
if (!polygon->isSanitized()) {
|
||||
Polygon2d *p = ClipperUtils::sanitize(*polygon);
|
||||
|
@ -516,7 +530,7 @@ Response GeometryEvaluator::visit(State &state, const TransformNode &node)
|
|||
if (!isSmartCached(node)) {
|
||||
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
|
||||
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 {
|
||||
// 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(3,0), node.matrix(3,1), node.matrix(3,3);
|
||||
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) {
|
||||
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)
|
||||
{
|
||||
BOOST_FOREACH(PolySet::Polygon &p, ps.polygons) {
|
||||
BOOST_FOREACH(Polygon &p, ps.polygons) {
|
||||
BOOST_FOREACH(Vector3d &v, p) {
|
||||
v += translation;
|
||||
}
|
||||
|
@ -651,7 +670,7 @@ static Geometry *extrudePolygon(const LinearExtrudeNode &node, const Polygon2d &
|
|||
PolySet *ps_bottom = poly.tessellate(); // bottom
|
||||
|
||||
// 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());
|
||||
}
|
||||
translate_PolySet(*ps_bottom, Vector3d(0,0,h1));
|
||||
|
@ -934,9 +953,10 @@ Response GeometryEvaluator::visit(State &state, const ProjectionNode &node)
|
|||
}
|
||||
if (!Nptr->isEmpty()) {
|
||||
Polygon2d *poly = CGALUtils::project(*Nptr, node.cut_mode);
|
||||
assert(poly);
|
||||
poly->setConvexity(node.convexity);
|
||||
geom.reset(poly);
|
||||
if (poly) {
|
||||
poly->setConvexity(node.convexity);
|
||||
geom.reset(poly);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,12 +29,20 @@ std::string LibraryInfo::info()
|
|||
{
|
||||
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__)
|
||||
std::string compiler_info( "GCC " + std::string(TOSTRING(__VERSION__)) );
|
||||
std::string compiler_info( "GCC " + std::string(TOSTRING(__VERSION__)) + bits);
|
||||
#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__)
|
||||
std::string compiler_info( "Clang " + std::string(TOSTRING(__clang_version__)) );
|
||||
std::string compiler_info( "Clang " + std::string(TOSTRING(__clang_version__)) + bits);
|
||||
#else
|
||||
std::string compiler_info( "unknown compiler" );
|
||||
#endif
|
||||
|
@ -80,6 +88,7 @@ std::string LibraryInfo::info()
|
|||
const char *env_font_path = getenv("OPENSCAD_FONT_PATH");
|
||||
|
||||
s << "OpenSCAD Version: " << TOSTRING(OPENSCAD_VERSION)
|
||||
<< "\nSystem information: " << PlatformUtils::sysinfo()
|
||||
<< "\nCompiler, build date: " << compiler_info << ", " << __DATE__
|
||||
<< "\nBoost version: " << BOOST_LIB_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
|
||||
<< "\nApplication Path: " << PlatformUtils::applicationPath()
|
||||
<< "\nDocuments Path: " << PlatformUtils::documentsPath()
|
||||
<< "\nResource Path: " << PlatformUtils::resourcesPath()
|
||||
<< "\nResource Path: " << PlatformUtils::resourceBasePath()
|
||||
<< "\nUser Library Path: " << PlatformUtils::userLibraryPath()
|
||||
<< "\nUser Config Path: " << PlatformUtils::userConfigPath()
|
||||
<< "\nBackup Path: " << PlatformUtils::backupPath()
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#include <QDialog>
|
||||
#include <QString>
|
||||
|
||||
#include "qtgettext.h"
|
||||
#include "ui_LibraryInfoDialog.h"
|
||||
|
||||
class LibraryInfoDialog : public QDialog, public Ui::LibraryInfoDialog
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "qtgettext.h"
|
||||
#include <QMainWindow>
|
||||
#include <QIcon>
|
||||
#include "ui_MainWindow.h"
|
||||
|
@ -13,6 +14,7 @@
|
|||
#include <vector>
|
||||
#include <QMutex>
|
||||
#include <QSet>
|
||||
#include <QTime>
|
||||
|
||||
enum export_type_e {
|
||||
EXPORT_TYPE_UNKNOWN,
|
||||
|
@ -39,6 +41,8 @@ public:
|
|||
std::string autoReloadId;
|
||||
QTimer *waitAfterReloadTimer;
|
||||
|
||||
QTime renderingTime;
|
||||
|
||||
ModuleContext top_ctx;
|
||||
FileModule *root_module; // Result of parsing
|
||||
ModuleInstantiation root_inst; // Top level instance
|
||||
|
@ -67,6 +71,7 @@ public:
|
|||
QAction *actionRecentFile[UIUtils::maxRecentFiles];
|
||||
QMap<QString, QString> knownFileExtensions;
|
||||
|
||||
QLabel *versionLabel;
|
||||
QWidget *editorDockTitleWidget;
|
||||
QWidget *consoleDockTitleWidget;
|
||||
|
||||
|
@ -112,6 +117,7 @@ private:
|
|||
void show_examples();
|
||||
void setDockWidgetTitle(QDockWidget *dockWidget, QString prefix, bool topLevel);
|
||||
void addKeyboardShortCut(const QList<QAction *> &actions);
|
||||
void updateStatusBar(class ProgressWidget *progressWidget);
|
||||
|
||||
EditorInterface *editor;
|
||||
|
||||
|
|
|
@ -179,7 +179,7 @@
|
|||
</property>
|
||||
<widget class="QMenu" name="menuOpenRecent">
|
||||
<property name="title">
|
||||
<string>Open Recent</string>
|
||||
<string>Recent Files</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuExamples">
|
||||
|
@ -543,6 +543,9 @@
|
|||
<property name="shortcut">
|
||||
<string>Ctrl+Q</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::QuitRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="editActionUndo">
|
||||
<property name="text">
|
||||
|
@ -955,6 +958,9 @@
|
|||
<property name="text">
|
||||
<string>About</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::AboutRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="helpActionManual">
|
||||
<property name="text">
|
||||
|
@ -983,6 +989,9 @@
|
|||
<property name="text">
|
||||
<string>Preferences</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::PreferencesRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="editActionFind">
|
||||
<property name="text">
|
||||
|
|
|
@ -4,17 +4,13 @@ GLView::GLView() {}
|
|||
void GLView::setRenderer(Renderer* r) {}
|
||||
void GLView::initializeGL() {}
|
||||
void GLView::resizeGL(int w, int h) {}
|
||||
void GLView::setupGimbalCamPerspective() {}
|
||||
void GLView::setupGimbalCamOrtho(double distance, bool offset) {}
|
||||
void GLView::setupVectorCamPerspective() {}
|
||||
void GLView::setupVectorCamOrtho(bool offset) {}
|
||||
void GLView::setCamera( Camera &cam ) {}
|
||||
void GLView::setCamera(const Camera &cam ) {assert(false && "not implemented");}
|
||||
void GLView::paintGL() {}
|
||||
void GLView::vectorCamPaintGL() {}
|
||||
void GLView::gimbalCamPaintGL() {}
|
||||
void GLView::showSmallaxes() {}
|
||||
void GLView::showAxes() {}
|
||||
void GLView::showSmallaxes(const Color4f &col) {}
|
||||
void GLView::showAxes(const Color4f &col) {}
|
||||
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"
|
||||
|
||||
|
@ -23,12 +19,16 @@ ThrownTogetherRenderer::ThrownTogetherRenderer(CSGChain *root_chain,
|
|||
void ThrownTogetherRenderer::draw(bool /*showfaces*/, bool showedges) const {}
|
||||
void ThrownTogetherRenderer::renderCSGChain(CSGChain *chain, bool
|
||||
highlight, bool background, bool showedges, bool fberror) const {}
|
||||
BoundingBox ThrownTogetherRenderer::getBoundingBox() const {assert(false && "not implemented");}
|
||||
|
||||
#include "CGALRenderer.h"
|
||||
|
||||
CGALRenderer::CGALRenderer(shared_ptr<const class Geometry> geom) {}
|
||||
CGALRenderer::~CGALRenderer() {}
|
||||
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"
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ const bool cull_backfaces = false;
|
|||
const bool color_backfaces = false;
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h> // For the CALLBACK macro
|
||||
#define CGAL_GLU_TESS_CALLBACK CALLBACK
|
||||
#else
|
||||
#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
|
||||
*/
|
||||
|
||||
#undef NOGDI
|
||||
#include <windows.h>
|
||||
#include <vector>
|
||||
|
||||
|
|
|
@ -90,7 +90,12 @@ void OpenCSGRenderer::renderCSGChain(CSGChain *chain, GLint *shaderinfo,
|
|||
const Color4f &c = j_obj.color;
|
||||
glPushMatrix();
|
||||
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;
|
||||
if (background) {
|
||||
if (j_obj.flag & CSGTerm::FLAG_HIGHLIGHT) {
|
||||
|
@ -99,11 +104,9 @@ void OpenCSGRenderer::renderCSGChain(CSGChain *chain, GLint *shaderinfo,
|
|||
else {
|
||||
colormode = COLORMODE_BACKGROUND;
|
||||
}
|
||||
csgmode = csgmode_e(csgmode + 10);
|
||||
} else if (j_obj.type == CSGTerm::TYPE_DIFFERENCE) {
|
||||
if (j_obj.flag & CSGTerm::FLAG_HIGHLIGHT) {
|
||||
colormode = COLORMODE_HIGHLIGHT;
|
||||
csgmode = csgmode_e(csgmode + 20);
|
||||
}
|
||||
else {
|
||||
colormode = COLORMODE_CUTOUT;
|
||||
|
@ -111,7 +114,6 @@ void OpenCSGRenderer::renderCSGChain(CSGChain *chain, GLint *shaderinfo,
|
|||
} else {
|
||||
if (j_obj.flag & CSGTerm::FLAG_HIGHLIGHT) {
|
||||
colormode = COLORMODE_HIGHLIGHT;
|
||||
csgmode = csgmode_e(csgmode + 20);
|
||||
}
|
||||
else {
|
||||
colormode = COLORMODE_MATERIAL;
|
||||
|
@ -139,9 +141,12 @@ void OpenCSGRenderer::renderCSGChain(CSGChain *chain, GLint *shaderinfo,
|
|||
|
||||
prim->geom = i_obj.geom;
|
||||
prim->m = i_obj.matrix;
|
||||
prim->csgmode = i_obj.type == CSGTerm::TYPE_DIFFERENCE ? CSGMODE_DIFFERENCE : CSGMODE_NORMAL;
|
||||
if (highlight) prim->csgmode = csgmode_e(prim->csgmode + 20);
|
||||
else if (background) prim->csgmode = csgmode_e(prim->csgmode + 10);
|
||||
prim->csgmode = csgmode_e(
|
||||
(highlight ?
|
||||
CSGMODE_HIGHLIGHT :
|
||||
(background ? CSGMODE_BACKGROUND : CSGMODE_NORMAL)) |
|
||||
(i_obj.type == CSGTerm::TYPE_DIFFERENCE ? CSGMODE_DIFFERENCE : 0));
|
||||
|
||||
primitives.push_back(prim);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "qtgettext.h"
|
||||
#include "ui_OpenCSGWarningDialog.h"
|
||||
|
||||
class OpenCSGWarningDialog : public QDialog, public Ui::OpenCSGWarningDialog
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
#include "PlatformUtils.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
std::string PlatformUtils::pathSeparatorChar()
|
||||
|
@ -18,5 +22,49 @@ std::string PlatformUtils::userConfigPath()
|
|||
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) {}
|
||||
|
||||
|
|
|
@ -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 "boosty.h"
|
||||
|
||||
|
@ -41,5 +52,126 @@ std::string PlatformUtils::userConfigPath()
|
|||
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) {}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#endif
|
||||
#undef NOGDI
|
||||
#include <windows.h>
|
||||
#ifndef _WIN32_IE
|
||||
#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 );
|
||||
|
||||
if (result == S_OK) {
|
||||
path = std::wstring( path.c_str() ); // strip extra NULLs
|
||||
//std::wcerr << "wchar path:" << "\n";
|
||||
const std::string retval = winapi_wstr_to_utf8( path );
|
||||
//PRINTB("Path found: %s",retval);
|
||||
return retval;
|
||||
path = std::wstring( path.c_str() ); // strip extra NULLs
|
||||
// Use boost::filesystem to decide how to convert from wstring
|
||||
// to string. Normally the path encoding is system local and
|
||||
// we don't want to force conversion to UTF-8.
|
||||
fs::path p(path);
|
||||
return p.string();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
@ -92,6 +94,101 @@ std::string PlatformUtils::userConfigPath()
|
|||
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 <stdio.h>
|
||||
#include <fstream>
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
#include <stdlib.h>
|
||||
#include <iomanip>
|
||||
|
||||
#include "PlatformUtils.h"
|
||||
#include "boosty.h"
|
||||
#include <Eigen/Core>
|
||||
#ifdef USE_SCINTILLA_EDITOR
|
||||
#include <Qsci/qsciglobal.h>
|
||||
|
||||
#ifdef INSTALL_SUFFIX
|
||||
#define RESOURCE_FOLDER(path) path INSTALL_SUFFIX
|
||||
#else
|
||||
#define RESOURCE_FOLDER(path) path
|
||||
#endif
|
||||
|
||||
extern std::vector<std::string> librarypath;
|
||||
|
@ -23,7 +25,6 @@ static std::string lookupResourcesPath()
|
|||
fs::path resourcedir(applicationpath);
|
||||
PRINTDB("Looking up resource folder with application path '%s'", resourcedir.c_str());
|
||||
|
||||
#ifndef WIN32
|
||||
#ifdef __APPLE__
|
||||
const char *searchpath[] = {
|
||||
"../Resources", // Resources can be bundled on Mac.
|
||||
|
@ -32,15 +33,24 @@ static std::string lookupResourcesPath()
|
|||
NULL
|
||||
};
|
||||
#else
|
||||
const char *searchpath[] = {
|
||||
"../share/openscad",
|
||||
"../../share/openscad",
|
||||
#ifdef WIN32
|
||||
const char *searchpath[] = {
|
||||
".", // Release location
|
||||
RESOURCE_FOLDER("../share/openscad"), // MSYS2 location
|
||||
"..", // Dev location
|
||||
NULL
|
||||
};
|
||||
#else
|
||||
const char *searchpath[] = {
|
||||
RESOURCE_FOLDER("../share/openscad"),
|
||||
RESOURCE_FOLDER("../../share/openscad"),
|
||||
".",
|
||||
"..",
|
||||
"../..",
|
||||
NULL
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
fs::path tmpdir;
|
||||
for (int a = 0;searchpath[a] != NULL;a++) {
|
||||
|
@ -55,7 +65,6 @@ static std::string lookupResourcesPath()
|
|||
break;
|
||||
}
|
||||
}
|
||||
#endif // !WIN32
|
||||
|
||||
// resourcedir defaults to applicationPath
|
||||
std::string result = boosty::stringy(boosty::canonical(resourcedir));
|
||||
|
@ -151,7 +160,7 @@ bool PlatformUtils::createBackupPath()
|
|||
}
|
||||
|
||||
// This is the built-in read-only resources path
|
||||
std::string PlatformUtils::resourcesPath()
|
||||
std::string PlatformUtils::resourceBasePath()
|
||||
{
|
||||
if (!path_initialized) {
|
||||
throw std::runtime_error("PlatformUtils::resourcesPath(): application path not initialized!");
|
||||
|
@ -159,6 +168,21 @@ std::string PlatformUtils::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)
|
||||
{
|
||||
#if defined(WIN32)
|
||||
|
@ -174,3 +198,25 @@ int PlatformUtils::setenv(const char *name, const char *value, int overwrite)
|
|||
return ::setenv(name, value, overwrite);
|
||||
#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 "boosty.h"
|
||||
|
||||
#define STACK_BUFFER_SIZE (64 * 1024)
|
||||
#define STACK_LIMIT_DEFAULT (8 * 1024 * 1024 - STACK_BUFFER_SIZE)
|
||||
|
||||
namespace PlatformUtils {
|
||||
extern const char *OPENSCAD_FOLDER_NAME;
|
||||
|
||||
|
@ -9,7 +14,8 @@ namespace PlatformUtils {
|
|||
std::string applicationPath();
|
||||
|
||||
std::string documentsPath();
|
||||
std::string resourcesPath();
|
||||
std::string resourceBasePath();
|
||||
fs::path resourcePath(const std::string& resource);
|
||||
std::string userLibraryPath();
|
||||
|
||||
/**
|
||||
|
@ -28,6 +34,20 @@ namespace PlatformUtils {
|
|||
std::string backupPath();
|
||||
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
|
||||
* does not support setenv(), but needs _putenv().
|
||||
|
@ -38,6 +58,14 @@ namespace PlatformUtils {
|
|||
*/
|
||||
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
|
||||
* (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.
|
||||
*/
|
||||
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
|
||||
{
|
||||
PRINTDB("Polygon2d::tessellate(): %d outlines", this->outlines().size());
|
||||
PolySet *polyset = new PolySet(*this);
|
||||
|
||||
Polygon2DCGAL::CDT cdt; // Uses a constrained Delaunay triangulator.
|
||||
|
|
|
@ -11,7 +11,10 @@
|
|||
|
||||
We can store sanitized vs. unsanitized polygons. Sanitized polygons
|
||||
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
|
||||
|
@ -56,7 +59,7 @@ bool Polygon2d::isEmpty() const
|
|||
void Polygon2d::transform(const Transform2d &mat)
|
||||
{
|
||||
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();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,55 @@ Preferences *Preferences::instance = NULL;
|
|||
const char * Preferences::featurePropertyName = "FeatureProperty";
|
||||
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)
|
||||
{
|
||||
setupUi(this);
|
||||
|
@ -108,6 +157,7 @@ void Preferences::init() {
|
|||
this->defaultmap["advanced/undockableWindows"] = false;
|
||||
this->defaultmap["advanced/reorderWindows"] = true;
|
||||
this->defaultmap["launcher/showOnStartup"] = true;
|
||||
this->defaultmap["advanced/localization"] = true;
|
||||
|
||||
// Toolbar
|
||||
QActionGroup *group = new QActionGroup(this);
|
||||
|
@ -139,6 +189,22 @@ void Preferences::init() {
|
|||
#endif
|
||||
this->polysetCacheSizeEdit->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()
|
||||
|
@ -380,6 +446,12 @@ void Preferences::on_opencsgLimitEdit_textChanged(const QString &text)
|
|||
// 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)
|
||||
{
|
||||
QSettings settings;
|
||||
|
@ -393,13 +465,101 @@ void Preferences::on_mouseWheelZoomBox_toggled(bool state)
|
|||
settings.setValue("editor/ctrlmousewheelzoom", state);
|
||||
}
|
||||
|
||||
void
|
||||
Preferences::on_launcherBox_toggled(bool state)
|
||||
void Preferences::on_launcherBox_toggled(bool state)
|
||||
{
|
||||
QSettings settings;
|
||||
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)
|
||||
{
|
||||
#ifdef Q_OS_MAC
|
||||
|
@ -486,12 +646,75 @@ void Preferences::updateGUI()
|
|||
this->cgalCacheSizeEdit->setText(getValue("advanced/cgalCacheSize").toString());
|
||||
this->polysetCacheSizeEdit->setText(getValue("advanced/polysetCacheSize").toString());
|
||||
this->opencsgLimitEdit->setText(getValue("advanced/openCSGLimit").toString());
|
||||
this->localizationCheckBox->setChecked(getValue("advanced/localization").toBool());
|
||||
this->forceGoldfeatherBox->setChecked(getValue("advanced/forceGoldfeather").toBool());
|
||||
this->mdiCheckBox->setChecked(getValue("advanced/mdi").toBool());
|
||||
this->reorderCheckBox->setChecked(getValue("advanced/reorderWindows").toBool());
|
||||
this->undockCheckBox->setChecked(getValue("advanced/undockableWindows").toBool());
|
||||
this->undockCheckBox->setEnabled(this->reorderCheckBox->isChecked());
|
||||
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
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
|
||||
#include <QMainWindow>
|
||||
#include <QSettings>
|
||||
|
||||
#include "qtgettext.h"
|
||||
#include "ui_Preferences.h"
|
||||
#include "settings.h"
|
||||
|
||||
class Preferences : public QMainWindow, public Ui::Preferences
|
||||
{
|
||||
|
@ -17,6 +20,7 @@ public:
|
|||
QVariant getValue(const QString &key) const;
|
||||
void init();
|
||||
void apply() const;
|
||||
void fireEditorConfigChanged() const;
|
||||
|
||||
public slots:
|
||||
void actionTriggered(class QAction *);
|
||||
|
@ -32,6 +36,7 @@ public slots:
|
|||
void on_opencsgLimitEdit_textChanged(const QString &);
|
||||
void on_forceGoldfeatherBox_toggled(bool);
|
||||
void on_mouseWheelZoomBox_toggled(bool);
|
||||
void on_localizationCheckBox_toggled(bool);
|
||||
void on_updateCheckBox_toggled(bool);
|
||||
void on_snapshotCheckBox_toggled(bool);
|
||||
void on_mdiCheckBox_toggled(bool);
|
||||
|
@ -41,6 +46,30 @@ public slots:
|
|||
void on_launcherBox_toggled(bool);
|
||||
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:
|
||||
void requestRedraw() const;
|
||||
void updateMdiMode(bool mdi) const;
|
||||
|
@ -51,6 +80,7 @@ signals:
|
|||
void openCSGSettingsChanged() const;
|
||||
void syntaxHighlightChanged(const QString &s) const;
|
||||
void editorTypeChanged(const QString &type);
|
||||
void editorConfigChanged() const;
|
||||
|
||||
private:
|
||||
Preferences(QWidget *parent = NULL);
|
||||
|
@ -58,8 +88,18 @@ private:
|
|||
void updateGUI();
|
||||
void removeDefaultSettings();
|
||||
void setupFeaturesPage();
|
||||
void writeSettings();
|
||||
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;
|
||||
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
|
||||
|
||||
#include "qtgettext.h"
|
||||
#include "ui_ProgressWidget.h"
|
||||
#include <QTime>
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "qtgettext.h"
|
||||
#include "QGLView.h"
|
||||
#include "Preferences.h"
|
||||
#include "renderer.h"
|
||||
|
@ -63,7 +64,6 @@ static bool running_under_wine = false;
|
|||
|
||||
void QGLView::init()
|
||||
{
|
||||
cam.type = Camera::GIMBAL;
|
||||
resetView();
|
||||
|
||||
this->mouse_drag_active = false;
|
||||
|
@ -83,9 +83,7 @@ void QGLView::init()
|
|||
|
||||
void QGLView::resetView()
|
||||
{
|
||||
cam.object_rot << 35, 0, -25;
|
||||
cam.object_trans << 0, 0, 0;
|
||||
cam.viewer_distance = 140;
|
||||
cam.resetView();
|
||||
}
|
||||
|
||||
void QGLView::viewAll()
|
||||
|
@ -110,7 +108,7 @@ std::string QGLView::getRendererInfo() const
|
|||
{
|
||||
std::string glewinfo = glew_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
|
||||
|
@ -127,19 +125,19 @@ void QGLView::display_opencsg_warning_dialog()
|
|||
|
||||
QString message;
|
||||
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 {
|
||||
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();
|
||||
}
|
||||
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"
|
||||
"Your renderer information is as follows:\n";
|
||||
"Your renderer information is as follows:\n");
|
||||
QString rendererinfo;
|
||||
rendererinfo.sprintf("GLEW version %s\n"
|
||||
rendererinfo.sprintf(_("GLEW version %s\n"
|
||||
"%s (%s)\n"
|
||||
"OpenGL version %s\n",
|
||||
"OpenGL version %s\n"),
|
||||
glewGetString(GLEW_VERSION),
|
||||
glGetString(GL_RENDERER), glGetString(GL_VENDOR),
|
||||
glGetString(GL_VERSION));
|
||||
|
@ -163,16 +161,9 @@ void QGLView::paintGL()
|
|||
GLView::paintGL();
|
||||
|
||||
if (statusLabel) {
|
||||
QString msg;
|
||||
|
||||
Camera nc(cam);
|
||||
nc.gimbalDefaultTranslate();
|
||||
msg.sprintf("Viewport: translate = [ %.2f %.2f %.2f ], rotate = [ %.2f %.2f %.2f ], distance = %.2f",
|
||||
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);
|
||||
statusLabel->setText(QString::fromStdString(nc.statusText()));
|
||||
}
|
||||
|
||||
if (running_under_wine) swapBuffers();
|
||||
|
@ -251,11 +242,11 @@ void QGLView::mouseMoveEvent(QMouseEvent *event)
|
|||
// Middle button pans in the xy plane
|
||||
// Shift-right and Shift-middle zooms
|
||||
if ((QApplication::keyboardModifiers() & Qt::ShiftModifier) != 0) {
|
||||
cam.viewer_distance += (GLdouble)dy;
|
||||
cam.zoom(-12.0 * dy);
|
||||
} else {
|
||||
|
||||
double mx = +(dx) * cam.viewer_distance/1000;
|
||||
double mz = -(dy) * cam.viewer_distance/1000;
|
||||
double mx = +(dx) * 3.0 * cam.zoomValue() / QWidget::width();
|
||||
double mz = -(dy) * 3.0 * cam.zoomValue() / QWidget::height();
|
||||
|
||||
double my = 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;
|
||||
glPushMatrix();
|
||||
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 edge_colormode = COLORMODE_NONE;
|
||||
|
||||
if (highlight) {
|
||||
csgmode = csgmode_e(csgmode + 20);
|
||||
colormode = COLORMODE_HIGHLIGHT;
|
||||
edge_colormode = COLORMODE_HIGHLIGHT_EDGES;
|
||||
} else if (background) {
|
||||
|
@ -89,16 +92,11 @@ void ThrownTogetherRenderer::renderCSGChain(CSGChain *chain, bool highlight,
|
|||
else {
|
||||
colormode = COLORMODE_BACKGROUND;
|
||||
}
|
||||
csgmode = csgmode_e(csgmode + 10);
|
||||
edge_colormode = COLORMODE_BACKGROUND_EDGES;
|
||||
} 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) {
|
||||
if (obj.flag & CSGTerm::FLAG_HIGHLIGHT) {
|
||||
colormode = COLORMODE_HIGHLIGHT;
|
||||
csgmode = csgmode_e(csgmode + 20);
|
||||
}
|
||||
else {
|
||||
colormode = COLORMODE_CUTOUT;
|
||||
|
@ -107,7 +105,6 @@ void ThrownTogetherRenderer::renderCSGChain(CSGChain *chain, bool highlight,
|
|||
} else {
|
||||
if (obj.flag & CSGTerm::FLAG_HIGHLIGHT) {
|
||||
colormode = COLORMODE_HIGHLIGHT;
|
||||
csgmode = csgmode_e(csgmode + 20);
|
||||
}
|
||||
else {
|
||||
colormode = COLORMODE_MATERIAL;
|
||||
|
|
26
src/Tree.cc
26
src/Tree.cc
|
@ -1,8 +1,11 @@
|
|||
#include "Tree.h"
|
||||
#include "nodedumper.h"
|
||||
#include "printutils.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
Tree::~Tree()
|
||||
{
|
||||
|
@ -29,11 +32,6 @@ const std::string &Tree::getString(const AbstractNode &node) const
|
|||
return this->nodecache[node];
|
||||
}
|
||||
|
||||
static bool filter(char c)
|
||||
{
|
||||
return c == ' ' || c == '\n' || c == '\t' || c == '\r';
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the cached ID string representation of the subtree rooted by \a node.
|
||||
If node is not cached, the cache will be rebuilt.
|
||||
|
@ -45,12 +43,22 @@ static bool filter(char c)
|
|||
const std::string &Tree::getIdString(const AbstractNode &node) const
|
||||
{
|
||||
assert(this->root_node);
|
||||
|
||||
if (!this->nodeidcache.contains(node)) {
|
||||
std::string str = getString(node);
|
||||
str.erase(std::remove_if(str.begin(), str.end(), filter), str.end());
|
||||
return this->nodeidcache.insert(node, str);
|
||||
const std::string &nodestr = getString(node);
|
||||
const boost::regex re("[^\\s\\\"]+|\\\"(?:[^\\\"\\\\]|\\\\.)*\\\"");
|
||||
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 <QDesktopServices>
|
||||
|
||||
#include "qtgettext.h"
|
||||
#include "UIUtils.h"
|
||||
#include "PlatformUtils.h"
|
||||
|
||||
|
@ -81,15 +82,15 @@ QStringList UIUtils::exampleCategories()
|
|||
{
|
||||
QStringList categories;
|
||||
//categories in File menu item - Examples
|
||||
categories << "Basics" << "Shapes" << "Extrusion" << "Advanced";
|
||||
categories << N_("Basics") << N_("Shapes") << N_("Extrusion") << N_("Advanced");
|
||||
|
||||
return categories;
|
||||
}
|
||||
|
||||
QFileInfoList UIUtils::exampleFiles(const QString &category)
|
||||
{
|
||||
QDir dir(QString::fromStdString(PlatformUtils::resourcesPath()));
|
||||
if (!dir.cd("examples") || !dir.cd(category)) {
|
||||
QDir dir(QString::fromStdString(PlatformUtils::resourcePath("examples").string()));
|
||||
if (!dir.cd(category)) {
|
||||
return QFileInfoList();
|
||||
}
|
||||
|
||||
|
|
|
@ -95,19 +95,19 @@ std::string Builtins::isDeprecated(const std::string &name)
|
|||
|
||||
Builtins::Builtins()
|
||||
{
|
||||
this->globalscope.assignments.push_back(Assignment("$fn", boost::shared_ptr<Expression>(new Expression(Value(0.0)))));
|
||||
this->globalscope.assignments.push_back(Assignment("$fs", boost::shared_ptr<Expression>(new Expression(Value(2.0)))));
|
||||
this->globalscope.assignments.push_back(Assignment("$fa", boost::shared_ptr<Expression>(new Expression(Value(12.0)))));
|
||||
this->globalscope.assignments.push_back(Assignment("$t", 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 ExpressionConst(ValuePtr(2.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 ExpressionConst(ValuePtr(0.0)))));
|
||||
|
||||
Value::VectorType zero3;
|
||||
zero3.push_back(Value(0.0));
|
||||
zero3.push_back(Value(0.0));
|
||||
zero3.push_back(Value(0.0));
|
||||
Value zero3val(zero3);
|
||||
this->globalscope.assignments.push_back(Assignment("$vpt", boost::shared_ptr<Expression>(new Expression(zero3val))));
|
||||
this->globalscope.assignments.push_back(Assignment("$vpr", boost::shared_ptr<Expression>(new Expression(zero3val))));
|
||||
this->globalscope.assignments.push_back(Assignment("$vpd", boost::shared_ptr<Expression>(new Expression(500))));
|
||||
ValuePtr zero3val(zero3);
|
||||
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 ExpressionConst(zero3val))));
|
||||
this->globalscope.assignments.push_back(Assignment("$vpd", boost::shared_ptr<Expression>(new ExpressionConst(ValuePtr(500)))));
|
||||
}
|
||||
|
||||
Builtins::~Builtins()
|
||||
|
|
|
@ -27,7 +27,7 @@ using boost::uintmax_t;
|
|||
#include <CGAL/Cartesian.h>
|
||||
#include <CGAL/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/Exact_predicates_exact_constructions_kernel.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::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::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::Explorer::Point which is different than
|
||||
|
|
|
@ -64,8 +64,11 @@ AbstractNode *CgaladvModule::instantiate(const Context *ctx, const ModuleInstant
|
|||
c.setVariables(args, 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) {
|
||||
convexity = c.lookup_variable("convexity", true);
|
||||
}
|
||||
|
@ -82,31 +85,31 @@ AbstractNode *CgaladvModule::instantiate(const Context *ctx, const ModuleInstant
|
|||
}
|
||||
|
||||
if (type == RESIZE) {
|
||||
Value ns = c.lookup_variable("newsize");
|
||||
ValuePtr ns = c.lookup_variable("newsize");
|
||||
node->newsize << 0,0,0;
|
||||
if ( ns.type() == Value::VECTOR ) {
|
||||
Value::VectorType vs = ns.toVector();
|
||||
if ( ns->type() == Value::VECTOR ) {
|
||||
const Value::VectorType &vs = ns->toVector();
|
||||
if ( vs.size() >= 1 ) node->newsize[0] = vs[0].toDouble();
|
||||
if ( vs.size() >= 2 ) node->newsize[1] = vs[1].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;
|
||||
if ( autosize.type() == Value::VECTOR ) {
|
||||
Value::VectorType va = autosize.toVector();
|
||||
if ( autosize->type() == Value::VECTOR ) {
|
||||
const Value::VectorType &va = autosize->toVector();
|
||||
if ( va.size() >= 1 ) node->autosize[0] = va[0].toBool();
|
||||
if ( va.size() >= 2 ) node->autosize[1] = va[1].toBool();
|
||||
if ( va.size() >= 3 ) node->autosize[2] = va[2].toBool();
|
||||
}
|
||||
else if ( autosize.type() == Value::BOOL ) {
|
||||
node->autosize << autosize.toBool(),autosize.toBool(),autosize.toBool();
|
||||
else if ( autosize->type() == Value::BOOL ) {
|
||||
node->autosize << autosize->toBool(),autosize->toBool(),autosize->toBool();
|
||||
}
|
||||
}
|
||||
|
||||
node->convexity = (int)convexity.toDouble();
|
||||
node->convexity = (int)convexity->toDouble();
|
||||
node->path = path;
|
||||
node->subdiv_type = subdiv_type.toString();
|
||||
node->level = (int)level.toDouble();
|
||||
node->subdiv_type = subdiv_type->toString();
|
||||
node->level = (int)level->toDouble();
|
||||
|
||||
if (node->level <= 1)
|
||||
node->level = 1;
|
||||
|
@ -151,7 +154,7 @@ std::string CgaladvNode::toString() const
|
|||
stream << "(convexity = " << this->convexity << ")";
|
||||
break;
|
||||
case GLIDE:
|
||||
stream << "(path = " << this->path << ", convexity = " << this->convexity << ")";
|
||||
stream << "(path = " << *this->path << ", convexity = " << this->convexity << ")";
|
||||
break;
|
||||
case SUBDIV:
|
||||
stream << "(level = " << this->level << ", convexity = " << this->convexity << ")";
|
||||
|
|
|
@ -26,7 +26,7 @@ public:
|
|||
virtual std::string toString() const;
|
||||
virtual std::string name() const;
|
||||
|
||||
Value path;
|
||||
ValuePtr path;
|
||||
std::string subdiv_type;
|
||||
int convexity, level;
|
||||
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 <CGAL/Delaunay_mesher_no_edge_refinement_2.h>
|
||||
#include <CGAL/Delaunay_mesh_face_base_2.h>
|
||||
//#include "cgal.h"
|
||||
//#include "tess.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;
|
||||
#ifdef NDEBUG
|
||||
#define PREV_NDEBUG NDEBUG
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
|
||||
#include <CGAL/Triangulation_2_filtered_projection_traits_3.h>
|
||||
#include <CGAL/Triangulation_face_base_with_info_2.h>
|
||||
#ifdef PREV_NDEBUG
|
||||
#define NDEBUG PREV_NDEBUG
|
||||
#endif
|
||||
|
||||
typedef CDT::Vertex_handle Vertex_handle;
|
||||
typedef CDT::Point CDTPoint;
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
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;
|
||||
struct FaceInfo {
|
||||
int nesting_level;
|
||||
bool in_domain() { return nesting_level%2 == 1; }
|
||||
};
|
||||
|
||||
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 );
|
||||
}
|
||||
typedef CGAL::Triangulation_2_filtered_projection_traits_3<K> Projection;
|
||||
typedef CGAL::Triangulation_face_base_with_info_2<FaceInfo, K> Fbb;
|
||||
typedef CGAL::Triangulation_data_structure_2<
|
||||
CGAL::Triangulation_vertex_base_2<Projection>,
|
||||
CGAL::Constrained_triangulation_face_base_2<Projection, Fbb> > Tds;
|
||||
typedef CGAL::Constrained_Delaunay_triangulation_2<
|
||||
Projection, Tds, CGAL::Exact_predicates_tag> CDT;
|
||||
|
||||
/* 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 )
|
||||
|
||||
static void mark_domains(CDT &ct,
|
||||
CDT::Face_handle start,
|
||||
int index,
|
||||
std::list<CDT::Edge>& border)
|
||||
{
|
||||
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;
|
||||
if (start->info().nesting_level != -1) return;
|
||||
std::list<CDT::Face_handle> queue;
|
||||
queue.push_back(start);
|
||||
while (!queue.empty()) {
|
||||
CDT::Face_handle fh = queue.front();
|
||||
queue.pop_front();
|
||||
if (fh->info().nesting_level == -1) {
|
||||
fh->info().nesting_level = index;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
CDT::Edge e(fh,i);
|
||||
CDT::Face_handle n = fh->neighbor(i);
|
||||
if (n->info().nesting_level == -1) {
|
||||
if (ct.is_constrained(e)) border.push_back(e);
|
||||
else queue.push_back(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
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;
|
||||
for(CDT::All_faces_iterator it = cdt.all_faces_begin(); it != cdt.all_faces_end(); ++it) {
|
||||
it->info().nesting_level = -1;
|
||||
}
|
||||
std::list<CDT::Edge> border;
|
||||
mark_domains(cdt, cdt.infinite_face(), 0, border);
|
||||
while (!border.empty()) {
|
||||
CDT::Edge e = border.front();
|
||||
border.pop_front();
|
||||
CDT::Face_handle n = e.first->neighbor(e.second);
|
||||
if (n->info().nesting_level == -1) {
|
||||
mark_domains(cdt, n, e.first->info().nesting_level+1, border);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 tessellate3DFaceWithHoles(std::vector<CGAL_Polygon_3> &polygons,
|
||||
std::vector<CGAL_Polygon_3> &triangles,
|
||||
CGAL_Plane_3 &plane)
|
||||
/*!
|
||||
polygons define a polygon, potentially with holes. Each contour
|
||||
should be added as a separate PolygonK instance.
|
||||
The tessellator will handle almost planar polygons.
|
||||
|
||||
If the normal is given, we will assume this as the normal vector of the polygon.
|
||||
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.");
|
||||
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 );
|
||||
Polygon t;
|
||||
t.push_back(Vector3d(polygon[0].x(), polygon[0].y(), polygon[0].z()));
|
||||
t.push_back(Vector3d(polygon[1].x(), polygon[1].y(), polygon[1].z()));
|
||||
t.push_back(Vector3d(polygon[2].x(), polygon[2].y(), polygon[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);
|
||||
}
|
||||
K::Vector_3 normalvec;
|
||||
if (normal) {
|
||||
normalvec = *normal;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Calculate best guess at face normal using Newell's method
|
||||
CGAL::normal_vector_newell_3(polygon.begin(), polygon.end(), normalvec);
|
||||
}
|
||||
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);
|
||||
|
||||
// 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);
|
||||
for (size_t i=0;i<polygon.size(); i++) {
|
||||
cdt.insert_constraint(polygon[i], polygon[(i+1)%polygon.size()]);
|
||||
}
|
||||
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() );
|
||||
|
||||
//Mark facets that are inside the domain bounded by the polygon
|
||||
mark_domains(cdt);
|
||||
|
||||
// Iterate over the resulting faces
|
||||
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 );
|
||||
for (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++) {
|
||||
K::Point_3 v = cdt.triangle(fit)[i];
|
||||
tri.push_back(Vector3d(v.x(), v.y(), v.z()));
|
||||
}
|
||||
triangles.push_back(tri);
|
||||
}
|
||||
}
|
||||
|
||||
PRINTDB("built %i triangles",triangles.size());
|
||||
return err;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
}; // namespace CGALUtils
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue