diff --git a/README.md b/README.md index 123cf8e..0eff5cc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,16 @@ ofxTriangleMesh =============== +This extends the original `ofxTriangleMesh` addons to use more features from the `Triangle` library, namely triangulating simple polygon with holes and generating Voronoï Diagram, Conforming Delaunay Triangulation, and Convex Hull. + +A new example demonstrates the different features available. + +![](https://tlgur.com/d/4RaXEMyg) + +(original README below) + +*** + triangle mesh addon for openframeworks this is based on ofxTriangle, but uses triangle rather than the c++ wrapper triangle++, which allows for more flexability and options in the triangulation. diff --git a/example-comparison/Makefile b/example-comparison/Makefile new file mode 100644 index 0000000..177e172 --- /dev/null +++ b/example-comparison/Makefile @@ -0,0 +1,13 @@ +# Attempt to load a config.make file. +# If none is found, project defaults in config.project.make will be used. +ifneq ($(wildcard config.make),) + include config.make +endif + +# make sure the the OF_ROOT location is defined +ifndef OF_ROOT + OF_ROOT=$(realpath ../../..) +endif + +# call the project makefile! +include $(OF_ROOT)/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk diff --git a/example-comparison/addons.make b/example-comparison/addons.make new file mode 100644 index 0000000..d36616a --- /dev/null +++ b/example-comparison/addons.make @@ -0,0 +1,2 @@ +ofxGui +ofxTriangleMesh diff --git a/example/meshExample/bin/data/.gitkeep b/example-comparison/bin/data/.gitkeep similarity index 100% rename from example/meshExample/bin/data/.gitkeep rename to example-comparison/bin/data/.gitkeep diff --git a/example-comparison/bin/data/A.poly b/example-comparison/bin/data/A.poly new file mode 100644 index 0000000..166a717 --- /dev/null +++ b/example-comparison/bin/data/A.poly @@ -0,0 +1,62 @@ +29 2 1 0 +1 0.200000 -0.776400 -0.57 +2 0.220000 -0.773200 -0.55 +3 0.245600 -0.756400 -0.51 +4 0.277600 -0.702000 -0.53 +5 0.488800 -0.207600 0.28 +6 0.504800 -0.207600 0.30 +7 0.740800 -0.739600 0 +8 0.756000 -0.761200 -0.01 +9 0.774400 -0.772400 0 +10 0.800000 -0.776400 0.02 +11 0.800000 -0.792400 0.01 +12 0.579200 -0.792400 -0.21 +13 0.579200 -0.776400 -0.2 +14 0.621600 -0.771600 -0.15 +15 0.633600 -0.762800 -0.13 +16 0.639200 -0.744400 -0.1 +17 0.620800 -0.684400 -0.06 +18 0.587200 -0.604400 -0.01 +19 0.360800 -0.604400 -0.24 +20 0.319200 -0.706800 -0.39 +21 0.312000 -0.739600 -0.43 +22 0.318400 -0.761200 -0.44 +23 0.334400 -0.771600 -0.44 +24 0.371200 -0.776400 -0.41 +25 0.371200 -0.792400 -0.42 +26 0.374400 -0.570000 -0.2 +27 0.574400 -0.570000 0 +28 0.473600 -0.330800 0.14 +29 0.200000 -0.792400 -0.59 +29 0 +1 29 1 +2 1 2 +3 2 3 +4 3 4 +5 4 5 +6 5 6 +7 6 7 +8 7 8 +9 8 9 +10 9 10 +11 10 11 +12 11 12 +13 12 13 +14 13 14 +15 14 15 +16 15 16 +17 16 17 +18 17 18 +19 18 19 +20 19 20 +21 20 21 +22 21 22 +23 22 23 +24 23 24 +25 24 25 +26 25 29 +27 26 27 +28 27 28 +29 28 26 +1 +1 0.47 -0.5 diff --git a/example-comparison/src/main.cpp b/example-comparison/src/main.cpp new file mode 100644 index 0000000..e57370b --- /dev/null +++ b/example-comparison/src/main.cpp @@ -0,0 +1,13 @@ +#include "ofMain.h" +#include "ofApp.h" + +//======================================================================== +int main( ){ + ofSetupOpenGL(1024,768,OF_WINDOW); // <-------- setup the GL context + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(new ofApp()); + +} diff --git a/example-comparison/src/ofApp.cpp b/example-comparison/src/ofApp.cpp new file mode 100644 index 0000000..2cc5632 --- /dev/null +++ b/example-comparison/src/ofApp.cpp @@ -0,0 +1,295 @@ +#include "ofApp.h" + +#include +#include + +constexpr char* ofApp::sTriangulationTypes[kNumTriangulationType]; + +//-------------------------------------------------------------- +void ofApp::setup() +{ + gui_.setup(); + gui_.add(typeSlider_.setup("", + TriangulationType::DELAUNAY_CONSTRAINED, kFirstTriangulationType, kNumTriangulationType-1 + )); + gui_.add(vertexToggle_.setup("Original vertices", true)); + gui_.add(contourToggle_.setup("Contour", true)); + gui_.add(faceToggle_.setup("Faces", true)); + gui_.add(convexToggle_.setup("Convex hull", true)); + gui_.add(voronoiToggle_.setup("Voronoi diagram", true)); + +#if 1 + + // Read from a 'Triangle' poly file. + ReadPolyFile( ofToDataPath("A.poly") ); + +#else + + // Example with custom shape + + polygon_.points.push_back(ofPoint(0, 0)); + polygon_.points.push_back(ofPoint(ofGetWidth(), 0)); + polygon_.points.push_back(ofPoint(ofGetWidth(), ofGetHeight())); + polygon_.points.push_back(ofPoint(0, ofGetHeight())); + + float midx = ofGetWidth() / 2.0f; + float midy = ofGetHeight() / 2.0f; + float side = ofGetWidth() / 6.0f; + + polygon_.points.push_back(ofPoint(midx-side, midy-side)); + polygon_.points.push_back(ofPoint(midx+side, midy-side)); + polygon_.points.push_back(ofPoint(midx+side, midy+side)); + polygon_.points.push_back(ofPoint(midx-side, midy+side)); + + polygon_.segments.push_back(glm::ivec2(0, 1)); + polygon_.segments.push_back(glm::ivec2(1, 2)); + polygon_.segments.push_back(glm::ivec2(2, 3)); + polygon_.segments.push_back(glm::ivec2(3, 0)); + polygon_.segments.push_back(glm::ivec2(4, 5)); + polygon_.segments.push_back(glm::ivec2(5, 6)); + polygon_.segments.push_back(glm::ivec2(6, 7)); + polygon_.segments.push_back(glm::ivec2(7, 4)); + + polygon_.holes.push_back(ofPoint(midx, midy)); + +#endif + + // Extract contours as polylines + int lastIndex = -1; + ofPolyline *pl = nullptr; + for (const auto& segment : polygon_.segments) + { + if (lastIndex != segment.x) + { + pl = new ofPolyline(); + pl->addVertex( polygon_.points[segment.x] ); + polylines_.push_back(pl); + } + lastIndex = segment.y; + pl->addVertex( polygon_.points[lastIndex] ); + } + ofPolyline *contour = polylines_[0]; + + // Center of gravity. + center_ = contour->getCentroid2D(); + + // Generate a convex hull for the base contour. + ofxTriangleMesh::QuickHull(*contour, convexHull_); + + // Triangulate the shape. + trimeshes_[ORIGINAL].triangulate(*contour); + trimeshes_[SIMPLE].triangulateSimple(polygon_); + trimeshes_[CONVEX_HULL].triangulateConvexHull(polygon_.points); + trimeshes_[DELAUNAY].triangulateDelaunay(polygon_); + + /// @note + /// Should the need arises to send a buffer of a different vector-type + /// we could hack our way like this : + //#define castVec ofxTriangleMesh::CastVector + //trimesh.triangulateConvexHull(castVec(contour->getVertices())); + + // Generate the associated Voronoi diagrams. + for (auto &trimesh : trimeshes_) { + trimesh.generateVoronoiDiagram(); + } +} + +//-------------------------------------------------------------- +void ofApp::update() +{ + const float dx = ofMap(ofGetMouseX(), 0.0f, ofGetWidth(), 0.0f, 1.0f); + const float dy = ofMap(ofGetMouseY(), 0.0f, ofGetHeight(), 0.0f, 1.0f); + + // Update the current triangle mesh to display. + const int typeId = typeSlider_; + typeSlider_.setName(sTriangulationTypes[typeId]); + trimesh_current_ = &trimeshes_[typeId]; + + // When use Delaunay Constrained updates its constraints based + // on mouse coordinates. + if (typeId == DELAUNAY_CONSTRAINED) + { + const float angleConstraint = ofLerp(10.0f, 30.0f, dx); + const float areaConstraint = ofLerp(20.0f, 1000.0f, dy); + trimesh_current_->triangulate( polygon_, angleConstraint, areaConstraint); + trimesh_current_->generateVoronoiDiagram(); + } +} + +//-------------------------------------------------------------- +void ofApp::draw() +{ + ofPushMatrix(); + { + // Center the mesh on the screen. + ofTranslate( + ofGetWidth()/2 - center_.x, + ofGetHeight()/2 - center_.y, + 0.0f + ); + + // Faces + if (faceToggle_) { + trimesh_current_->draw(bUseDebugColor); + } + + // Vertices + if (vertexToggle_) { + ofSetColor(120, 255, 120); + for (auto &vertex : polygon_.points) { + ofDrawCircle( vertex.x, vertex.y, 2); + } + } + + // Contours + if (contourToggle_) { + // Segments + ofSetColor(120, 120, 255); + for (auto *poly : polylines_) { + poly->draw(); + } + // Holes + ofSetColor(255, 120, 120); + for (auto hole : polygon_.holes) { + ofDrawCircle( hole.x, hole.y, 2); + } + } + + // ConvexHull + if (convexToggle_) { + ofSetColor(0, 255, 0); + convexHull_.draw(); + } + + // Voronoi Diagram + if (voronoiToggle_) { + ofSetColor(255, 80, 80); + trimesh_current_->drawVoronoi(); + } + } + ofPopMatrix(); + + gui_.draw(); +} + +//-------------------------------------------------------------- +void ofApp::keyPressed(int key){ + if (key == 'd') { + bUseDebugColor ^= true; + } +} + +//-------------------------------------------------------------- +void ofApp::keyReleased(int key){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseMoved(int x, int y ){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseDragged(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void ofApp::mousePressed(int x, int y, int button){ +} + +//-------------------------------------------------------------- +void ofApp::mouseReleased(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseEntered(int x, int y){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseExited(int x, int y){ + +} + +//-------------------------------------------------------------- +void ofApp::windowResized(int w, int h){ + +} + +//-------------------------------------------------------------- +void ofApp::gotMessage(ofMessage msg){ + +} + +//-------------------------------------------------------------- +void ofApp::dragEvent(ofDragInfo dragInfo){ + +} + +//-------------------------------------------------------------- +void ofApp::ReadPolyFile(const string& filename) +{ + /// Simplified Triangle's .poly file reader. + + FILE *fd(nullptr); + if (nullptr == (fd = fopen(filename.c_str(), "r"))) { + fprintf(stderr, "Unable to found file \"%s\". Exiting..\n", filename.c_str()); + ofExit(); + } + + const float scaleFactor = std::min(ofGetWidth(), ofGetHeight()); + + // Read vertices + int numVertices, dummy; + fscanf(fd, "%d 2 %d %d\n", &numVertices, &dummy, &dummy); + polygon_.points.resize(numVertices); + for (int i=0; ix + resultX.second->x); + center_.y = 0.5f*(resultY.first->y + resultY.second->y); + */ +} + diff --git a/example-comparison/src/ofApp.h b/example-comparison/src/ofApp.h new file mode 100644 index 0000000..751b23f --- /dev/null +++ b/example-comparison/src/ofApp.h @@ -0,0 +1,71 @@ +#pragma once + +#include +#include "ofMain.h" +#include "ofxGui.h" +#include "ofxTriangleMesh.h" + +class ofApp : public ofBaseApp{ + + public: + void setup(); + void update(); + void draw(); + + void keyPressed(int key); + void keyReleased(int key); + void mouseMoved(int x, int y ); + void mouseDragged(int x, int y, int button); + void mousePressed(int x, int y, int button); + void mouseReleased(int x, int y, int button); + void mouseEntered(int x, int y); + void mouseExited(int x, int y); + void windowResized(int w, int h); + void dragEvent(ofDragInfo dragInfo); + void gotMessage(ofMessage msg); + + private: + enum TriangulationType { + kFirstTriangulationType = 0, + ORIGINAL = kFirstTriangulationType, + SIMPLE, + CONVEX_HULL, + DELAUNAY, + DELAUNAY_CONSTRAINED, + kNumTriangulationType + }; + + static constexpr char* sTriangulationTypes[kNumTriangulationType] = { + (char*)"Original", + (char*)"Simplest", + (char*)"Convex Hull", + (char*)"Delaunay", + (char*)"Delaunay constrained" + }; + + void ReadPolyFile(const string& filename); + + // GUI + ofxPanel gui_; + ofxToggle vertexToggle_; + ofxToggle contourToggle_; + ofxToggle faceToggle_; + ofxToggle voronoiToggle_; + ofxToggle convexToggle_; + ofxSlider typeSlider_; + ofxLabel typeLabel_; + + // Polygon geometrical datas. + ofxTriangleMesh::Polygon_t polygon_; + + // Generated at import. + std::vector polylines_; + ofPolyline convexHull_; + ofPoint center_; + + // Triangulated mesh. + std::array trimeshes_; + ofxTriangleMesh *trimesh_current_; + + bool bUseDebugColor = true; +}; diff --git a/example/Makefile b/example/Makefile new file mode 100644 index 0000000..177e172 --- /dev/null +++ b/example/Makefile @@ -0,0 +1,13 @@ +# Attempt to load a config.make file. +# If none is found, project defaults in config.project.make will be used. +ifneq ($(wildcard config.make),) + include config.make +endif + +# make sure the the OF_ROOT location is defined +ifndef OF_ROOT + OF_ROOT=$(realpath ../../..) +endif + +# call the project makefile! +include $(OF_ROOT)/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk diff --git a/example/meshExample/addons.make b/example/addons.make similarity index 100% rename from example/meshExample/addons.make rename to example/addons.make diff --git a/example/bin/data/.gitkeep b/example/bin/data/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/example/meshExample/Project.xcconfig b/example/meshExample/Project.xcconfig deleted file mode 100644 index 72633e9..0000000 --- a/example/meshExample/Project.xcconfig +++ /dev/null @@ -1,9 +0,0 @@ -//THE PATH TO THE ROOT OF OUR OF PATH RELATIVE TO THIS PROJECT. -//THIS NEEDS TO BE DEFINED BEFORE CoreOF.xcconfig IS INCLUDED -OF_PATH = ../../../.. - -//THIS HAS ALL THE HEADER AND LIBS FOR OF CORE -#include "../../../../libs/openFrameworksCompiled/project/osx/CoreOF.xcconfig" - -OTHER_LDFLAGS = $(OF_CORE_LIBS) -HEADER_SEARCH_PATHS = $(OF_CORE_HEADERS) diff --git a/example/meshExample/meshExample.xcodeproj/project.pbxproj b/example/meshExample/meshExample.xcodeproj/project.pbxproj deleted file mode 100644 index 27d4e82..0000000 --- a/example/meshExample/meshExample.xcodeproj/project.pbxproj +++ /dev/null @@ -1,1217 +0,0 @@ - - - - archiveVersion - 1 - classes - - objectVersion - 42 - objects - - 7938a53245bbe5d005288b3f06fdd748 - - explicitFileType - sourcecode.c.h - fileEncoding - 30 - isa - PBXFileReference - name - triangle.h - path - ../../../../addons/ofxTriangleMesh/libs/Triangle/triangle.h - sourceTree - SOURCE_ROOT - - 7e04d4fab9708987a9d1971851b4ac81 - - children - - a8e43c90843d9da179bd5f6d338dd0fa - 7938a53245bbe5d005288b3f06fdd748 - - isa - PBXGroup - name - Triangle - sourceTree - <group> - - fcaa0cca876cd31f282d632f5d8cb6b6 - - children - - 7e04d4fab9708987a9d1971851b4ac81 - - isa - PBXGroup - name - libs - sourceTree - <group> - - a58e30f81ffc795a1919b2b0b4f81dcd - - fileRef - a8e43c90843d9da179bd5f6d338dd0fa - isa - PBXBuildFile - - a8e43c90843d9da179bd5f6d338dd0fa - - explicitFileType - sourcecode.cpp.cpp - fileEncoding - 30 - isa - PBXFileReference - name - triangle.cpp - path - ../../../../addons/ofxTriangleMesh/libs/Triangle/triangle.cpp - sourceTree - SOURCE_ROOT - - 20896a8747958ab7edb07f1812b539cf - - explicitFileType - sourcecode.c.h - fileEncoding - 30 - isa - PBXFileReference - name - ofxTriangleMesh.h - path - ../../../../addons/ofxTriangleMesh/src/ofxTriangleMesh.h - sourceTree - SOURCE_ROOT - - 374c131120f53c04b100fe9033bdbbf8 - - children - - 3e88bb56bfb0306d19ddb1ac0c375b45 - 20896a8747958ab7edb07f1812b539cf - - isa - PBXGroup - name - src - sourceTree - <group> - - 53bebf43328554cda832cc05f26a9bcf - - children - - 374c131120f53c04b100fe9033bdbbf8 - fcaa0cca876cd31f282d632f5d8cb6b6 - - isa - PBXGroup - name - ofxTriangleMesh - sourceTree - <group> - - 220d3fa0b8d1a5e3af568f1594e7f026 - - fileRef - 3e88bb56bfb0306d19ddb1ac0c375b45 - isa - PBXBuildFile - - 3e88bb56bfb0306d19ddb1ac0c375b45 - - explicitFileType - sourcecode.cpp.cpp - fileEncoding - 30 - isa - PBXFileReference - name - ofxTriangleMesh.cpp - path - ../../../../addons/ofxTriangleMesh/src/ofxTriangleMesh.cpp - sourceTree - SOURCE_ROOT - - BB4B014C10F69532006C3DED - - children - - 53bebf43328554cda832cc05f26a9bcf - - isa - PBXGroup - name - addons - sourceTree - <group> - - BBAB23BE13894E4700AA2426 - - isa - PBXFileReference - lastKnownFileType - wrapper.framework - name - GLUT.framework - path - ../../../../libs/glut/lib/osx/GLUT.framework - sourceTree - <group> - - BBAB23C913894ECA00AA2426 - - children - - E4C2424410CC5A17004149E2 - E4C2424510CC5A17004149E2 - E4C2424610CC5A17004149E2 - E45BE9710E8CC7DD009D7055 - E45BE9720E8CC7DD009D7055 - E45BE9730E8CC7DD009D7055 - E45BE9740E8CC7DD009D7055 - E45BE9750E8CC7DD009D7055 - E45BE9760E8CC7DD009D7055 - E45BE9770E8CC7DD009D7055 - E45BE9790E8CC7DD009D7055 - E45BE97A0E8CC7DD009D7055 - - isa - PBXGroup - name - system frameworks - sourceTree - <group> - - BBAB23CA13894EDB00AA2426 - - children - - BBAB23BE13894E4700AA2426 - - isa - PBXGroup - name - 3rd party frameworks - sourceTree - <group> - - BBAB23CB13894F3D00AA2426 - - fileRef - BBAB23BE13894E4700AA2426 - isa - PBXBuildFile - - E4328143138ABC890047C5CB - - isa - PBXFileReference - lastKnownFileType - wrapper.pb-project - name - openFrameworksLib.xcodeproj - path - ../../../../libs/openFrameworksCompiled/project/osx/openFrameworksLib.xcodeproj - sourceTree - SOURCE_ROOT - - E4328144138ABC890047C5CB - - children - - E4328148138ABC890047C5CB - - isa - PBXGroup - name - Products - sourceTree - <group> - - E4328147138ABC890047C5CB - - containerPortal - E4328143138ABC890047C5CB - isa - PBXContainerItemProxy - proxyType - 2 - remoteGlobalIDString - E4B27C1510CBEB8E00536013 - remoteInfo - openFrameworks - - E4328148138ABC890047C5CB - - fileType - archive.ar - isa - PBXReferenceProxy - path - openFrameworks.a - remoteRef - E4328147138ABC890047C5CB - sourceTree - BUILT_PRODUCTS_DIR - - E4328149138ABC9F0047C5CB - - fileRef - E4328148138ABC890047C5CB - isa - PBXBuildFile - - E45BE5980E8CC70C009D7055 - - children - - BBAB23CA13894EDB00AA2426 - BBAB23C913894ECA00AA2426 - - isa - PBXGroup - name - frameworks - sourceTree - <group> - - E45BE9710E8CC7DD009D7055 - - isa - PBXFileReference - lastKnownFileType - wrapper.framework - name - AGL.framework - path - /System/Library/Frameworks/AGL.framework - sourceTree - <absolute> - - E45BE9720E8CC7DD009D7055 - - isa - PBXFileReference - lastKnownFileType - wrapper.framework - name - ApplicationServices.framework - path - /System/Library/Frameworks/ApplicationServices.framework - sourceTree - <absolute> - - E45BE9730E8CC7DD009D7055 - - isa - PBXFileReference - lastKnownFileType - wrapper.framework - name - AudioToolbox.framework - path - /System/Library/Frameworks/AudioToolbox.framework - sourceTree - <absolute> - - E45BE9740E8CC7DD009D7055 - - isa - PBXFileReference - lastKnownFileType - wrapper.framework - name - Carbon.framework - path - /System/Library/Frameworks/Carbon.framework - sourceTree - <absolute> - - E45BE9750E8CC7DD009D7055 - - isa - PBXFileReference - lastKnownFileType - wrapper.framework - name - CoreAudio.framework - path - /System/Library/Frameworks/CoreAudio.framework - sourceTree - <absolute> - - E45BE9760E8CC7DD009D7055 - - isa - PBXFileReference - lastKnownFileType - wrapper.framework - name - CoreFoundation.framework - path - /System/Library/Frameworks/CoreFoundation.framework - sourceTree - <absolute> - - E45BE9770E8CC7DD009D7055 - - isa - PBXFileReference - lastKnownFileType - wrapper.framework - name - CoreServices.framework - path - /System/Library/Frameworks/CoreServices.framework - sourceTree - <absolute> - - E45BE9790E8CC7DD009D7055 - - isa - PBXFileReference - lastKnownFileType - wrapper.framework - name - OpenGL.framework - path - /System/Library/Frameworks/OpenGL.framework - sourceTree - <absolute> - - E45BE97A0E8CC7DD009D7055 - - isa - PBXFileReference - lastKnownFileType - wrapper.framework - name - QuickTime.framework - path - /System/Library/Frameworks/QuickTime.framework - sourceTree - <absolute> - - E45BE97B0E8CC7DD009D7055 - - fileRef - E45BE9710E8CC7DD009D7055 - isa - PBXBuildFile - - E45BE97C0E8CC7DD009D7055 - - fileRef - E45BE9720E8CC7DD009D7055 - isa - PBXBuildFile - - E45BE97D0E8CC7DD009D7055 - - fileRef - E45BE9730E8CC7DD009D7055 - isa - PBXBuildFile - - E45BE97E0E8CC7DD009D7055 - - fileRef - E45BE9740E8CC7DD009D7055 - isa - PBXBuildFile - - E45BE97F0E8CC7DD009D7055 - - fileRef - E45BE9750E8CC7DD009D7055 - isa - PBXBuildFile - - E45BE9800E8CC7DD009D7055 - - fileRef - E45BE9760E8CC7DD009D7055 - isa - PBXBuildFile - - E45BE9810E8CC7DD009D7055 - - fileRef - E45BE9770E8CC7DD009D7055 - isa - PBXBuildFile - - E45BE9830E8CC7DD009D7055 - - fileRef - E45BE9790E8CC7DD009D7055 - isa - PBXBuildFile - - E45BE9840E8CC7DD009D7055 - - fileRef - E45BE97A0E8CC7DD009D7055 - isa - PBXBuildFile - - E4B69B4A0A3A1720003C02F2 - - children - - E4B6FCAD0C3E899E008CF71C - E4EB6923138AFD0F00A09F29 - E4B69E1C0A3A1BDC003C02F2 - E4EEC9E9138DF44700A80321 - BB4B014C10F69532006C3DED - E45BE5980E8CC70C009D7055 - E4B69B5B0A3A1756003C02F2 - - isa - PBXGroup - sourceTree - <group> - - E4B69B4C0A3A1720003C02F2 - - buildConfigurationList - E4B69B4D0A3A1720003C02F2 - compatibilityVersion - Xcode 2.4 - developmentRegion - English - hasScannedForEncodings - 0 - isa - PBXProject - knownRegions - - English - Japanese - French - German - - mainGroup - E4B69B4A0A3A1720003C02F2 - productRefGroup - E4B69B4A0A3A1720003C02F2 - projectDirPath - - projectReferences - - - ProductGroup - E4328144138ABC890047C5CB - ProjectRef - E4328143138ABC890047C5CB - - - projectRoot - - targets - - E4B69B5A0A3A1756003C02F2 - - - E4B69B4D0A3A1720003C02F2 - - buildConfigurations - - E4B69B4E0A3A1720003C02F2 - E4B69B4F0A3A1720003C02F2 - - defaultConfigurationIsVisible - 0 - defaultConfigurationName - Release - isa - XCConfigurationList - - E4B69B4E0A3A1720003C02F2 - - baseConfigurationReference - E4EB6923138AFD0F00A09F29 - buildSettings - - HEADER_SEARCH_PATHS - - $(OF_CORE_HEADERS) - ../../../../addons/ofxTriangleMesh/libs - ../../../../addons/ofxTriangleMesh/libs/Triangle - ../../../../addons/ofxTriangleMesh/src - - ARCHS - $(NATIVE_ARCH) - CONFIGURATION_BUILD_DIR - $(SRCROOT)/bin/ - COPY_PHASE_STRIP - NO - DEAD_CODE_STRIPPING - YES - GCC_AUTO_VECTORIZATION - YES - GCC_ENABLE_SSE3_EXTENSIONS - YES - GCC_ENABLE_SUPPLEMENTAL_SSE3_INSTRUCTIONS - YES - GCC_INLINES_ARE_PRIVATE_EXTERN - NO - GCC_OPTIMIZATION_LEVEL - 0 - GCC_SYMBOLS_PRIVATE_EXTERN - NO - GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS - NO - GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO - NO - GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL - NO - GCC_WARN_UNINITIALIZED_AUTOS - NO - GCC_WARN_UNUSED_VALUE - NO - GCC_WARN_UNUSED_VARIABLE - NO - OTHER_CPLUSPLUSFLAGS - - -D__MACOSX_CORE__ - -lpthread - -mtune=native - - - isa - XCBuildConfiguration - name - Debug - - E4B69B4F0A3A1720003C02F2 - - baseConfigurationReference - E4EB6923138AFD0F00A09F29 - buildSettings - - HEADER_SEARCH_PATHS - - $(OF_CORE_HEADERS) - ../../../../addons/ofxTriangleMesh/libs - ../../../../addons/ofxTriangleMesh/libs/Triangle - ../../../../addons/ofxTriangleMesh/src - - ARCHS - $(NATIVE_ARCH) - CONFIGURATION_BUILD_DIR - $(SRCROOT)/bin/ - COPY_PHASE_STRIP - YES - DEAD_CODE_STRIPPING - YES - GCC_AUTO_VECTORIZATION - YES - GCC_ENABLE_SSE3_EXTENSIONS - YES - GCC_ENABLE_SUPPLEMENTAL_SSE3_INSTRUCTIONS - YES - GCC_INLINES_ARE_PRIVATE_EXTERN - NO - GCC_OPTIMIZATION_LEVEL - 3 - GCC_SYMBOLS_PRIVATE_EXTERN - NO - GCC_UNROLL_LOOPS - YES - GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS - NO - GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO - NO - GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL - NO - GCC_WARN_UNINITIALIZED_AUTOS - NO - GCC_WARN_UNUSED_VALUE - NO - GCC_WARN_UNUSED_VARIABLE - NO - OTHER_CPLUSPLUSFLAGS - - -D__MACOSX_CORE__ - -lpthread - -mtune=native - - - isa - XCBuildConfiguration - name - Release - - E4B69B580A3A1756003C02F2 - - buildActionMask - 2147483647 - files - - E4B69E200A3A1BDC003C02F2 - E4B69E210A3A1BDC003C02F2 - 220d3fa0b8d1a5e3af568f1594e7f026 - a58e30f81ffc795a1919b2b0b4f81dcd - - isa - PBXSourcesBuildPhase - runOnlyForDeploymentPostprocessing - 0 - - E4B69B590A3A1756003C02F2 - - buildActionMask - 2147483647 - files - - E4EB6799138ADC1D00A09F29 - E4328149138ABC9F0047C5CB - E45BE97B0E8CC7DD009D7055 - E45BE97C0E8CC7DD009D7055 - E45BE97D0E8CC7DD009D7055 - E45BE97E0E8CC7DD009D7055 - E45BE97F0E8CC7DD009D7055 - E45BE9800E8CC7DD009D7055 - E45BE9810E8CC7DD009D7055 - E45BE9830E8CC7DD009D7055 - E45BE9840E8CC7DD009D7055 - E4C2424710CC5A17004149E2 - E4C2424810CC5A17004149E2 - E4C2424910CC5A17004149E2 - - isa - PBXFrameworksBuildPhase - runOnlyForDeploymentPostprocessing - 0 - - E4B69B5A0A3A1756003C02F2 - - buildConfigurationList - E4B69B5F0A3A1757003C02F2 - buildPhases - - E4B69B580A3A1756003C02F2 - E4B69B590A3A1756003C02F2 - E4B6FFFD0C3F9AB9008CF71C - E4C2427710CC5ABF004149E2 - - buildRules - - dependencies - - E4EEB9AC138B136A00A80321 - - isa - PBXNativeTarget - name - meshExample - productName - myOFApp - productReference - E4B69B5B0A3A1756003C02F2 - productType - com.apple.product-type.application - - E4B69B5B0A3A1756003C02F2 - - explicitFileType - wrapper.application - includeInIndex - 0 - isa - PBXFileReference - path - meshExampleDebug.app - sourceTree - BUILT_PRODUCTS_DIR - - E4B69B5F0A3A1757003C02F2 - - buildConfigurations - - E4B69B600A3A1757003C02F2 - E4B69B610A3A1757003C02F2 - - defaultConfigurationIsVisible - 0 - defaultConfigurationName - Release - isa - XCConfigurationList - - E4B69B600A3A1757003C02F2 - - buildSettings - - COPY_PHASE_STRIP - NO - FRAMEWORK_SEARCH_PATHS - - $(inherited) - $(FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1) - - FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1 - "$(SRCROOT)/../../../../libs/glut/lib/osx" - GCC_DYNAMIC_NO_PIC - NO - GCC_ENABLE_FIX_AND_CONTINUE - YES - GCC_GENERATE_DEBUGGING_SYMBOLS - YES - GCC_MODEL_TUNING - NONE - GCC_PRECOMPILE_PREFIX_HEADER - YES - GCC_PREFIX_HEADER - $(SYSTEM_LIBRARY_DIR)/Frameworks/Carbon.framework/Headers/Carbon.h - INFOPLIST_FILE - openFrameworks-Info.plist - INSTALL_PATH - $(HOME)/Applications - LIBRARY_SEARCH_PATHS - - $(inherited) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_2) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_3) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_4) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_5) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_6) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_7) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_8) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_9) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_10) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_11) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_12) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_13) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_14) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_15) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_2) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_3) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_7) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_8) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_9) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_10) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_11) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_12) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_13) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_16) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_17) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_18) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_19) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_20) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_21) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_22) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_23) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_24) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_25) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_26) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_27) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_28) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_29) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_30) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_31) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_32) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_33) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_34) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_35) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_36) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_37) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_38) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_39) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_40) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_41) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_42) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_43) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_44) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_45) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_46) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_47) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_48) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_49) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_50) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_51) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_52) - - PREBINDING - NO - PRODUCT_NAME - $(TARGET_NAME)Debug - WRAPPER_EXTENSION - app - - isa - XCBuildConfiguration - name - Debug - - E4B69B610A3A1757003C02F2 - - buildSettings - - COPY_PHASE_STRIP - YES - FRAMEWORK_SEARCH_PATHS - - $(inherited) - $(FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1) - - FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1 - "$(SRCROOT)/../../../../libs/glut/lib/osx" - GCC_ENABLE_FIX_AND_CONTINUE - NO - GCC_GENERATE_DEBUGGING_SYMBOLS - YES - GCC_MODEL_TUNING - NONE - GCC_PRECOMPILE_PREFIX_HEADER - YES - GCC_PREFIX_HEADER - $(SYSTEM_LIBRARY_DIR)/Frameworks/Carbon.framework/Headers/Carbon.h - INFOPLIST_FILE - openFrameworks-Info.plist - INSTALL_PATH - $(HOME)/Applications - LIBRARY_SEARCH_PATHS - - $(inherited) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_2) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_3) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_4) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_5) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_6) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_7) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_8) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_9) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_10) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_11) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_12) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_13) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_14) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_15) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_2) - $(LIBRARY_SEARCH_PATHS_QUOTED_1) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_3) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_7) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_8) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_9) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_10) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_11) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_12) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_13) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_16) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_17) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_18) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_19) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_20) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_21) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_22) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_23) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_24) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_25) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_26) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_27) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_28) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_29) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_30) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_31) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_32) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_33) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_34) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_35) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_36) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_37) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_38) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_39) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_40) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_41) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_42) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_43) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_44) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_45) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_46) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_47) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_48) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_49) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_50) - $(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_51) - - PREBINDING - NO - PRODUCT_NAME - $(TARGET_NAME) - WRAPPER_EXTENSION - app - - isa - XCBuildConfiguration - name - Release - - E4B69E1C0A3A1BDC003C02F2 - - children - - E4B69E1D0A3A1BDC003C02F2 - E4B69E1E0A3A1BDC003C02F2 - E4B69E1F0A3A1BDC003C02F2 - - isa - PBXGroup - path - src - sourceTree - SOURCE_ROOT - - E4B69E1D0A3A1BDC003C02F2 - - fileEncoding - 30 - isa - PBXFileReference - lastKnownFileType - sourcecode.cpp.cpp - name - main.cpp - path - src/main.cpp - sourceTree - SOURCE_ROOT - - E4B69E1E0A3A1BDC003C02F2 - - explicitFileType - sourcecode.cpp.cpp - fileEncoding - 30 - isa - PBXFileReference - name - testApp.cpp - path - src/testApp.cpp - sourceTree - SOURCE_ROOT - - E4B69E1F0A3A1BDC003C02F2 - - fileEncoding - 30 - isa - PBXFileReference - lastKnownFileType - sourcecode.c.h - name - testApp.h - path - src/testApp.h - sourceTree - SOURCE_ROOT - - E4B69E200A3A1BDC003C02F2 - - fileRef - E4B69E1D0A3A1BDC003C02F2 - isa - PBXBuildFile - - E4B69E210A3A1BDC003C02F2 - - fileRef - E4B69E1E0A3A1BDC003C02F2 - isa - PBXBuildFile - - E4B6FCAD0C3E899E008CF71C - - fileEncoding - 30 - isa - PBXFileReference - lastKnownFileType - text.plist.xml - path - openFrameworks-Info.plist - sourceTree - <group> - - E4B6FFFD0C3F9AB9008CF71C - - buildActionMask - 2147483647 - files - - inputPaths - - isa - PBXShellScriptBuildPhase - outputPaths - - runOnlyForDeploymentPostprocessing - 0 - shellPath - /bin/sh - shellScript - cp -f ../../../../libs/fmodex/lib/osx/libfmodex.dylib "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/MacOS/libfmodex.dylib"; install_name_tool -change ./libfmodex.dylib @executable_path/libfmodex.dylib "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/MacOS/$PRODUCT_NAME"; - - E4C2424410CC5A17004149E2 - - isa - PBXFileReference - lastKnownFileType - wrapper.framework - name - AppKit.framework - path - /System/Library/Frameworks/AppKit.framework - sourceTree - <absolute> - - E4C2424510CC5A17004149E2 - - isa - PBXFileReference - lastKnownFileType - wrapper.framework - name - Cocoa.framework - path - /System/Library/Frameworks/Cocoa.framework - sourceTree - <absolute> - - E4C2424610CC5A17004149E2 - - isa - PBXFileReference - lastKnownFileType - wrapper.framework - name - IOKit.framework - path - /System/Library/Frameworks/IOKit.framework - sourceTree - <absolute> - - E4C2424710CC5A17004149E2 - - fileRef - E4C2424410CC5A17004149E2 - isa - PBXBuildFile - - E4C2424810CC5A17004149E2 - - fileRef - E4C2424510CC5A17004149E2 - isa - PBXBuildFile - - E4C2424910CC5A17004149E2 - - fileRef - E4C2424610CC5A17004149E2 - isa - PBXBuildFile - - E4C2427710CC5ABF004149E2 - - buildActionMask - 2147483647 - dstPath - - dstSubfolderSpec - 10 - files - - BBAB23CB13894F3D00AA2426 - - isa - PBXCopyFilesBuildPhase - runOnlyForDeploymentPostprocessing - 0 - - E4EB6799138ADC1D00A09F29 - - fileRef - BBAB23BE13894E4700AA2426 - isa - PBXBuildFile - - E4EB691F138AFCF100A09F29 - - fileEncoding - 4 - isa - PBXFileReference - lastKnownFileType - text.xcconfig - name - CoreOF.xcconfig - path - ../../../../libs/openFrameworksCompiled/project/osx/CoreOF.xcconfig - sourceTree - SOURCE_ROOT - - E4EB6923138AFD0F00A09F29 - - fileEncoding - 4 - isa - PBXFileReference - lastKnownFileType - text.xcconfig - path - Project.xcconfig - sourceTree - <group> - - E4EEB9AB138B136A00A80321 - - containerPortal - E4328143138ABC890047C5CB - isa - PBXContainerItemProxy - proxyType - 1 - remoteGlobalIDString - E4B27C1410CBEB8E00536013 - remoteInfo - openFrameworks - - E4EEB9AC138B136A00A80321 - - isa - PBXTargetDependency - name - openFrameworks - targetProxy - E4EEB9AB138B136A00A80321 - - E4EEC9E9138DF44700A80321 - - children - - E4EB691F138AFCF100A09F29 - E4328143138ABC890047C5CB - - isa - PBXGroup - name - openFrameworks - sourceTree - <group> - - - rootObject - E4B69B4C0A3A1720003C02F2 - - diff --git a/example/meshExample/meshExample.xcodeproj/xcshareddata/xcschemes/meshExample Debug.xcscheme b/example/meshExample/meshExample.xcodeproj/xcshareddata/xcschemes/meshExample Debug.xcscheme deleted file mode 100644 index bc30738..0000000 --- a/example/meshExample/meshExample.xcodeproj/xcshareddata/xcschemes/meshExample Debug.xcscheme +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/example/meshExample/meshExample.xcodeproj/xcshareddata/xcschemes/meshExample Release.xcscheme b/example/meshExample/meshExample.xcodeproj/xcshareddata/xcschemes/meshExample Release.xcscheme deleted file mode 100644 index b264d3a..0000000 --- a/example/meshExample/meshExample.xcodeproj/xcshareddata/xcschemes/meshExample Release.xcscheme +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/example/meshExample/openFrameworks-Info.plist b/example/meshExample/openFrameworks-Info.plist deleted file mode 100644 index e5db555..0000000 --- a/example/meshExample/openFrameworks-Info.plist +++ /dev/null @@ -1,20 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - ${EXECUTABLE_NAME} - CFBundleIdentifier - com.yourcompany.openFrameworks - CFBundleInfoDictionaryVersion - 6.0 - CFBundlePackageType - APPL - CFBundleSignature - ???? - CFBundleVersion - 1.0 - - diff --git a/example/meshExample/src/main.cpp b/example/src/main.cpp similarity index 54% rename from example/meshExample/src/main.cpp rename to example/src/main.cpp index 6a32c6a..8bce185 100644 --- a/example/meshExample/src/main.cpp +++ b/example/src/main.cpp @@ -1,16 +1,14 @@ #include "ofMain.h" -#include "testApp.h" -#include "ofAppGlutWindow.h" +#include "ofApp.h" //======================================================================== int main( ){ - ofAppGlutWindow window; - ofSetupOpenGL(&window, 1024,768, OF_WINDOW); // <-------- setup the GL context + ofSetupOpenGL(1024,768, OF_WINDOW); // <-------- setup the GL context // this kicks off the running of my app // can be OF_WINDOW or OF_FULLSCREEN // pass in width and height too: - ofRunApp( new testApp()); + ofRunApp( new ofApp()); } diff --git a/example/meshExample/src/testApp.cpp b/example/src/ofApp.cpp similarity index 78% rename from example/meshExample/src/testApp.cpp rename to example/src/ofApp.cpp index 8143a8f..d6786e3 100644 --- a/example/meshExample/src/testApp.cpp +++ b/example/src/ofApp.cpp @@ -1,59 +1,57 @@ -#include "testApp.h" +#include "ofApp.h" //-------------------------------------------------------------- -void testApp::setup(){ +void ofApp::setup(){ } //-------------------------------------------------------------- -void testApp::update(){ +void ofApp::update(){ } //-------------------------------------------------------------- -void testApp::draw(){ - - +void ofApp::draw(){ ofBackgroundGradient(ofColor::white, ofColor(200,200,200), OF_GRADIENT_LINEAR); - line.draw(); - - - mesh.draw(); + mesh.draw(true); + + ofSetColor(ofColor(150)); + line.draw(); } //-------------------------------------------------------------- -void testApp::keyPressed(int key){ +void ofApp::keyPressed(int key){ } //-------------------------------------------------------------- -void testApp::keyReleased(int key){ +void ofApp::keyReleased(int key){ } //-------------------------------------------------------------- -void testApp::mouseMoved(int x, int y ){ +void ofApp::mouseMoved(int x, int y ){ } //-------------------------------------------------------------- -void testApp::mouseDragged(int x, int y, int button){ +void ofApp::mouseDragged(int x, int y, int button){ line.addVertex(ofPoint(x, y)); } //-------------------------------------------------------------- -void testApp::mousePressed(int x, int y, int button){ +void ofApp::mousePressed(int x, int y, int button){ line.clear(); line.addVertex(ofPoint(x, y)); } //-------------------------------------------------------------- -void testApp::mouseReleased(int x, int y, int button){ +void ofApp::mouseReleased(int x, int y, int button){ if (line.size() > 2){ @@ -84,16 +82,16 @@ void testApp::mouseReleased(int x, int y, int button){ } //-------------------------------------------------------------- -void testApp::windowResized(int w, int h){ +void ofApp::windowResized(int w, int h){ } //-------------------------------------------------------------- -void testApp::gotMessage(ofMessage msg){ +void ofApp::gotMessage(ofMessage msg){ } //-------------------------------------------------------------- -void testApp::dragEvent(ofDragInfo dragInfo){ +void ofApp::dragEvent(ofDragInfo dragInfo){ } \ No newline at end of file diff --git a/example/meshExample/src/testApp.h b/example/src/ofApp.h similarity index 94% rename from example/meshExample/src/testApp.h rename to example/src/ofApp.h index 24c3541..8490ffa 100644 --- a/example/meshExample/src/testApp.h +++ b/example/src/ofApp.h @@ -5,7 +5,7 @@ -class testApp : public ofBaseApp{ +class ofApp : public ofBaseApp{ public: void setup(); diff --git a/libs/Triangle/triangle_utils.cpp b/libs/Triangle/triangle_utils.cpp new file mode 100755 index 0000000..d17da4b --- /dev/null +++ b/libs/Triangle/triangle_utils.cpp @@ -0,0 +1,348 @@ +#include "triangle_utils.h" + +#include +#include "glm/glm.hpp" +#include "triangle.h" + +/*--------------------------------------------------------------------------- */ + +constexpr float TriangleUtils::kAngleConstraintLimit; +constexpr float TriangleUtils::kInfVoronoiSegmentFactor; + +namespace { + +// Wrap the Triangle main call function to avoid aliasing issues. +void TriangulatePoints(char const* flags, triangulateio *in, triangulateio *mid, triangulateio *out) { + triangulate((char*)flags, in, mid, out); +} + +// QuickHull 2D Divide & Conquer step : +// Finds the farest vertex from segment AB in direct order, then filter the +// vertices set and continue further. +using Vec2_t = glm::vec3; +using PointVector_t = std::vector; +#define Vec2_t(x,y) Vec2_t(x, y, 0.0f) +void FindHullVertex2D(Vec2_t const &A, + Vec2_t const &B, + PointVector_t const &vertices, + PointVector_t &hull_vertices) +{ + // Compute AB's orthogonal vector. + auto const AB = B - A; + auto const N = glm::normalize(Vec2_t(-AB.y, AB.x)); + + // Compute vertices dot products relative to the base segment + // & retrieve the index of valid ones. + std::vector dots(vertices.size()); + std::vector indices; + for (size_t i=0; i std::numeric_limits::epsilon()) { + indices.push_back(i); + } + } + + // Exit condition: no more vertices on this edge of space. + // Add the right vertex (B) and quit. + if ( indices.empty() + || ((indices.size() == 1) && (vertices[indices[0]] == B))) { + hull_vertices.push_back(B); + return; + } + + // Filter vertices & retrieve the farest vertex index. + PointVector_t sub_vertices(indices.size()); + size_t max_index = 0; + for (size_t i=0; i dots[vid]) ? max_index : vid; + } + + // Farest vertex from the base segment AB. + auto const &P = vertices[max_index]; + + // Continue with the two new sub-segments. + FindHullVertex2D(A, P, sub_vertices, hull_vertices); + FindHullVertex2D(P, B, sub_vertices, hull_vertices); +} + +} // namespace "" + + +/* -------------------------------------------------------------------------- */ + +void TriangleUtils::QuickHull(VertexBuffer_t const& vertices, VertexBuffer_t &hull_vertices) { + // Retrieve corner vertices, known to be on the convex hull. + auto min_v(vertices[0u]), max_v(vertices[0u]); + for (auto const& v : vertices) { + min_v = (min_v.x < v.x) ? min_v : v; + max_v = (max_v.x > v.x) ? max_v : v; + } + + // Vertices of the hull, initialized with the left vertex. + hull_vertices.clear(); + hull_vertices.push_back(min_v); + + // Subdivide search. + FindHullVertex2D(min_v, max_v, vertices, hull_vertices); + FindHullVertex2D(max_v, min_v, vertices, hull_vertices); +} + +/*--------------------------------------------------------------------------- */ + +void TriangleUtils::triangulate(VertexBuffer_t const& vertices, float angleConstraint, int sizeConstraint) { + Polygon_t polygon; + + // Transform the polyline loop into separate buffers + // of points and segments while removing the last duplicated element. + int const size = vertices.size() - 1; // + + polygon.points.reserve(size); + polygon.segments.reserve(size); + for (int i = 0; i < size; ++i) { + polygon.points.push_back( vertices[i] ); + polygon.segments.push_back( Segment_t(i, (i+1)%size) ); + } + triangulateConstrainedDelaunay( polygon, angleConstraint, sizeConstraint, false); +} + +/* -------------------------------------------------------------------------- */ + +void TriangleUtils::triangulateSimple(Polygon_t const& polygon) { + triangulateArgs(polygon, "zQpY"); +} + +void TriangleUtils::triangulateConvexHull(Polygon_t const& polygon) { + triangulateArgs( polygon, "zQc"); +} + +void TriangleUtils::triangulateConvexHull(VertexBuffer_t const& points) { + triangulateConvexHull( { points, SegmentBuffer_t() } ); +} + +void TriangleUtils::triangulateDelaunay(Polygon_t const& polygon, bool bAddVertices) { + std::string params = "zQpD"; + if (!bAddVertices) { + params += "Y"; + } + triangulateArgs( polygon, params); +} + +void TriangleUtils::triangulateConstrainedDelaunay(Polygon_t const& polygon, float angleConstraint, int sizeConstraint, bool bAddVertices) { + std::string params = "zQp"; + if (angleConstraint > 0) { + params += "q" + std::to_string( std::min(kAngleConstraintLimit, angleConstraint) ); + } + if (sizeConstraint > 0) { + params += "a" + std::to_string( sizeConstraint ); + } + if (!bAddVertices) { + params += "Y"; + } + triangulateArgs( polygon, params); +} + +void TriangleUtils::triangulateArgs(Polygon_t const& polygon, std::string const& params) { + // >> params basic options : + // Verbose : V + // Quiet : Q + // Index start at 0 : z + // Simple Polygon Triangulation : p + // Don't add new vertices : Y + // Constrained Delaunay : p[aX qX] + // Conforming Delaunay : pD + // Convex Hull : c + + auto &points = polygon.points; + auto &segments = polygon.segments; + auto &holes = polygon.holes; + + struct triangulateio in{}; + in.numberofpoints = static_cast(points.size()); + in.numberofpointattributes = 0; + in.pointmarkerlist = nullptr; + in.pointlist = (REAL*)calloc(2 * in.numberofpoints, sizeof(REAL)); + in.numberofsegments = static_cast(segments.size()); + in.segmentlist = (int*)calloc(2 * in.numberofsegments, sizeof(int)); + in.segmentmarkerlist = nullptr; + in.numberofholes = static_cast(holes.size()); + in.holelist = (REAL*)calloc(2 * in.numberofholes, sizeof(REAL)); + + for(int i = 0; i < in.numberofpoints; i++) { + in.pointlist[i*2+0] = points[i].x; + in.pointlist[i*2+1] = points[i].y; + } + for(int i = 0; i < in.numberofsegments; i++) { + in.segmentlist[i*2+0] = segments[i].x; + in.segmentlist[i*2+1] = segments[i].y; + } + for(int i = 0; i < in.numberofholes; i++) { + in.holelist[i*2+0] = holes[i].x; + in.holelist[i*2+1] = holes[i].y; + } + + /// @note 'vorout' is necessary only when 'v' is set in params + /// but is not actually accounted for here, see generateVoronoiDiagram(). + struct triangulateio out{}, vorout{}; + TriangulatePoints(params.c_str(), &in, &out, &vorout); + + // ------------------------------------- + + auto &Triangles = trimesh_.triangles; + Triangles.clear(); + Triangles.reserve(out.numberoftriangles); + + std::map goodPts; + for (int i = 0; i < out.numberoftriangles; i++) { + Triangle_t triangle; + + for (int j = 0; j < 3; j++){ + int const index = out.trianglelist[3 * i + j]; + triangle.coords[j].x = out.pointlist[2*index + 0]; + triangle.coords[j].y = out.pointlist[2*index + 1]; + triangle.coords[j].z = 0; + triangle.indices[j] = index; + } + Triangles.push_back(triangle); + + for (int j = 0; j < 3; j++){ + goodPts[triangle.indices[j]] = triangle.coords[j]; + } + } + + // put all good points in a std::vector and handle the remapping of indices. + // the indices stored above were for all points, but since we drop triangles, we + // can drop non used points, and then remap all the indces. + // that happens here: + auto &Points = trimesh_.points; + Points.clear(); + + std::map indexChanges; + for (auto iter = goodPts.cbegin(); iter != goodPts.cend(); ++iter) { + indexChanges[iter->first] = static_cast(Points.size()); + Points.push_back(iter->second); + } + + // now, with the new, potentially smaller group of points, + // update all the indices of the triangles so their indices point right: + for (auto &tri : Triangles){ + for (int j = 0; j < 3; j++){ + tri.indices[j] = indexChanges[tri.indices[j]]; + } + } + + generateTriangleMesh(); + + // ------------------------------------- + + if (in.pointlist) free(in.pointlist); + if (in.segmentlist) free(in.segmentlist); + if (in.holelist) free(in.holelist); + + if (out.pointlist) free(out.pointlist); + if (out.pointattributelist) free(out.pointattributelist); + if (out.pointmarkerlist) free(out.pointmarkerlist); + if (out.trianglelist) free(out.trianglelist); + if (out.triangleattributelist) free(out.triangleattributelist); + if (out.segmentlist) free(out.segmentlist); +} + +/* -------------------------------------------------------------------------- */ + +void TriangleUtils::generateVoronoiDiagram(VertexBuffer_t const& points, bool bUseDelaunay) { + if (points.size() < 3) { + return; + } + + struct triangulateio in{}, out{}, vorout{}; + in.numberofpoints = static_cast(points.size()); + in.pointlist = (REAL*)calloc(2 * in.numberofpoints, sizeof(REAL)); + for(int i = 0; i < in.numberofpoints; i++) { + in.pointlist[i*2+0] = points[i].x; + in.pointlist[i*2+1] = points[i].y; + } + + std::string params = "zQv"; + if (bUseDelaunay) { + params += "D"; + } + + TriangulatePoints(params.c_str(), &in, &out, &vorout); + + // Save Voronoi result vertices. + voronoi_.points.resize(vorout.numberofpoints); + for (int i = 0; i < vorout.numberofpoints; ++i) { + auto &pt = voronoi_.points[i]; + pt.x = vorout.pointlist[2*i+0]; + pt.y = vorout.pointlist[2*i+1]; + pt.z = 0; + } + + // Remap the edges indices to account for infinite vertices. + voronoi_.segments.resize(vorout.numberofedges); + for (int i=0; i < vorout.numberofedges; ++i) { + int const e1 = vorout.edgelist[2*i+0]; + int e2 = vorout.edgelist[2*i+1]; + + // if the edge is at infinite, add a virtually infinite distant vertex. + if (e2 < 0) { + float const nx = vorout.normlist[2*i+0]; + float const ny = vorout.normlist[2*i+1]; + + auto pt = voronoi_.points[e1]; + pt.x += kInfVoronoiSegmentFactor * nx; + pt.y += kInfVoronoiSegmentFactor * ny; + voronoi_.points.push_back(pt); + + e2 = static_cast(voronoi_.points.size()) - 1; + } + + voronoi_.segments[i] = Segment_t(e1, e2); + } + + /* + // Detect interior segments for clean voronoi + voronoi_.is_inside.clear(); + voronoi_.is_inside.resize(voronoi_.segments.size()); + + //auto const &poly = points; + + int index(0); + for (auto const &s : voronoi_.segments) { + auto const &a = voronoi_.points[s.x]; + auto const &b = voronoi_.points[s.y]; + + bool inside1 = ofInsidePoly(a, poly); + bool inside2 = ofInsidePoly(b, poly); + voronoi_.is_inside[index++] = (inside1 && inside2); + } + */ + + if (in.pointlist) free(in.pointlist); + if (in.segmentlist) free(in.segmentlist); + if (in.holelist) free(in.holelist); + + if (out.pointlist) free(out.pointlist); + if (out.pointattributelist) free(out.pointattributelist); + if (out.pointmarkerlist) free(out.pointmarkerlist); + if (out.trianglelist) free(out.trianglelist); + if (out.triangleattributelist) free(out.triangleattributelist); + if (out.segmentlist) free (out.segmentlist); + + if (vorout.pointattributelist) free(vorout.pointattributelist); + if (vorout.edgelist) free(vorout.edgelist); + if (vorout.normlist) free(vorout.normlist); +} + +bool TriangleUtils::generateVoronoiDiagram() { + if (trimesh_.points.empty()) { + return false; + } + generateVoronoiDiagram( trimesh_.points ); + return true; +} + +/* -------------------------------------------------------------------------- */ diff --git a/libs/Triangle/triangle_utils.h b/libs/Triangle/triangle_utils.h new file mode 100755 index 0000000..3e8ccdf --- /dev/null +++ b/libs/Triangle/triangle_utils.h @@ -0,0 +1,125 @@ +#ifndef TRIANGLE_TRIANGLE_UTILS_H_ +#define TRIANGLE_TRIANGLE_UTILS_H_ + +#include +#include +#include "glm/vec2.hpp" +#include "glm/vec3.hpp" + +/* -------------------------------------------------------------------------- */ + +class TriangleUtils { + public : + using Vertex_t = glm::vec3; + using VertexBuffer_t = std::vector; + + using Segment_t = glm::ivec2; + using SegmentBuffer_t = std::vector; + + struct Polygon_t { + Polygon_t() = default; + + Polygon_t(VertexBuffer_t const& _points, SegmentBuffer_t const& _segments, VertexBuffer_t const& _holes = VertexBuffer_t()) + : points(_points) + , segments(_segments) + , holes(_holes) + {} + + VertexBuffer_t points; + SegmentBuffer_t segments; + VertexBuffer_t holes; + }; + + struct Triangle_t { + std::array coords; + std::array indices; + }; + + struct TriMesh_t { + VertexBuffer_t points; + std::vector triangles; + }; + + struct Voronoi_t { + VertexBuffer_t points; + SegmentBuffer_t segments; + //std::vector is_inside; + }; + + static constexpr float kAngleConstraintLimit = 34.0f; + static constexpr float kInfVoronoiSegmentFactor = 250.0f; + + // Helper to cast a vector of Vertex_t-like structure to be + // accepted by the instance as VertexBuffer. + template + static VertexBuffer_t const& CastVector(T const& v) { + return *reinterpret_cast(&v); + } + + // Utility function to generate a convex hull. + static void QuickHull(VertexBuffer_t const& points, VertexBuffer_t &hull); + + public: + TriangleUtils() = default; + + void clear() { + trimesh_.points.clear(); + trimesh_.triangles.clear(); + voronoi_.points.clear(); + voronoi_.segments.clear(); + } + + //----------------------------------- + // usage notes: + // points : unordered set of vertices. + // segments : set of vertex indices for segment of the shape. + // holes : points inside interior segment loops not to triangulate. + // bAddVertices : when set to true, authorize the algorithm to add + // new vertices to fullfill its constraints. + //----------------------------------- + + // Triangulate a contour. First and last vertex must be the same. + void triangulate(VertexBuffer_t const& contour, float angleConstraint=-1, int sizeConstraint=-1); + + // Generic constrained Delaunay triangulation. + void triangulate(Polygon_t const& polygon, float angleConstraint=-1, int sizeConstraint=-1, bool bAddVertices=true) { + triangulateConstrainedDelaunay( polygon, angleConstraint, sizeConstraint, bAddVertices); + } + + // Simple polygon triangulation. + void triangulateSimple(Polygon_t const& polygon); + + // Triangulate the convex hull of a set of points. + void triangulateConvexHull(VertexBuffer_t const& points); + void triangulateConvexHull(Polygon_t const& polygon); + + // Triangulate using Delaunay's algorithm. + void triangulateDelaunay(Polygon_t const& polygon, bool bAddVertices=true); + + // Triangulate using Delaunay's algorithm constrained by triangles angle and/or size. + void triangulateConstrainedDelaunay(Polygon_t const& polygon, float angleConstraint=-1, int sizeConstraint=-1, bool bAddVertices=true); + + // Generic triangulation template. + void triangulateArgs(Polygon_t const& polygon, std::string const& params); + + // Generate a custom Voronoi diagram from a set of points. + void generateVoronoiDiagram(VertexBuffer_t const& points, bool bUseDelaunay=false); + + // Generate a Voronoi diagram based on a previous triangulation result, if any exists. + bool generateVoronoiDiagram(); + + // Getters. + inline TriMesh_t const& trimesh() const noexcept { return trimesh_; } + inline Voronoi_t const& voronoi() const noexcept { return voronoi_; } + + protected: + // Function to specialize used to create engine-specific triangle mesh. + virtual void generateTriangleMesh() {} + + TriMesh_t trimesh_; + Voronoi_t voronoi_; +}; + +#endif // TRIANGLE_TRIANGLE_UTILS_H_ + +/* -------------------------------------------------------------------------- */ diff --git a/src/ofxTriangleMesh.cpp b/src/ofxTriangleMesh.cpp old mode 100755 new mode 100644 index f33de83..eebd2ef --- a/src/ofxTriangleMesh.cpp +++ b/src/ofxTriangleMesh.cpp @@ -1,244 +1,89 @@ #include "ofxTriangleMesh.h" #include "triangle.h" +/* -------------------------------------------------------------------------- */ - - - - - -void triangulatePoints(char * flags, triangulateio * in, triangulateio * mid, - triangulateio * out){ - - // this funciton, which calls triangulage is because we have a function called triangulate, so the compiler get's a bit confused. - triangulate(flags, in, mid, out); +void ofxTriangleMesh::QuickHull(const ofPolyline &points, ofPolyline &hull) { + VertexBuffer_t hull_vertices; + TriangleUtils::QuickHull( points.getVertices(), hull_vertices); + hull.addVertices(hull_vertices.data(), hull_vertices.size()); } +/*--------------------------------------------------------------------------- */ -ofxTriangleMesh::ofxTriangleMesh(){ - nTriangles = 0; +void ofxTriangleMesh::triangulate(const ofPolyline &contour, float angleConstraint, int sizeConstraint) { + TriangleUtils::triangulate( contour.getVertices(), angleConstraint, sizeConstraint); } - -// see note in the h file for how to use the parameters here.... -void ofxTriangleMesh::triangulate(ofPolyline contour, float angleConstraint, float sizeConstraint){ - - int bSize = contour.size(); - - struct triangulateio in, out; - in.numberofpoints = bSize; - in.numberofpointattributes = 0; - in.pointmarkerlist = NULL; - in.pointlist = (REAL *) malloc(bSize * 2 * sizeof(REAL)); - in.numberofregions = 0; - in.regionlist = NULL; - - for(int i = 0; i < bSize; i++) { - in.pointlist[i*2+0] = contour[i].x; - in.pointlist[i*2+1] = contour[i].y; - } - - out.pointlist = (REAL *) NULL; - out.pointattributelist = (REAL *) NULL; - out.pointmarkerlist = (int *) NULL; - out.trianglelist = (int *) NULL; - out.triangleattributelist = (REAL *) NULL; - out.neighborlist = (int *) NULL; - out.segmentlist = (int *) NULL; - out.segmentmarkerlist = (int *) NULL; - out.edgelist = (int *) NULL; - out.edgemarkerlist = (int *) NULL; - - - bool bConstrainAngle = false; - bool bConstrainSize = false; - - if (angleConstraint > 0) bConstrainAngle = true; - if (sizeConstraint > 0) bConstrainSize = true; - - - - string triangulateParams; - - triangulateParams += "z"; // start from zero - triangulateParams += "Y"; // Prohibits the insertion of Steiner points (extra points) on the mesh boundary. - triangulateParams += "Q"; // quiet! change to V is you want alot of info - - if (bConstrainAngle == true){ - triangulateParams += "q" + ofToString( angleConstraint ); - } - - if (bConstrainSize == true){ - triangulateParams += "a" + ofToString( (int)sizeConstraint ); - } - - - triangulatePoints((char *) triangulateParams.c_str(), &in, &out, NULL); - - - /* - printf("Initial triangulation:\n\n"); - //report(&mid, 1, 1, 1, 1, 1, 0); - for (int i = 0; i < out.numberofpoints; i++) { - printf("Point %4d:", i); - for (int j = 0; j < 2; j++) { - printf(" %.6g", out.pointlist[i * 2 + j]); - } - printf("\n"); - - } - */ - - - nTriangles = 0; - triangles.clear(); - - - std::map < int , ofPoint > goodPts; - - for (int i = 0; i < out.numberoftriangles; i++) { - meshTriangle triangle; - - int whichPt; - - for (int j = 0; j < 3; j++){ - whichPt = out.trianglelist[i * 3 + j]; - triangle.pts[j] = ofPoint( out.pointlist[ whichPt * 2 + 0], out.pointlist[ whichPt * 2 + 1]); - triangle.index[j] = whichPt; - - - - } - - ofPoint tr[3]; - tr[0] = triangle.pts[0]; - tr[1] = triangle.pts[1]; - tr[2] = triangle.pts[2]; - - - // here we check if a triangle is "inside" a contour to drop non inner triangles - - if( isPointInsidePolygon(&contour[0], contour.size(), getTriangleCenter(tr) ) ) { - triangle.randomColor = ofColor(ofRandom(0,255), ofRandom(0,255), ofRandom(0,255)); - triangles.push_back(triangle); - - // store the good points in a map - for (int j = 0; j < 3; j++){ - goodPts[triangle.index[j]] = triangle.pts[j]; - } - nTriangles++; - } - } - - // put all good points in a vector and handle the remapping of indices. - // the indices stored above were for all points, but since we drop triangles, we - // can drop non used points, and then remap all the indces. - // that happens here: - - outputPts.clear(); - std::map < int, int > indexChanges; - std::map< int , ofPoint >::iterator iter; - for (iter = goodPts.begin(); iter != goodPts.end(); ++iter) { - //cout << iter->first << " " << iter->second << endl; - indexChanges[iter->first] = outputPts.size(); - outputPts.push_back(iter->second); - } - - // now, with the new, potentially smaller group of points, update all the indices of the triangles so their indices point right: - - for (int i = 0; i < triangles.size(); i++){ - for (int j = 0; j < 3; j++){ - triangles[i].index[j] = indexChanges[triangles[i].index[j]]; - } - } - - // now make a mesh, using indices: - - triangulatedMesh.clear(); - triangulatedMesh.setMode(OF_PRIMITIVE_TRIANGLES); - for (int i = 0; i < outputPts.size(); i++){ - triangulatedMesh.addVertex(outputPts[i]); - } - - for (int i = 0; i < triangles.size(); i++){ - triangulatedMesh.addIndex(triangles[i].index[0]);; - triangulatedMesh.addIndex(triangles[i].index[1]);; - triangulatedMesh.addIndex(triangles[i].index[2]);; +/* -------------------------------------------------------------------------- */ + +void ofxTriangleMesh::draw(bool use_debug_color) const { + // draw the triangles in their random colors: + if (use_debug_color) { + int index = 0; + for (const auto& tri : trimesh_.triangles) { + ofFill(); + if (use_debug_color) { + ofSetColor( randomColors[index++] ); + } + ofDrawTriangle( trimesh_.points[tri.indices[0]], + trimesh_.points[tri.indices[1]], + trimesh_.points[tri.indices[2]] ); } - // depending on flags, we may need to adjust some of the memory clearing - // (see tricall.c for full listings) - // TODO: this should be agressively tested. - - free(in.pointlist); - free(out.pointlist); - if (out.pointattributelist != NULL) free(out.pointattributelist); - if (out.pointmarkerlist != NULL) free(out.pointmarkerlist); - free(out.trianglelist); - if (out.triangleattributelist != NULL) free(out.triangleattributelist); - - return; - + // draw the mesh as a wire frame in white on top. + ofSetColor(0xff); + drawWireframe(); + } else { + triangulatedMesh.draw(); + } } -void ofxTriangleMesh::clear(){ - triangles.clear(); - nTriangles = 0; -} +/* -------------------------------------------------------------------------- */ -ofPoint ofxTriangleMesh::getTriangleCenter(ofPoint *tr){ - float c_x = (tr[0].x + tr[1].x + tr[2].x) / 3; - float c_y = (tr[0].y + tr[1].y + tr[2].y) / 3; - return ofPoint(c_x, c_y); +void ofxTriangleMesh::drawVoronoi() const { + for (const auto &s : voronoi_.segments) { + const auto &a = voronoi_.points[s.x]; + const auto &b = voronoi_.points[s.y]; + ofDrawLine(a.x, a.y, b.x, b.y); + } } -bool ofxTriangleMesh::isPointInsidePolygon(ofPoint *polygon,int N, ofPoint p) -{ - int counter = 0; - int i; - double xinters; - ofPoint p1,p2; - - p1 = polygon[0]; - - for (i=1;i<=N;i++) - { - p2 = polygon[i % N]; - if (p.y > MIN(p1.y,p2.y)) { - if (p.y <= MAX(p1.y,p2.y)) { - if (p.x <= MAX(p1.x,p2.x)) { - if (p1.y != p2.y) { - xinters = (p.y-p1.y)*(p2.x-p1.x)/(p2.y-p1.y)+p1.x; - if (p1.x == p2.x || p.x <= xinters){ - counter++; - } - } - } - } - } - p1 = p2; +void ofxTriangleMesh::drawCleanVoronoi(const VertexBuffer_t& poly) const { + /// @note + /// Neither efficient nor it seems always true when the shape contains + /// holes. + + for (const auto &s : voronoi_.segments) { + const auto &a = voronoi_.points[s.x]; + const auto &b = voronoi_.points[s.y]; + + bool inside1 = ofInsidePoly(a, poly); + bool inside2 = ofInsidePoly(b, poly); + if (inside1 && inside2) { + ofDrawLine(a.x, a.y, b.x, b.y); } - return counter % 2 != 0; + } } +/* -------------------------------------------------------------------------- */ -void ofxTriangleMesh::draw() { +void ofxTriangleMesh::generateTriangleMesh() { + triangulatedMesh.clear(); + triangulatedMesh.setMode(OF_PRIMITIVE_TRIANGLES); - // draw the triangles in their random colors: - - for (int i=0; i outputPts; - vector triangles; - ofMesh triangulatedMesh; - - + private: + void generateTriangleMesh() override; - - -}; \ No newline at end of file + ofMesh triangulatedMesh; + vector randomColors; +};