pcbnew: Fix 45° snapping polygons

The constrained draw was constraining the polygon size to fit the
existing points rather than extending the existing points to fit the
user's intent.

This adds a 90° double-joint for the completion polygon that allows the
user to complete common constrained polygons visually based on the
preview with a double-click to finish.
This commit is contained in:
Seth Hillbrand 2019-10-24 08:01:14 -07:00
parent ea1c8525ce
commit bae50fab9f
2 changed files with 29 additions and 35 deletions

View File

@ -145,46 +145,49 @@ void POLYGON_GEOM_MANAGER::Reset()
void POLYGON_GEOM_MANAGER::updateLeaderPoints( const VECTOR2I& aEndPoint, LEADER_MODE aModifier ) void POLYGON_GEOM_MANAGER::updateLeaderPoints( const VECTOR2I& aEndPoint, LEADER_MODE aModifier )
{ {
wxCHECK( m_lockedPoints.PointCount() > 0, /*void*/ ); wxCHECK( m_lockedPoints.PointCount() > 0, /*void*/ );
const VECTOR2I& lastPt = m_lockedPoints.CLastPoint(); const VECTOR2I& last_pt = m_lockedPoints.CLastPoint();
if( m_leaderMode == LEADER_MODE::DEG45 || aModifier == LEADER_MODE::DEG45 ) if( m_leaderMode == LEADER_MODE::DEG45 || aModifier == LEADER_MODE::DEG45 )
{ {
const VECTOR2I lineVector( aEndPoint - lastPt ); const VECTOR2I line_vec( aEndPoint - last_pt );
// get a restricted 45/H/V line from the last fixed point to the cursor // get a restricted 45/H/V line from the last fixed point to the cursor
auto newEnd = lastPt + GetVectorSnapped45( lineVector ); auto new_end = last_pt + GetVectorSnapped45( line_vec );
OPT_VECTOR2I pt; OPT_VECTOR2I pt;
if( m_lockedPoints.SegmentCount() >0 ) if( m_lockedPoints.SegmentCount() > 1 )
{ {
SEG first( lastPt, newEnd ); const VECTOR2I& start_pt = m_lockedPoints.CPoint( 0 );
SEG test_seg = m_lockedPoints.CSegment( 0 ); VECTOR2I completed_vec( start_pt - new_end );
pt = first.IntersectLines( m_lockedPoints.CSegment( 0 ) ); if( completed_vec != GetVectorSnapped45( completed_vec ) )
int dist = pt ? ( aEndPoint - *pt ).EuclideanNorm() : std::numeric_limits<int>::max();
for( int i = 1; i < 8; i++ )
{ {
test_seg.B = ( test_seg.B - test_seg.A ).Rotate( M_PI_4 ) + test_seg.A; SEG v_first( new_end, VECTOR2I( new_end.x, start_pt.y ) );
auto pt2 = first.IntersectLines( test_seg ); SEG h_first( new_end, VECTOR2I( start_pt.x, new_end.y ) );
if( pt2 )
SHAPE_LINE_CHAIN::INTERSECTIONS intersections;
auto v_hits = m_lockedPoints.Intersect( v_first, intersections );
v_hits += m_lockedPoints.Intersect( SEG( v_first.B, start_pt ), intersections );
pt = v_first.B;
if( v_hits > 0 )
{ {
int dist2 = ( aEndPoint - *pt2 ).EuclideanNorm(); intersections.clear();
if( dist2 < dist ) auto h_hits = m_lockedPoints.Intersect( h_first, intersections );
{ h_hits += m_lockedPoints.Intersect( SEG( h_first.B, start_pt ), intersections );
dist = dist2;
pt = pt2; if( h_hits < v_hits )
} pt = h_first.B;
} }
} }
} }
m_leaderPts = SHAPE_LINE_CHAIN( lastPt, newEnd ); m_leaderPts = SHAPE_LINE_CHAIN( last_pt, new_end );
if( pt ) if( pt )
{ {
// This checks for backtracking from the point to intersection // This checks for backtracking from the point to intersection
if( SEG( lastPt, newEnd ).Collinear( SEG( newEnd, *pt ) ) ) if( SEG( last_pt, new_end ).Collinear( SEG( new_end, *pt ) ) )
m_leaderPts = SHAPE_LINE_CHAIN( lastPt, *pt ); m_leaderPts = SHAPE_LINE_CHAIN( last_pt, *pt );
else else
m_leaderPts.Append( *pt ); m_leaderPts.Append( *pt );
} }
@ -192,7 +195,7 @@ void POLYGON_GEOM_MANAGER::updateLeaderPoints( const VECTOR2I& aEndPoint, LEADER
else else
{ {
// direct segment // direct segment
m_leaderPts = SHAPE_LINE_CHAIN( lastPt, aEndPoint ); m_leaderPts = SHAPE_LINE_CHAIN( last_pt, aEndPoint );
} }
m_client.OnGeometryChange( *this ); m_client.OnGeometryChange( *this );

View File

@ -285,22 +285,13 @@ void ZONE_CREATE_HELPER::OnComplete( const POLYGON_GEOM_MANAGER& aMgr )
if( aMgr.GetLeaderMode() == POLYGON_GEOM_MANAGER::LEADER_MODE::DEG45 ) if( aMgr.GetLeaderMode() == POLYGON_GEOM_MANAGER::LEADER_MODE::DEG45 )
{ {
auto pts = aMgr.GetLeaderLinePoints(); auto pts = aMgr.GetLeaderLinePoints();
for( int i = 1; i < pts.PointCount(); i++ )
// The first 2 points of the leader are the continuation of the previous segment outline->Append( pts.CPoint( i ) );
// The third point is where it intersects with the extension from the 0-th segment
for( int i = 0; i < pts.PointCount(); i++ )
{
auto pt = pts.CPoint( i );
// If we have at least 2 points, then we need to check if the leader points
// already exist before re-adding them to the finalized polygon
if( pts.PointCount() < 2 || ( pts.CPoint( -1 ) != pt && pts.CPoint( -2 ) != pt ) )
outline->Append( pts.CPoint( i ) );
}
} }
outline->Outline( 0 ).SetClosed( true ); outline->Outline( 0 ).SetClosed( true );
outline->RemoveNullSegments(); outline->RemoveNullSegments();
outline->Simplify( SHAPE_POLY_SET::PM_FAST );
// hand the zone over to the committer // hand the zone over to the committer
commitZone( std::move( m_zone ) ); commitZone( std::move( m_zone ) );