From eaf8eb284a9499103527c8ca3d9f16ac23e57e51 Mon Sep 17 00:00:00 2001 From: Roberto Fernandez Bautista Date: Mon, 26 Jul 2021 17:14:05 +0100 Subject: [PATCH] Add true arc-to-polyline collisions --- libs/kimath/src/geometry/shape_collisions.cpp | 49 +++++++++++++++++-- qa/libs/kimath/geometry/test_shape_arc.cpp | 5 +- 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/libs/kimath/src/geometry/shape_collisions.cpp b/libs/kimath/src/geometry/shape_collisions.cpp index eca244e584..7153cb8ee3 100644 --- a/libs/kimath/src/geometry/shape_collisions.cpp +++ b/libs/kimath/src/geometry/shape_collisions.cpp @@ -534,14 +534,53 @@ static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_LINE_CHAIN_BASE& aB aA.Type(), aB.Type() ) ); - const SHAPE_LINE_CHAIN lc = aA.ConvertToPolyline(); + int closest_dist = INT_MAX; + VECTOR2I nearest; - bool rv = Collide( lc, aB, aClearance + aA.GetWidth() / 2, aActual, aLocation, aMTV ); + if( aB.IsClosed() && aB.PointInside( aA.GetP0() ) ) + { + closest_dist = 0; + nearest = aA.GetP0(); + } + else + { + for( size_t i = 0; i < aB.GetSegmentCount(); i++ ) + { + int collision_dist = 0; + VECTOR2I pn; - if( rv && aActual ) - *aActual = std::max( 0, *aActual - aA.GetWidth() / 2 ); + if( aA.Collide( aB.GetSegment( i ), aClearance, + aActual || aLocation ? &collision_dist : nullptr, + aLocation ? &pn : nullptr ) ) + { + if( collision_dist < closest_dist ) + { + nearest = pn; + closest_dist = collision_dist; + } - return rv; + if( closest_dist == 0 ) + break; + + // If we're not looking for aActual then any collision will do + if( !aActual ) + break; + } + } + } + + if( closest_dist == 0 || closest_dist < aClearance ) + { + if( aLocation ) + *aLocation = nearest; + + if( aActual ) + *aActual = closest_dist; + + return true; + } + + return false; } diff --git a/qa/libs/kimath/geometry/test_shape_arc.cpp b/qa/libs/kimath/geometry/test_shape_arc.cpp index 3005b30d97..7e7d63d92b 100644 --- a/qa/libs/kimath/geometry/test_shape_arc.cpp +++ b/qa/libs/kimath/geometry/test_shape_arc.cpp @@ -761,10 +761,11 @@ BOOST_AUTO_TEST_CASE( CollideArcToPolygonApproximation ) // Create a polyset approximation from the arc - error outside (simulating the zone filler) SHAPE_POLY_SET arcBuffer; int clearance = ( arc.GetWidth() * 3 ) / 2; + int polygonApproximationError = SHAPE_ARC::DefaultAccuracyForPCB(); TransformArcToPolygon( arcBuffer, wxPoint( arc.GetP0() ), wxPoint( arc.GetArcMid() ), wxPoint( arc.GetP1() ), arc.GetWidth() + 2 * clearance, - SHAPE_ARC::DefaultAccuracyForPCB(), ERROR_OUTSIDE ); + polygonApproximationError, ERROR_OUTSIDE ); BOOST_REQUIRE_EQUAL( arcBuffer.OutlineCount(), 1 ); BOOST_CHECK_EQUAL( arcBuffer.HoleCount( 0 ), 0 ); @@ -793,7 +794,7 @@ BOOST_AUTO_TEST_CASE( CollideArcToPolygonApproximation ) BOOST_CHECK_EQUAL( zoneFill.Collide( &arc, clearance * 2, &actual, &location ), true ); - BOOST_CHECK( KI_TEST::IsWithin( actual, clearance, tol ) ); + BOOST_CHECK( KI_TEST::IsWithin( actual, clearance, polygonApproximationError ) ); }