From 7e7fec69f61b2988c0b82c712d5f6beb4918e8cb Mon Sep 17 00:00:00 2001 From: Seth Hillbrand Date: Thu, 21 Mar 2024 02:00:42 +0100 Subject: [PATCH] Add logging and area check to tesselation Logging is useful when we find an area that cannot be triangulated. This will be used to generated test cases. Skipping minor untesselated areas means that the polygon will still be considered fully tesselated (and not sent back again and again) even if the tesselation misses an area less than the configured limit. Currently, this is 31^2nm. --- common/advanced_config.cpp | 6 ++++ include/advanced_config.h | 11 ++++++ .../include/geometry/polygon_triangulation.h | 36 ++++++++++++++++--- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/common/advanced_config.cpp b/common/advanced_config.cpp index d050d7b748..f1449375f0 100644 --- a/common/advanced_config.cpp +++ b/common/advanced_config.cpp @@ -108,6 +108,7 @@ static const wxChar MinimumSegmentLength[] = wxT( "MinimumSegmentLength" ); static const wxChar OcePluginLinearDeflection[] = wxT( "OcePluginLinearDeflection" ); static const wxChar OcePluginAngularDeflection[] = wxT( "OcePluginAngularDeflection" ); static const wxChar TriangulateSimplificationLevel[] = wxT( "TriangulateSimplificationLevel" ); +static const wxChar TriangulateMinimumArea[] = wxT( "TriangulateMinimumArea" ); } // namespace KEYS @@ -257,6 +258,7 @@ ADVANCED_CFG::ADVANCED_CFG() m_OcePluginAngularDeflection = 30; m_TriangulateSimplificationLevel = 50; + m_TriangulateMinimumArea = 1000; loadFromConfigFile(); } @@ -469,6 +471,10 @@ void ADVANCED_CFG::loadSettings( wxConfigBase& aCfg ) &m_TriangulateSimplificationLevel, m_TriangulateSimplificationLevel, 0, 1000 ) ); + configParams.push_back( new PARAM_CFG_INT( true, AC_KEYS::TriangulateMinimumArea, + &m_TriangulateMinimumArea, + m_TriangulateMinimumArea, 0, 100000 ) ); + // Special case for trace mask setting...we just grab them and set them immediately // Because we even use wxLogTrace inside of advanced config wxString traceMasks; diff --git a/include/advanced_config.h b/include/advanced_config.h index 37ba672567..68a792d64a 100644 --- a/include/advanced_config.h +++ b/include/advanced_config.h @@ -555,6 +555,17 @@ public: */ int m_TriangulateSimplificationLevel; + /** + * The minimum area of a polygon that can be left over after triangulation and + * still consider the triangulation successful. This is internal units, so + * it is square nm in pcbnew. + * + * Setting name: "TriangulateMinimumArea" + * Valid values: 0 to 100000 + * Default value: 1000 + */ + int m_TriangulateMinimumArea; + ///@} diff --git a/libs/kimath/include/geometry/polygon_triangulation.h b/libs/kimath/include/geometry/polygon_triangulation.h index 37e0fdde24..ed627cb6d9 100644 --- a/libs/kimath/include/geometry/polygon_triangulation.h +++ b/libs/kimath/include/geometry/polygon_triangulation.h @@ -50,6 +50,7 @@ #include #include +#include #include #include #include @@ -93,6 +94,10 @@ public: else { auto retval = earcutList( firstVertex ); + + if( !retval ) + logRemaining(); + m_vertices.clear(); return retval; } @@ -324,7 +329,7 @@ private: void logRemaining() { std::set seen; - + wxLog::EnableLogging(); for( VERTEX& p : m_vertices ) { if( !p.next || p.next == &p || seen.find( &p ) != seen.end() ) @@ -332,15 +337,27 @@ private: seen.insert( &p ); - wxString msg = wxString::Format( "Remaining: %d,%d,", p.x, p.y ); + // Don't both logging tiny areas + if( std::abs( p.area() ) < 10 ) + continue; + + int count = 1; + wxString msg = wxString::Format( "Remaining: %d,%d,", static_cast( p.x ), + static_cast( p.y ) ); VERTEX* q = p.next; do { - msg += wxString::Format( "%d,%d,", q->x, q->y ); + msg += wxString::Format( "%d,%d,", static_cast( q->x ), + static_cast( q->y ) ); seen.insert( q ); q = q->next; - } while ( q != &p ); + count++; + } while( q != &p ); + + // Don't log anything that only has 2 or fewer points + if( count < 3 ) + continue; msg.RemoveLast(); wxLogTrace( TRIANGULATE_TRACE, msg ); @@ -362,12 +379,18 @@ private: { if( *p == *( p->next ) || area( p->prev, p, p->next ) == 0.0 ) { + // This is a spike, remove it, leaving only one point + if( *( p->next ) == *( p->prev ) ) + p->next->remove(); + p = p->prev; p->next->remove(); retval = aStart; if( p == p->next ) break; + + continue; } p = p->next; @@ -551,7 +574,10 @@ private: /* * At this point, our polygon should be fully tessellated. */ - return( aPoint->prev == aPoint->next ); + if( aPoint->prev != aPoint->next ) + return std::abs( aPoint->area() > ADVANCED_CFG::GetCfg().m_TriangulateMinimumArea ); + + return true; } /**