From 9cf0528e858d2bf247b993403cef1eec066d36f5 Mon Sep 17 00:00:00 2001 From: Gal Sasson Date: Wed, 14 Nov 2018 23:35:37 +0200 Subject: [PATCH 01/15] pass a vector of points istead of a pointer (satisfying GLM) --- src/ofxTriangleMesh.cpp | 7 ++++--- src/ofxTriangleMesh.h | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/ofxTriangleMesh.cpp b/src/ofxTriangleMesh.cpp index f33de83..dfe04aa 100755 --- a/src/ofxTriangleMesh.cpp +++ b/src/ofxTriangleMesh.cpp @@ -118,7 +118,7 @@ void ofxTriangleMesh::triangulate(ofPolyline contour, float angleConstraint, flo // here we check if a triangle is "inside" a contour to drop non inner triangles - if( isPointInsidePolygon(&contour[0], contour.size(), getTriangleCenter(tr) ) ) { + if( isPointInsidePolygon(contour.getVertices(), contour.size(), getTriangleCenter(tr) ) ) { triangle.randomColor = ofColor(ofRandom(0,255), ofRandom(0,255), ofRandom(0,255)); triangles.push_back(triangle); @@ -192,12 +192,12 @@ ofPoint ofxTriangleMesh::getTriangleCenter(ofPoint *tr){ return ofPoint(c_x, c_y); } -bool ofxTriangleMesh::isPointInsidePolygon(ofPoint *polygon,int N, ofPoint p) +bool ofxTriangleMesh::isPointInsidePolygon(const vector& polygon,int N, ofPoint p) { int counter = 0; int i; double xinters; - ofPoint p1,p2; + ofDefaultVec3 p1,p2; p1 = polygon[0]; @@ -242,3 +242,4 @@ void ofxTriangleMesh::draw() { triangulatedMesh.drawWireframe(); } + diff --git a/src/ofxTriangleMesh.h b/src/ofxTriangleMesh.h index 06d8944..79f4a36 100755 --- a/src/ofxTriangleMesh.h +++ b/src/ofxTriangleMesh.h @@ -65,7 +65,7 @@ class ofxTriangleMesh { ofPoint getTriangleCenter(ofPoint *tr); - bool isPointInsidePolygon(ofPoint *polygon,int N, ofPoint p); + bool isPointInsidePolygon(const vector& polygon,int N, ofPoint p); void draw(); void clear(); @@ -79,4 +79,5 @@ class ofxTriangleMesh { -}; \ No newline at end of file +}; + From 2968b26d452272df14981e64169c2ac105a91357 Mon Sep 17 00:00:00 2001 From: Tyler Henry Date: Tue, 18 Dec 2018 17:44:42 -0500 Subject: [PATCH 02/15] fix example --- example/{meshExample => }/addons.make | 0 example/{meshExample => }/bin/data/.gitkeep | 0 example/meshExample/Project.xcconfig | 9 - .../meshExample.xcodeproj/project.pbxproj | 1217 ----------------- .../xcschemes/meshExample Debug.xcscheme | 84 -- .../xcschemes/meshExample Release.xcscheme | 84 -- example/meshExample/openFrameworks-Info.plist | 20 - example/{meshExample => }/src/main.cpp | 8 +- .../src/testApp.cpp => src/ofApp.cpp} | 26 +- .../src/testApp.h => src/ofApp.h} | 2 +- 10 files changed, 17 insertions(+), 1433 deletions(-) rename example/{meshExample => }/addons.make (100%) rename example/{meshExample => }/bin/data/.gitkeep (100%) delete mode 100644 example/meshExample/Project.xcconfig delete mode 100644 example/meshExample/meshExample.xcodeproj/project.pbxproj delete mode 100644 example/meshExample/meshExample.xcodeproj/xcshareddata/xcschemes/meshExample Debug.xcscheme delete mode 100644 example/meshExample/meshExample.xcodeproj/xcshareddata/xcschemes/meshExample Release.xcscheme delete mode 100644 example/meshExample/openFrameworks-Info.plist rename example/{meshExample => }/src/main.cpp (54%) rename example/{meshExample/src/testApp.cpp => src/ofApp.cpp} (80%) rename example/{meshExample/src/testApp.h => src/ofApp.h} (94%) 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/meshExample/bin/data/.gitkeep b/example/bin/data/.gitkeep similarity index 100% rename from example/meshExample/bin/data/.gitkeep rename to example/bin/data/.gitkeep 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 80% rename from example/meshExample/src/testApp.cpp rename to example/src/ofApp.cpp index 8143a8f..0252b41 100644 --- a/example/meshExample/src/testApp.cpp +++ b/example/src/ofApp.cpp @@ -1,18 +1,18 @@ -#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); @@ -24,36 +24,36 @@ void testApp::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 +84,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(); From 568dfc341674a959b2b4fc93d9b14793430bc866 Mon Sep 17 00:00:00 2001 From: Tyler Henry Date: Tue, 18 Dec 2018 17:52:21 -0500 Subject: [PATCH 03/15] fix ofTriangle deprecrated --- src/ofxTriangleMesh.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ofxTriangleMesh.cpp b/src/ofxTriangleMesh.cpp index dfe04aa..962009f 100755 --- a/src/ofxTriangleMesh.cpp +++ b/src/ofxTriangleMesh.cpp @@ -230,9 +230,9 @@ void ofxTriangleMesh::draw() { ofFill(); ofSetColor( triangles[i].randomColor); - ofTriangle( outputPts[triangles[i].index[0]], - outputPts[triangles[i].index[1]], - outputPts[triangles[i].index[2]]); + ofDrawTriangle( outputPts[triangles[i].index[0]], + outputPts[triangles[i].index[1]], + outputPts[triangles[i].index[2]] ); } From 7363728e2f632f4ec033e4a8b544a86142143db5 Mon Sep 17 00:00:00 2001 From: tcoppex Date: Thu, 9 Apr 2020 15:36:11 +0200 Subject: [PATCH 04/15] Update addon to use extended Triangle capabilities. --- src/ofxTriangleMesh.cpp | 467 +++++++++++++++++++++++++++++----------- src/ofxTriangleMesh.h | 117 +++++++--- 2 files changed, 425 insertions(+), 159 deletions(-) diff --git a/src/ofxTriangleMesh.cpp b/src/ofxTriangleMesh.cpp index 962009f..81312a8 100755 --- a/src/ofxTriangleMesh.cpp +++ b/src/ofxTriangleMesh.cpp @@ -2,132 +2,266 @@ #include "triangle.h" +/*--------------------------------------------------------------------------- */ +namespace { +void TriangulatePoints(char * flags, triangulateio * in, triangulateio * mid, + triangulateio * out) { + triangulate(flags, in, mid, out); +} + +// QuickHull's Divide & Conquer step : +// finds the farest vertex from segment AB in direct order, +// then filter the vertices set and continue further. +typedef ofDefaultVec3 Vec2_t; +#define Vec2_t(x,y) Vec2_t(x, y, 0.0f) +typedef vector PointVector_t; +void FindHullVertex2D(Vec2_t const &A, + Vec2_t const &B, + PointVector_t const &vertices, + PointVector_t &hull_vertices) +{ + // Compute AB's orthogonal vector. + const auto AB = B - A; + const auto N = glm::normalize(Vec2_t(-AB.y, AB.x)); + // Compute vertices dot products relative to the base segment + // & retrieve the index of valid ones. + vector dots(vertices.size()); + vector indices; + for (size_t i=0; i numeric_limits::epsilon()) { + indices.push_back(i); + } + } -void triangulatePoints(char * flags, triangulateio * in, triangulateio * mid, - triangulateio * out){ + // 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; + } - // 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); + // 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. + const auto &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 ofxTriangleMesh::QuickHull(const ofPolyline &points, ofPolyline &hull) +{ + const PointVector_t &vertices = points.getVertices(); + PointVector_t hull_vertices; + + // Retrieve corner vertices, known to be on the convex hull. + auto min_v(vertices[0u]), max_v(vertices[0u]); + for (const auto& 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); + + // Add the result vertices to the polyline. + hull.addVertices(hull_vertices.data(), hull_vertices.size()); } +/*--------------------------------------------------------------------------- */ ofxTriangleMesh::ofxTriangleMesh(){ nTriangles = 0; } +void ofxTriangleMesh::triangulate(ofPolyline contour, float angleConstraint, float sizeConstraint) +{ +/// +/// Emulate the original method, which act like a Constrained Delaunay +/// with no added vertices and no handling of holes. +/// + VertexVector_t points; + SegmentVector_t segments; + VertexVector_t holes; -// see note in the h file for how to use the parameters here.... -void ofxTriangleMesh::triangulate(ofPolyline contour, float angleConstraint, float sizeConstraint){ + // Transform the polyline loop into separate buffers + // of points and segments while removing the last dupplicate element. + const auto &vertices = contour.getVertices(); + const int size = vertices.size() - 1; + for (int i = 0; i 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){ + string triangulateParams = "zQYp"; + if (angleConstraint > 0) { triangulateParams += "q" + ofToString( angleConstraint ); } - - if (bConstrainSize == true){ + if (sizeConstraint > 0) { triangulateParams += "a" + ofToString( (int)sizeConstraint ); } - - - triangulatePoints((char *) triangulateParams.c_str(), &in, &out, NULL); + triangulateArgs(points, segments, holes, triangulateParams); +} - - /* - 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"); +/* -------------------------------------------------------------------------- */ - } - */ - +void ofxTriangleMesh::triangulate( + const VertexVector_t &points, + const SegmentVector_t &segments, + const VertexVector_t &holes +) +{ + triangulateArgs(points, segments, holes, "zQpY"); +} + +void ofxTriangleMesh::triangulateConvexHull( + const VertexVector_t &points +) +{ + SegmentVector_t segments; + VertexVector_t holes; + triangulateArgs(points, segments, holes, "zQc"); +} + +void ofxTriangleMesh::triangulateDelaunay( + const VertexVector_t &points, + const SegmentVector_t &segments, + const VertexVector_t &holes, + bool bAddVertices +) +{ + string triangulateParams = "zQpD"; + if (!bAddVertices) { + triangulateParams += "Y"; + } + triangulateArgs(points, segments, holes, triangulateParams); +} + +void ofxTriangleMesh::triangulateConstrainedDelaunay( + const VertexVector_t &points, + const SegmentVector_t &segments, + const VertexVector_t &holes, + float angleConstraint, + float sizeConstraint, + bool bAddVertices +) +{ + string triangulateParams = "zQp"; + if (angleConstraint > 0) { + triangulateParams += "q" + ofToString( angleConstraint ); + } + if (sizeConstraint > 0) { + triangulateParams += "a" + ofToString( (int)sizeConstraint ); + } + if (!bAddVertices) { + triangulateParams += "Y"; + } + triangulateArgs(points, segments, holes, triangulateParams); +} + +void ofxTriangleMesh::triangulateArgs( + const VertexVector_t &points, + const SegmentVector_t &segments, + const VertexVector_t &holes, + const string &triangulateParams +) +{ + // >> triangulateParams 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 + + 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; + } + + /// @warning 'vorout' is necessary only when 'v' is set in triangulateParams + /// but is not actually accounted for here, see generateVoronoiDiagram(). + struct triangulateio out{}, vorout{}; + TriangulatePoints((char *)triangulateParams.c_str(), &in, &out, &vorout); nTriangles = 0; triangles.clear(); - - std::map < int , ofPoint > goodPts; - + // resize the buffer of colors used for debugging. + randomColors.reserve(out.numberoftriangles); + const int numRandomColors = static_cast(randomColors.size()); + + map goodPts; for (int i = 0; i < out.numberoftriangles; i++) { meshTriangle triangle; - int whichPt; - + 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.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 (i >= numRandomColors) { + randomColors.push_back(ofColor(ofRandom(255), ofRandom(255), ofRandom(255))); + } + + triangles.push_back(triangle); - if( isPointInsidePolygon(contour.getVertices(), 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++; + // 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. @@ -136,51 +270,131 @@ void ofxTriangleMesh::triangulate(ofPolyline contour, float angleConstraint, flo // that happens here: outputPts.clear(); - std::map < int, int > indexChanges; - std::map< int , ofPoint >::iterator iter; + map < int, int > indexChanges; + 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++){ + // 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++){ - triangles[i].index[j] = indexChanges[triangles[i].index[j]]; + tri.index[j] = indexChanges[tri.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 (const auto &pt : outputPts){ + triangulatedMesh.addVertex(pt); } - 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]);; + for (const auto &tri : triangles){ + triangulatedMesh.addIndex(tri.index[0]); + triangulatedMesh.addIndex(tri.index[1]); + triangulatedMesh.addIndex(tri.index[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; + 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 ofxTriangleMesh::generateVoronoiDiagram(const VertexVector_t &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; + } + + string params = "zQv"; + if (bUseDelaunay) { + params += "D"; + } + + TriangulatePoints((char*)params.c_str(), &in, &out, &vorout); + + // Save Voronoi result vertices. + voronoiPoints.resize(vorout.numberofpoints); + for (int i=0; i(voronoiPoints.size()) - 1; + } + + voronoiSegments[i] = glm::ivec2(e1, e2); + } + 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); } +void ofxTriangleMesh::drawVoronoi() const { + for (const auto &s : voronoiSegments) { + const auto &a = voronoiPoints[s.x]; + const auto &b = voronoiPoints[s.y]; + ofDrawLine(a.x, a.y, b.x, b.y); + } +} + +/* -------------------------------------------------------------------------- */ + void ofxTriangleMesh::clear(){ triangles.clear(); nTriangles = 0; @@ -197,7 +411,7 @@ bool ofxTriangleMesh::isPointInsidePolygon(const vector& polygon, int counter = 0; int i; double xinters; - ofDefaultVec3 p1,p2; + ofDefaultVec3 p1,p2; p1 = polygon[0]; @@ -211,35 +425,30 @@ bool ofxTriangleMesh::isPointInsidePolygon(const vector& polygon, 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; } - return counter % 2 != 0; + return counter % 2 != 0; } - -void ofxTriangleMesh::draw() { - - // draw the triangles in their random colors: - - for (int i=0; i& polygon,int N, ofPoint p); - - void draw(); + void draw() const; void clear(); + ofPoint getTriangleCenter(ofPoint *tr); + bool isPointInsidePolygon(const vector& polygon,int N, ofPoint p); + + // Triangulation output. int nTriangles; vector outputPts; vector triangles; + vector randomColors; ofMesh triangulatedMesh; - - - - + // [extension] + public : + // Aliases of internal types (for easy change if needed). + typedef ofPoint Vertex_t; + typedef vector VertexVector_t; + typedef vector SegmentVector_t; + + // Helper to cast a vector of Vertex_t-like structure to be + // accepted by the instance. + template + static const VertexVector_t& CastVector(const T &v) { + return *reinterpret_cast(&v); + } + + // Utility function to generate a convex hull. + static void QuickHull(const ofPolyline &points, ofPolyline &hull); + + //----------------------------------- + // 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. + //----------------------------------- + + // Simple triangulation. + void triangulate( + const VertexVector_t &points, + const SegmentVector_t &segments, + const VertexVector_t &holes = VertexVector_t() + ); + + // Triangulate the convex hull of a set of points. + void triangulateConvexHull(const vector &points); + + // Triangulate using Delaunay's algorithm. + void triangulateDelaunay( + const VertexVector_t &points, + const SegmentVector_t &segments, + const VertexVector_t &holes = VertexVector_t(), + bool bAddVertices=true + ); + + // Triangulate using Delaunay's algorithm constrained by + // triangles angle and/or size. + void triangulateConstrainedDelaunay( + const VertexVector_t &points, + const SegmentVector_t &segments, + const VertexVector_t &holes = VertexVector_t(), + float angleConstraint=-1, + float sizeConstraint=-1, + bool bAddVertices=true + ); + + // Generic triangulation template. + void triangulateArgs( + const VertexVector_t &points, + const SegmentVector_t &segments, + const VertexVector_t &holes, + const string &triangulateParams + ); + + // Generate a Voronoi diagram based on a previous triangulation + // result, if any. + void generateVoronoiDiagram() { + generateVoronoiDiagram(outputPts); + } + + // Generate a custom Voronoi diagram from a set of points. + void generateVoronoiDiagram(const VertexVector_t &points, bool bUseDelaunay=false); + + void drawVoronoi() const; + + // Voronoi diagram output. + VertexVector_t voronoiPoints; + SegmentVector_t voronoiSegments; }; From 7511a79b6d7f11f79dd0a84836b54a1fdf0a1d3c Mon Sep 17 00:00:00 2001 From: tcoppex Date: Thu, 9 Apr 2020 15:37:53 +0200 Subject: [PATCH 05/15] Add example showing extended capabilities. --- example-comparison/addons.make | 2 + example-comparison/bin/data/.gitkeep | 0 example-comparison/bin/data/A.poly | 62 ++++++ example-comparison/src/main.cpp | 13 ++ example-comparison/src/ofApp.cpp | 293 +++++++++++++++++++++++++++ example-comparison/src/ofApp.h | 71 +++++++ 6 files changed, 441 insertions(+) create mode 100644 example-comparison/addons.make create mode 100644 example-comparison/bin/data/.gitkeep create mode 100644 example-comparison/bin/data/A.poly create mode 100644 example-comparison/src/main.cpp create mode 100644 example-comparison/src/ofApp.cpp create mode 100644 example-comparison/src/ofApp.h 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-comparison/bin/data/.gitkeep b/example-comparison/bin/data/.gitkeep new file mode 100644 index 0000000..e69de29 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..bee21fd --- /dev/null +++ b/example-comparison/src/ofApp.cpp @@ -0,0 +1,293 @@ +#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("data/A.poly"); + +#else + + // Example with custom shape + + vertices_.push_back(ofPoint(0, 0)); + vertices_.push_back(ofPoint(ofGetWidth(), 0)); + vertices_.push_back(ofPoint(ofGetWidth(), ofGetHeight())); + vertices_.push_back(ofPoint(0, ofGetHeight())); + + float midx = ofGetWidth() / 2.0f; + float midy = ofGetHeight() / 2.0f; + float side = ofGetWidth() / 6.0f; + + vertices_.push_back(ofPoint(midx-side, midy-side)); + vertices_.push_back(ofPoint(midx+side, midy-side)); + vertices_.push_back(ofPoint(midx+side, midy+side)); + vertices_.push_back(ofPoint(midx-side, midy+side)); + + segments_.push_back(glm::ivec2(0, 1)); + segments_.push_back(glm::ivec2(1, 2)); + segments_.push_back(glm::ivec2(2, 3)); + segments_.push_back(glm::ivec2(3, 0)); + segments_.push_back(glm::ivec2(4, 5)); + segments_.push_back(glm::ivec2(5, 6)); + segments_.push_back(glm::ivec2(6, 7)); + segments_.push_back(glm::ivec2(7, 4)); + + holes_.push_back(ofPoint(midx, midy)); + +#endif + + // Extract contours as polylines + int lastIndex = -1; + ofPolyline *pl = nullptr; + for (const auto& segment : segments_) + { + if (lastIndex != segment.x) + { + pl = new ofPolyline(); + pl->addVertex( vertices_[segment.x] ); + polylines_.push_back(pl); + } + lastIndex = segment.y; + pl->addVertex( vertices_[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].triangulate(vertices_, segments_, holes_); + trimeshes_[CONVEX_HULL].triangulateConvexHull(vertices_); + trimeshes_[DELAUNAY].triangulateDelaunay(vertices_, segments_, holes_); + + /// @note + /// Should the need arises to send a buffer 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_->triangulateConstrainedDelaunay( vertices_, segments_, holes_, 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(); + } + + // Vertices + if (vertexToggle_) { + ofSetColor(120, 255, 120); + for (auto &vertex : vertices_) { + 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 : 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){ + +} + +//-------------------------------------------------------------- +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); + vertices_.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..b242416 --- /dev/null +++ b/example-comparison/src/ofApp.h @@ -0,0 +1,71 @@ +#pragma once + +#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. + std::vector vertices_; + std::vector segments_; + std::vector holes_; + + // Generated at import. + std::vector polylines_; + ofPolyline convexHull_; + ofPoint center_; + + // Triangulated mesh. + ofxTriangleMesh trimeshes_[kNumTriangulationType]; + ofxTriangleMesh *trimesh_current_; +}; From bfc979791023bef93cf721e0ebd37bed3b354498 Mon Sep 17 00:00:00 2001 From: tcoppex Date: Thu, 9 Apr 2020 15:59:45 +0200 Subject: [PATCH 06/15] Update README. --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 123cf8e..f3e0c47 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. + +An 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. From c46307880d5613d4bc9913284c8e420fd24f495b Mon Sep 17 00:00:00 2001 From: tcoppex Date: Fri, 7 Aug 2020 11:31:08 +0200 Subject: [PATCH 07/15] change curve rendering for readability. --- example/src/ofApp.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/example/src/ofApp.cpp b/example/src/ofApp.cpp index 0252b41..29edefd 100644 --- a/example/src/ofApp.cpp +++ b/example/src/ofApp.cpp @@ -13,14 +13,12 @@ void ofApp::update(){ //-------------------------------------------------------------- void ofApp::draw(){ - - ofBackgroundGradient(ofColor::white, ofColor(200,200,200), OF_GRADIENT_LINEAR); - line.draw(); - - mesh.draw(); + + ofSetColor(ofColor(150)); + line.draw(); } //-------------------------------------------------------------- From c96244eace04d2231f7128880c9de6c987bd702e Mon Sep 17 00:00:00 2001 From: tcoppex Date: Fri, 7 Aug 2020 11:39:15 +0200 Subject: [PATCH 08/15] cleanup --- src/ofxTriangleMesh.cpp | 126 ++++++++++++++----------- src/ofxTriangleMesh.h | 201 ++++++++++++++++++++-------------------- 2 files changed, 169 insertions(+), 158 deletions(-) diff --git a/src/ofxTriangleMesh.cpp b/src/ofxTriangleMesh.cpp index 81312a8..0a04b91 100755 --- a/src/ofxTriangleMesh.cpp +++ b/src/ofxTriangleMesh.cpp @@ -6,17 +6,23 @@ namespace { -void TriangulatePoints(char * flags, triangulateio * in, triangulateio * mid, - triangulateio * out) { +// Wrap the Triangle function to avoid aliasing issues. +void TriangulatePoints( + char * flags, triangulateio * in, + triangulateio * mid, + triangulateio * out) +{ triangulate(flags, in, mid, out); } -// QuickHull's Divide & Conquer step : -// finds the farest vertex from segment AB in direct order, -// then filter the vertices set and continue further. +// Types wrappers typedef ofDefaultVec3 Vec2_t; #define Vec2_t(x,y) Vec2_t(x, y, 0.0f) typedef vector PointVector_t; + +// QuickHull 2D Divide & Conquer step : +// Finds the farest vertex from segment AB in direct order, then filter the +// vertices set and continue further. void FindHullVertex2D(Vec2_t const &A, Vec2_t const &B, PointVector_t const &vertices, @@ -99,7 +105,7 @@ ofxTriangleMesh::ofxTriangleMesh(){ nTriangles = 0; } -void ofxTriangleMesh::triangulate(ofPolyline contour, float angleConstraint, float sizeConstraint) +void ofxTriangleMesh::triangulate(const ofPolyline &contour, float angleConstraint, float sizeConstraint) { /// /// Emulate the original method, which act like a Constrained Delaunay @@ -112,6 +118,7 @@ void ofxTriangleMesh::triangulate(ofPolyline contour, float angleConstraint, flo // Transform the polyline loop into separate buffers // of points and segments while removing the last dupplicate element. const auto &vertices = contour.getVertices(); + const int size = vertices.size() - 1; for (int i = 0; i& polygon,int N, ofPoint p) +/* -------------------------------------------------------------------------- */ + +void ofxTriangleMesh::clear() { - int counter = 0; - int i; - double xinters; - ofDefaultVec3 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; - } - return counter % 2 != 0; + triangles.clear(); + nTriangles = 0; } -void ofxTriangleMesh::draw() const +void ofxTriangleMesh::draw(bool use_debug_color) const { - // draw the triangles in their random colors: - int index=0; - for (const auto& tri : triangles){ - ofFill(); + // draw the triangles in their random colors: + int index = 0; + for (const auto& tri : triangles) { + ofFill(); + if (use_debug_color) { ofSetColor( randomColors[index++] ); - ofDrawTriangle( outputPts[tri.index[0]], - outputPts[tri.index[1]], - outputPts[tri.index[2]] ); } - - // draw the mesh as a wire frame in white on top. + ofDrawTriangle( outputPts[tri.index[0]], + outputPts[tri.index[1]], + outputPts[tri.index[2]] ); + } + + // draw the mesh as a wire frame in white on top. + if (use_debug_color) { ofSetColor(255,255,255); triangulatedMesh.drawWireframe(); + } } +/* -------------------------------------------------------------------------- */ diff --git a/src/ofxTriangleMesh.h b/src/ofxTriangleMesh.h index fb255fe..cecec94 100755 --- a/src/ofxTriangleMesh.h +++ b/src/ofxTriangleMesh.h @@ -23,118 +23,115 @@ #include "ofMain.h" - typedef struct{ ofPoint pts[3]; int index[3]; // for the mesh, what points does this triangle relate to. } meshTriangle; - class ofxTriangleMesh { // [Legacy code] public : - ofxTriangleMesh(); - - // usage notes: - // -1 = don't use constraint, other values = use constraint - // - // for angle, 20-30 is pretty good - // https://www.cs.cmu.edu/~quake/triangle.q.html - // be careful! "It usually doesn't terminate for angles above 34o" - // - // for size, this depends on the size of your shape, - // 100 to 200 is a good first guess for screen resolution based points - void triangulate(ofPolyline contour, float angleConstraint=-1, float sizeConstraint=-1); - - void draw() const; - void clear(); - - ofPoint getTriangleCenter(ofPoint *tr); - bool isPointInsidePolygon(const vector& polygon,int N, ofPoint p); - - // Triangulation output. - int nTriangles; - vector outputPts; - vector triangles; - vector randomColors; - ofMesh triangulatedMesh; + ofxTriangleMesh(); + + // usage notes: + // -1 = don't use constraint, other values = use constraint + // + // for angle, 20-30 is pretty good + // https://www.cs.cmu.edu/~quake/triangle.q.html + // be careful! "It usually doesn't terminate for angles above 34o" + // + // for size, this depends on the size of your shape, + // 100 to 200 is a good first guess for screen resolution based points + void triangulate(const ofPolyline &contour, float angleConstraint=-1, float sizeConstraint=-1); + + void draw(bool use_debug_color = true) const; + void clear(); + + // Triangulation output. + int nTriangles; + vector outputPts; + vector triangles; + vector randomColors; + ofMesh triangulatedMesh; // [extension] public : - // Aliases of internal types (for easy change if needed). - typedef ofPoint Vertex_t; - typedef vector VertexVector_t; - typedef vector SegmentVector_t; - - // Helper to cast a vector of Vertex_t-like structure to be - // accepted by the instance. - template - static const VertexVector_t& CastVector(const T &v) { - return *reinterpret_cast(&v); - } - - // Utility function to generate a convex hull. - static void QuickHull(const ofPolyline &points, ofPolyline &hull); - - //----------------------------------- - // 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. - //----------------------------------- - - // Simple triangulation. - void triangulate( - const VertexVector_t &points, - const SegmentVector_t &segments, - const VertexVector_t &holes = VertexVector_t() - ); - - // Triangulate the convex hull of a set of points. - void triangulateConvexHull(const vector &points); - - // Triangulate using Delaunay's algorithm. - void triangulateDelaunay( - const VertexVector_t &points, - const SegmentVector_t &segments, - const VertexVector_t &holes = VertexVector_t(), - bool bAddVertices=true - ); - - // Triangulate using Delaunay's algorithm constrained by - // triangles angle and/or size. - void triangulateConstrainedDelaunay( - const VertexVector_t &points, - const SegmentVector_t &segments, - const VertexVector_t &holes = VertexVector_t(), - float angleConstraint=-1, - float sizeConstraint=-1, - bool bAddVertices=true - ); - - // Generic triangulation template. - void triangulateArgs( - const VertexVector_t &points, - const SegmentVector_t &segments, - const VertexVector_t &holes, - const string &triangulateParams - ); - - // Generate a Voronoi diagram based on a previous triangulation - // result, if any. - void generateVoronoiDiagram() { - generateVoronoiDiagram(outputPts); - } - - // Generate a custom Voronoi diagram from a set of points. - void generateVoronoiDiagram(const VertexVector_t &points, bool bUseDelaunay=false); - - void drawVoronoi() const; - - // Voronoi diagram output. - VertexVector_t voronoiPoints; - SegmentVector_t voronoiSegments; + // Aliases of internal types (for easy change if needed). + typedef ofPoint Vertex_t; + typedef vector VertexVector_t; + typedef vector SegmentVector_t; + + // Helper to cast a vector of Vertex_t-like structure to be + // accepted by the instance. + template + static const VertexVector_t& CastVector(const T &v) { + return *reinterpret_cast(&v); + } + + // Utility function to generate a convex hull. + static void QuickHull(const ofPolyline &points, ofPolyline &hull); + + //----------------------------------- + // 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. + //----------------------------------- + + // Simple triangulation. + void triangulate( + const VertexVector_t &points, + const SegmentVector_t &segments, + const VertexVector_t &holes = VertexVector_t() + ); + + // Triangulate the convex hull of a set of points. + void triangulateConvexHull(const VertexVector_t &points); + + // Triangulate using Delaunay's algorithm. + void triangulateDelaunay( + const VertexVector_t &points, + const SegmentVector_t &segments, + const VertexVector_t &holes = VertexVector_t(), + bool bAddVertices=true + ); + + // Triangulate using Delaunay's algorithm constrained by + // triangles angle and/or size. + void triangulateConstrainedDelaunay( + const VertexVector_t &points, + const SegmentVector_t &segments, + const VertexVector_t &holes = VertexVector_t(), + float angleConstraint=-1, + float sizeConstraint=-1, + bool bAddVertices=true + ); + + // Generic triangulation template. + void triangulateArgs( + const VertexVector_t &points, + const SegmentVector_t &segments, + const VertexVector_t &holes, + const string &triangulateParams + ); + + // Generate a Voronoi diagram based on a previous triangulation + // result, if any. + void generateVoronoiDiagram() { + generateVoronoiDiagram(outputPts); + } + + // Generate a custom Voronoi diagram from a set of points. + void generateVoronoiDiagram(const VertexVector_t &points, bool bUseDelaunay=false); + + void drawVoronoi() const; + void drawCleanVoronoi(const VertexVector_t& poly) const; + + // Voronoi diagram output. + VertexVector_t voronoiPoints; + SegmentVector_t voronoiSegments; + std::vector voronoiInsideSegments; }; From 3f56f9e340c09746a10eb022510f63a35c43d69e Mon Sep 17 00:00:00 2001 From: tcoppex Date: Sat, 12 Jun 2021 21:33:18 +0200 Subject: [PATCH 09/15] Improve draw function, disable debug color by default, add drawWireframe. --- example/src/ofApp.cpp | 2 +- src/ofxTriangleMesh.cpp | 26 ++++++++++++++------------ src/ofxTriangleMesh.h | 17 ++++++++++++++--- 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/example/src/ofApp.cpp b/example/src/ofApp.cpp index 29edefd..d6786e3 100644 --- a/example/src/ofApp.cpp +++ b/example/src/ofApp.cpp @@ -15,7 +15,7 @@ void ofApp::update(){ void ofApp::draw(){ ofBackgroundGradient(ofColor::white, ofColor(200,200,200), OF_GRADIENT_LINEAR); - mesh.draw(); + mesh.draw(true); ofSetColor(ofColor(150)); line.draw(); diff --git a/src/ofxTriangleMesh.cpp b/src/ofxTriangleMesh.cpp index 0a04b91..c12735d 100755 --- a/src/ofxTriangleMesh.cpp +++ b/src/ofxTriangleMesh.cpp @@ -447,21 +447,23 @@ void ofxTriangleMesh::clear() void ofxTriangleMesh::draw(bool use_debug_color) const { // draw the triangles in their random colors: - int index = 0; - for (const auto& tri : triangles) { - ofFill(); - if (use_debug_color) { - ofSetColor( randomColors[index++] ); + if (use_debug_color) { + int index = 0; + for (const auto& tri : triangles) { + ofFill(); + if (use_debug_color) { + ofSetColor( randomColors[index++] ); + } + ofDrawTriangle( outputPts[tri.index[0]], + outputPts[tri.index[1]], + outputPts[tri.index[2]] ); } - ofDrawTriangle( outputPts[tri.index[0]], - outputPts[tri.index[1]], - outputPts[tri.index[2]] ); - } - // draw the mesh as a wire frame in white on top. - if (use_debug_color) { + // draw the mesh as a wire frame in white on top. ofSetColor(255,255,255); - triangulatedMesh.drawWireframe(); + drawWireframe(); + } else { + triangulatedMesh.draw(); } } diff --git a/src/ofxTriangleMesh.h b/src/ofxTriangleMesh.h index cecec94..9bd64e1 100755 --- a/src/ofxTriangleMesh.h +++ b/src/ofxTriangleMesh.h @@ -44,7 +44,8 @@ class ofxTriangleMesh { // 100 to 200 is a good first guess for screen resolution based points void triangulate(const ofPolyline &contour, float angleConstraint=-1, float sizeConstraint=-1); - void draw(bool use_debug_color = true) const; + void draw(bool use_debug_color = false) const; + void clear(); // Triangulation output. @@ -52,10 +53,11 @@ class ofxTriangleMesh { vector outputPts; vector triangles; vector randomColors; + ofMesh triangulatedMesh; - // [extension] - public : + // [extension] + public : // Aliases of internal types (for easy change if needed). typedef ofPoint Vertex_t; typedef vector VertexVector_t; @@ -129,6 +131,15 @@ class ofxTriangleMesh { void drawVoronoi() const; void drawCleanVoronoi(const VertexVector_t& poly) const; + + void drawWireframe() const { + triangulatedMesh.drawWireframe(); + } + + ofMesh& mesh() { + return triangulatedMesh; + } + // Voronoi diagram output. VertexVector_t voronoiPoints; SegmentVector_t voronoiSegments; From a5caff9d95d8d99ff4393a955f9ecb8d715e829a Mon Sep 17 00:00:00 2001 From: tcoppex Date: Mon, 14 Jun 2021 09:44:29 +0200 Subject: [PATCH 10/15] Update README. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f3e0c47..0eff5cc 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ 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. -An new example demonstrates the different features available. +A new example demonstrates the different features available. ![](https://tlgur.com/d/4RaXEMyg) From 3fb0129dc7c1ff27e12a93cff8963553ef093006 Mon Sep 17 00:00:00 2001 From: tcoppex Date: Mon, 14 Jun 2021 09:45:10 +0200 Subject: [PATCH 11/15] Add Makefile for examples. --- example-comparison/Makefile | 13 +++++++++++++ example/Makefile | 13 +++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 example-comparison/Makefile create mode 100644 example/Makefile 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/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 From 265827025b6539fcb612c7e4186f3ac19760ac1f Mon Sep 17 00:00:00 2001 From: tcoppex Date: Mon, 14 Jun 2021 09:46:43 +0200 Subject: [PATCH 12/15] Add a wrapper utility class to access the Triangle lib. --- libs/Triangle/triangle_utils.cpp | 348 +++++++++++++++++++++++++++++++ libs/Triangle/triangle_utils.h | 119 +++++++++++ 2 files changed, 467 insertions(+) create mode 100755 libs/Triangle/triangle_utils.cpp create mode 100755 libs/Triangle/triangle_utils.h 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..c9f0821 --- /dev/null +++ b/libs/Triangle/triangle_utils.h @@ -0,0 +1,119 @@ +#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 triangulate(VertexBuffer_t const& contour, float angleConstraint=-1, int sizeConstraint=-1); + + 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. + //----------------------------------- + + // 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_ + +/* -------------------------------------------------------------------------- */ From 0cfeb794f5f104f790593fd4e6f55b10abe581ff Mon Sep 17 00:00:00 2001 From: tcoppex Date: Mon, 14 Jun 2021 10:19:10 +0200 Subject: [PATCH 13/15] Cleanup & simplify. --- src/ofxTriangleMesh.cpp | 473 ++++------------------------------------ src/ofxTriangleMesh.h | 123 ++--------- 2 files changed, 63 insertions(+), 533 deletions(-) mode change 100755 => 100644 src/ofxTriangleMesh.cpp mode change 100755 => 100644 src/ofxTriangleMesh.h diff --git a/src/ofxTriangleMesh.cpp b/src/ofxTriangleMesh.cpp old mode 100755 new mode 100644 index c12735d..eebd2ef --- a/src/ofxTriangleMesh.cpp +++ b/src/ofxTriangleMesh.cpp @@ -1,470 +1,89 @@ #include "ofxTriangleMesh.h" #include "triangle.h" - -/*--------------------------------------------------------------------------- */ - -namespace { - -// Wrap the Triangle function to avoid aliasing issues. -void TriangulatePoints( - char * flags, triangulateio * in, - triangulateio * mid, - triangulateio * out) -{ - triangulate(flags, in, mid, out); -} - -// Types wrappers -typedef ofDefaultVec3 Vec2_t; -#define Vec2_t(x,y) Vec2_t(x, y, 0.0f) -typedef vector PointVector_t; - -// QuickHull 2D Divide & Conquer step : -// Finds the farest vertex from segment AB in direct order, then filter the -// vertices set and continue further. -void FindHullVertex2D(Vec2_t const &A, - Vec2_t const &B, - PointVector_t const &vertices, - PointVector_t &hull_vertices) -{ - // Compute AB's orthogonal vector. - const auto AB = B - A; - const auto N = glm::normalize(Vec2_t(-AB.y, AB.x)); - - // Compute vertices dot products relative to the base segment - // & retrieve the index of valid ones. - vector dots(vertices.size()); - vector indices; - for (size_t i=0; i 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. - const auto &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 ofxTriangleMesh::QuickHull(const ofPolyline &points, ofPolyline &hull) -{ - const PointVector_t &vertices = points.getVertices(); - PointVector_t hull_vertices; - - // Retrieve corner vertices, known to be on the convex hull. - auto min_v(vertices[0u]), max_v(vertices[0u]); - for (const auto& 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); - - // Add the result vertices to the polyline. - hull.addVertices(hull_vertices.data(), hull_vertices.size()); +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, float sizeConstraint) -{ -/// -/// Emulate the original method, which act like a Constrained Delaunay -/// with no added vertices and no handling of holes. -/// - VertexVector_t points; - SegmentVector_t segments; - VertexVector_t holes; - - // Transform the polyline loop into separate buffers - // of points and segments while removing the last dupplicate element. - const auto &vertices = contour.getVertices(); - - const int size = vertices.size() - 1; - for (int i = 0; i 0) { - triangulateParams += "q" + ofToString( angleConstraint ); - } - if (sizeConstraint > 0) { - triangulateParams += "a" + ofToString( (int)sizeConstraint ); - } - triangulateArgs(points, segments, holes, triangulateParams); +void ofxTriangleMesh::triangulate(const ofPolyline &contour, float angleConstraint, int sizeConstraint) { + TriangleUtils::triangulate( contour.getVertices(), angleConstraint, sizeConstraint); } /* -------------------------------------------------------------------------- */ -void ofxTriangleMesh::triangulate( - const VertexVector_t &points, - const SegmentVector_t &segments, - const VertexVector_t &holes -) -{ - triangulateArgs(points, segments, holes, "zQpY"); -} - -void ofxTriangleMesh::triangulateConvexHull( - const VertexVector_t &points -) -{ - SegmentVector_t segments; - VertexVector_t holes; - triangulateArgs(points, segments, holes, "zQc"); -} - -void ofxTriangleMesh::triangulateDelaunay( - const VertexVector_t &points, - const SegmentVector_t &segments, - const VertexVector_t &holes, - bool bAddVertices -) -{ - string triangulateParams = "zQpD"; - if (!bAddVertices) { - triangulateParams += "Y"; - } - triangulateArgs(points, segments, holes, triangulateParams); -} - -void ofxTriangleMesh::triangulateConstrainedDelaunay( - const VertexVector_t &points, - const SegmentVector_t &segments, - const VertexVector_t &holes, - float angleConstraint, - float sizeConstraint, - bool bAddVertices -) -{ - string triangulateParams = "zQp"; - if (angleConstraint > 0) { - triangulateParams += "q" + ofToString( angleConstraint ); - } - if (sizeConstraint > 0) { - triangulateParams += "a" + ofToString( (int)sizeConstraint ); - } - if (!bAddVertices) { - triangulateParams += "Y"; - } - triangulateArgs(points, segments, holes, triangulateParams); -} - -void ofxTriangleMesh::triangulateArgs( - const VertexVector_t &points, - const SegmentVector_t &segments, - const VertexVector_t &holes, - const string &triangulateParams -) -{ - // >> triangulateParams 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 - - 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; - } - - /// @warning 'vorout' is necessary only when 'v' is set in triangulateParams - /// but is not actually accounted for here, see generateVoronoiDiagram(). - struct triangulateio out{}, vorout{}; - TriangulatePoints((char *)triangulateParams.c_str(), &in, &out, &vorout); - - nTriangles = 0; - triangles.clear(); - - // resize the buffer of colors used for debugging. - randomColors.reserve(out.numberoftriangles); - const int numRandomColors = static_cast(randomColors.size()); - - map 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; - } - - if (i >= numRandomColors) { - randomColors.push_back(ofColor(ofRandom(255), ofRandom(255), ofRandom(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(); - map < int, int > indexChanges; - 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 (auto &tri : triangles){ - for (int j = 0; j < 3; j++){ - tri.index[j] = indexChanges[tri.index[j]]; - } - } - - // now make a mesh, using indices: - triangulatedMesh.clear(); - triangulatedMesh.setMode(OF_PRIMITIVE_TRIANGLES); - for (const auto &pt : outputPts){ - triangulatedMesh.addVertex(pt); - } - - for (const auto &tri : triangles){ - triangulatedMesh.addIndex(tri.index[0]); - triangulatedMesh.addIndex(tri.index[1]); - triangulatedMesh.addIndex(tri.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. - - 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); + // draw the mesh as a wire frame in white on top. + ofSetColor(0xff); + drawWireframe(); + } else { + triangulatedMesh.draw(); + } } /* -------------------------------------------------------------------------- */ -void ofxTriangleMesh::generateVoronoiDiagram(const VertexVector_t &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; - } - - string params = "zQv"; - if (bUseDelaunay) { - params += "D"; - } - - TriangulatePoints((char*)params.c_str(), &in, &out, &vorout); - - // Save Voronoi result vertices. - voronoiPoints.resize(vorout.numberofpoints); - for (int i=0; i(voronoiPoints.size()) - 1; - } - - voronoiSegments[i] = glm::ivec2(e1, e2); - } - - /* - // Detect interior segments for clean voronoi - voronoiInsideSegments.clear(); - voronoiInsideSegments.resize(voronoiSegments.size()); - - //const auto &poly = points; - - int index(0); - for (const auto &s : voronoiSegments) { - const auto &a = voronoiPoints[s.x]; - const auto &b = voronoiPoints[s.y]; - - bool inside1 = ofInsidePoly(a, poly); - bool inside2 = ofInsidePoly(b, poly); - voronoiInsideSegments[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); -} - void ofxTriangleMesh::drawVoronoi() const { - for (const auto &s : voronoiSegments) { - const auto &a = voronoiPoints[s.x]; - const auto &b = voronoiPoints[s.y]; + 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); } } -void ofxTriangleMesh::drawCleanVoronoi(const VertexVector_t& poly) const { +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 : voronoiSegments) { - const auto &a = voronoiPoints[s.x]; - const auto &b = voronoiPoints[s.y]; + 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)) { + if (inside1 && inside2) { ofDrawLine(a.x, a.y, b.x, b.y); } } - } /* -------------------------------------------------------------------------- */ -void ofxTriangleMesh::clear() -{ - triangles.clear(); - nTriangles = 0; -} +void ofxTriangleMesh::generateTriangleMesh() { + triangulatedMesh.clear(); + triangulatedMesh.setMode(OF_PRIMITIVE_TRIANGLES); -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 : triangles) { - ofFill(); - if (use_debug_color) { - ofSetColor( randomColors[index++] ); - } - ofDrawTriangle( outputPts[tri.index[0]], - outputPts[tri.index[1]], - outputPts[tri.index[2]] ); - } + for (const auto &pt : trimesh_.points) { + triangulatedMesh.addVertex(pt); + } + for (const auto &tri : trimesh_.triangles) { + triangulatedMesh.addIndex(tri.indices[0]); + triangulatedMesh.addIndex(tri.indices[1]); + triangulatedMesh.addIndex(tri.indices[2]); + } - // draw the mesh as a wire frame in white on top. - ofSetColor(255,255,255); - drawWireframe(); - } else { - triangulatedMesh.draw(); + for (size_t i=randomColors.size(); i outputPts; - vector triangles; - vector randomColors; + ofMesh& mesh() { return triangulatedMesh; } + ofMesh const& mesh() const { return triangulatedMesh; } - ofMesh triangulatedMesh; - - // [extension] - public : - // Aliases of internal types (for easy change if needed). - typedef ofPoint Vertex_t; - typedef vector VertexVector_t; - typedef vector SegmentVector_t; - - // Helper to cast a vector of Vertex_t-like structure to be - // accepted by the instance. - template - static const VertexVector_t& CastVector(const T &v) { - return *reinterpret_cast(&v); - } - - // Utility function to generate a convex hull. + // Utility function to generate a convex hull from a polyline. static void QuickHull(const ofPolyline &points, ofPolyline &hull); - //----------------------------------- - // 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. - //----------------------------------- - - // Simple triangulation. - void triangulate( - const VertexVector_t &points, - const SegmentVector_t &segments, - const VertexVector_t &holes = VertexVector_t() - ); - - // Triangulate the convex hull of a set of points. - void triangulateConvexHull(const VertexVector_t &points); - - // Triangulate using Delaunay's algorithm. - void triangulateDelaunay( - const VertexVector_t &points, - const SegmentVector_t &segments, - const VertexVector_t &holes = VertexVector_t(), - bool bAddVertices=true - ); - - // Triangulate using Delaunay's algorithm constrained by - // triangles angle and/or size. - void triangulateConstrainedDelaunay( - const VertexVector_t &points, - const SegmentVector_t &segments, - const VertexVector_t &holes = VertexVector_t(), - float angleConstraint=-1, - float sizeConstraint=-1, - bool bAddVertices=true - ); - - // Generic triangulation template. - void triangulateArgs( - const VertexVector_t &points, - const SegmentVector_t &segments, - const VertexVector_t &holes, - const string &triangulateParams - ); - - // Generate a Voronoi diagram based on a previous triangulation - // result, if any. - void generateVoronoiDiagram() { - generateVoronoiDiagram(outputPts); - } - - // Generate a custom Voronoi diagram from a set of points. - void generateVoronoiDiagram(const VertexVector_t &points, bool bUseDelaunay=false); - - void drawVoronoi() const; - void drawCleanVoronoi(const VertexVector_t& poly) const; - - - void drawWireframe() const { - triangulatedMesh.drawWireframe(); - } - - ofMesh& mesh() { - return triangulatedMesh; - } - - // Voronoi diagram output. - VertexVector_t voronoiPoints; - SegmentVector_t voronoiSegments; - std::vector voronoiInsideSegments; + private: + void generateTriangleMesh() override; + + ofMesh triangulatedMesh; + vector randomColors; }; - From 0efcc5c46831a7db68c8bf76d42847064e9070c6 Mon Sep 17 00:00:00 2001 From: tcoppex Date: Mon, 14 Jun 2021 10:20:14 +0200 Subject: [PATCH 14/15] Add a generic triangulate method for constrained Delaunay. --- libs/Triangle/triangle_utils.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/libs/Triangle/triangle_utils.h b/libs/Triangle/triangle_utils.h index c9f0821..3e8ccdf 100755 --- a/libs/Triangle/triangle_utils.h +++ b/libs/Triangle/triangle_utils.h @@ -61,9 +61,7 @@ class TriangleUtils { public: TriangleUtils() = default; - - void triangulate(VertexBuffer_t const& contour, float angleConstraint=-1, int sizeConstraint=-1); - + void clear() { trimesh_.points.clear(); trimesh_.triangles.clear(); @@ -79,6 +77,14 @@ class TriangleUtils { // 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); From f145164aff8f47ac1a447cab7273064f4b1c298e Mon Sep 17 00:00:00 2001 From: tcoppex Date: Mon, 14 Jun 2021 10:20:54 +0200 Subject: [PATCH 15/15] Update example to reflect API changes. --- example-comparison/src/ofApp.cpp | 78 ++++++++++++++++---------------- example-comparison/src/ofApp.h | 10 ++-- 2 files changed, 45 insertions(+), 43 deletions(-) diff --git a/example-comparison/src/ofApp.cpp b/example-comparison/src/ofApp.cpp index bee21fd..2cc5632 100644 --- a/example-comparison/src/ofApp.cpp +++ b/example-comparison/src/ofApp.cpp @@ -21,52 +21,52 @@ void ofApp::setup() #if 1 // Read from a 'Triangle' poly file. - ReadPolyFile("data/A.poly"); + ReadPolyFile( ofToDataPath("A.poly") ); #else // Example with custom shape - vertices_.push_back(ofPoint(0, 0)); - vertices_.push_back(ofPoint(ofGetWidth(), 0)); - vertices_.push_back(ofPoint(ofGetWidth(), ofGetHeight())); - vertices_.push_back(ofPoint(0, ofGetHeight())); + 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; - vertices_.push_back(ofPoint(midx-side, midy-side)); - vertices_.push_back(ofPoint(midx+side, midy-side)); - vertices_.push_back(ofPoint(midx+side, midy+side)); - vertices_.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_.points.push_back(ofPoint(midx-side, midy+side)); - segments_.push_back(glm::ivec2(0, 1)); - segments_.push_back(glm::ivec2(1, 2)); - segments_.push_back(glm::ivec2(2, 3)); - segments_.push_back(glm::ivec2(3, 0)); - segments_.push_back(glm::ivec2(4, 5)); - segments_.push_back(glm::ivec2(5, 6)); - segments_.push_back(glm::ivec2(6, 7)); - segments_.push_back(glm::ivec2(7, 4)); + 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)); - holes_.push_back(ofPoint(midx, midy)); + polygon_.holes.push_back(ofPoint(midx, midy)); #endif // Extract contours as polylines int lastIndex = -1; ofPolyline *pl = nullptr; - for (const auto& segment : segments_) + for (const auto& segment : polygon_.segments) { if (lastIndex != segment.x) { pl = new ofPolyline(); - pl->addVertex( vertices_[segment.x] ); + pl->addVertex( polygon_.points[segment.x] ); polylines_.push_back(pl); } lastIndex = segment.y; - pl->addVertex( vertices_[lastIndex] ); + pl->addVertex( polygon_.points[lastIndex] ); } ofPolyline *contour = polylines_[0]; @@ -78,12 +78,12 @@ void ofApp::setup() // Triangulate the shape. trimeshes_[ORIGINAL].triangulate(*contour); - trimeshes_[SIMPLE].triangulate(vertices_, segments_, holes_); - trimeshes_[CONVEX_HULL].triangulateConvexHull(vertices_); - trimeshes_[DELAUNAY].triangulateDelaunay(vertices_, segments_, holes_); + trimeshes_[SIMPLE].triangulateSimple(polygon_); + trimeshes_[CONVEX_HULL].triangulateConvexHull(polygon_.points); + trimeshes_[DELAUNAY].triangulateDelaunay(polygon_); /// @note - /// Should the need arises to send a buffer a different vector-type + /// 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())); @@ -111,7 +111,7 @@ void ofApp::update() { const float angleConstraint = ofLerp(10.0f, 30.0f, dx); const float areaConstraint = ofLerp(20.0f, 1000.0f, dy); - trimesh_current_->triangulateConstrainedDelaunay( vertices_, segments_, holes_, angleConstraint, areaConstraint); + trimesh_current_->triangulate( polygon_, angleConstraint, areaConstraint); trimesh_current_->generateVoronoiDiagram(); } } @@ -130,13 +130,13 @@ void ofApp::draw() // Faces if (faceToggle_) { - trimesh_current_->draw(); + trimesh_current_->draw(bUseDebugColor); } // Vertices if (vertexToggle_) { ofSetColor(120, 255, 120); - for (auto &vertex : vertices_) { + for (auto &vertex : polygon_.points) { ofDrawCircle( vertex.x, vertex.y, 2); } } @@ -150,7 +150,7 @@ void ofApp::draw() } // Holes ofSetColor(255, 120, 120); - for (auto hole : holes_) { + for (auto hole : polygon_.holes) { ofDrawCircle( hole.x, hole.y, 2); } } @@ -174,7 +174,9 @@ void ofApp::draw() //-------------------------------------------------------------- void ofApp::keyPressed(int key){ - + if (key == 'd') { + bUseDebugColor ^= true; + } } //-------------------------------------------------------------- @@ -242,10 +244,10 @@ void ofApp::ReadPolyFile(const string& filename) // Read vertices int numVertices, dummy; fscanf(fd, "%d 2 %d %d\n", &numVertices, &dummy, &dummy); - vertices_.resize(numVertices); + polygon_.points.resize(numVertices); for (int i=0; ix + resultX.second->x); diff --git a/example-comparison/src/ofApp.h b/example-comparison/src/ofApp.h index b242416..751b23f 100644 --- a/example-comparison/src/ofApp.h +++ b/example-comparison/src/ofApp.h @@ -1,7 +1,7 @@ #pragma once +#include #include "ofMain.h" - #include "ofxGui.h" #include "ofxTriangleMesh.h" @@ -56,9 +56,7 @@ class ofApp : public ofBaseApp{ ofxLabel typeLabel_; // Polygon geometrical datas. - std::vector vertices_; - std::vector segments_; - std::vector holes_; + ofxTriangleMesh::Polygon_t polygon_; // Generated at import. std::vector polylines_; @@ -66,6 +64,8 @@ class ofApp : public ofBaseApp{ ofPoint center_; // Triangulated mesh. - ofxTriangleMesh trimeshes_[kNumTriangulationType]; + std::array trimeshes_; ofxTriangleMesh *trimesh_current_; + + bool bUseDebugColor = true; };