Pcbnew: Dimension: break out the knockout function

This avoids some fiddly repeated code, and will be useful in
other dimension types.
This commit is contained in:
John Beard 2024-10-30 18:49:52 +08:00
parent 0581423d50
commit ab6049ec0b
2 changed files with 87 additions and 105 deletions

View File

@ -44,6 +44,89 @@
static const EDA_ANGLE s_arrowAngle( 27.5, DEGREES_T ); static const EDA_ANGLE s_arrowAngle( 27.5, DEGREES_T );
/**
* Find the intersection between a given segment and polygon outline.
*
* @param aPoly is the polygon to collide.
* @param aSeg is the segment to collide.
* @param aStart if true will start from aSeg.A, otherwise aSeg.B.
* @return a point on aSeg that collides with aPoly closest to the start, if one exists.
*/
static OPT_VECTOR2I segPolyIntersection( const SHAPE_POLY_SET& aPoly, const SEG& aSeg,
bool aStart = true )
{
VECTOR2I start( aStart ? aSeg.A : aSeg.B );
VECTOR2I endpoint( aStart ? aSeg.B : aSeg.A );
if( aPoly.Contains( start ) )
return std::nullopt;
for( SHAPE_POLY_SET::CONST_SEGMENT_ITERATOR seg = aPoly.CIterateSegments(); seg; ++seg )
{
if( OPT_VECTOR2I intersection = ( *seg ).Intersect( aSeg ) )
{
if( ( *intersection - start ).SquaredEuclideanNorm()
< ( endpoint - start ).SquaredEuclideanNorm() )
endpoint = *intersection;
}
}
if( start == endpoint )
return std::nullopt;
return OPT_VECTOR2I( endpoint );
}
static OPT_VECTOR2I segCircleIntersection( CIRCLE& aCircle, SEG& aSeg, bool aStart = true )
{
VECTOR2I start( aStart ? aSeg.A : aSeg.B );
VECTOR2I endpoint( aStart ? aSeg.B : aSeg.A );
if( aCircle.Contains( start ) )
return std::nullopt;
std::vector<VECTOR2I> intersections = aCircle.Intersect( aSeg );
for( VECTOR2I& intersection : aCircle.Intersect( aSeg ) )
{
if( ( intersection - start ).SquaredEuclideanNorm()
< ( endpoint - start ).SquaredEuclideanNorm() )
endpoint = intersection;
}
if( start == endpoint )
return std::nullopt;
return OPT_VECTOR2I( endpoint );
}
/**
* Knockout a polygon from a segment. This function will add 0, 1 or 2 segments to the
* vector, depending on how the polygon intersects the segment.
*/
static void CollectKnockedOutSegments( const SHAPE_POLY_SET& aPoly, const SEG& aSeg,
std::vector<std::shared_ptr<SHAPE>>& aSegmentsAfterKnockout )
{
// Now we can draw 0, 1, or 2 crossbar lines depending on how the polygon collides
const bool containsA = aPoly.Contains( aSeg.A );
const bool containsB = aPoly.Contains( aSeg.B );
const OPT_VECTOR2I endpointA = segPolyIntersection( aPoly, aSeg );
const OPT_VECTOR2I endpointB = segPolyIntersection( aPoly, aSeg, false );
if( endpointA )
aSegmentsAfterKnockout.emplace_back( new SHAPE_SEGMENT( aSeg.A, *endpointA ) );
if( endpointB )
aSegmentsAfterKnockout.emplace_back( new SHAPE_SEGMENT( *endpointB, aSeg.B ) );
if( !containsA && !containsB && !endpointA && !endpointB )
aSegmentsAfterKnockout.emplace_back( new SHAPE_SEGMENT( aSeg ) );
}
PCB_DIMENSION_BASE::PCB_DIMENSION_BASE( BOARD_ITEM* aParent, KICAD_T aType ) : PCB_DIMENSION_BASE::PCB_DIMENSION_BASE( BOARD_ITEM* aParent, KICAD_T aType ) :
PCB_TEXT( aParent, aType ), PCB_TEXT( aParent, aType ),
m_overrideTextEnabled( false ), m_overrideTextEnabled( false ),
@ -574,56 +657,6 @@ const BOX2I PCB_DIMENSION_BASE::ViewBBox() const
} }
OPT_VECTOR2I PCB_DIMENSION_BASE::segPolyIntersection( const SHAPE_POLY_SET& aPoly, const SEG& aSeg,
bool aStart )
{
VECTOR2I start( aStart ? aSeg.A : aSeg.B );
VECTOR2I endpoint( aStart ? aSeg.B : aSeg.A );
if( aPoly.Contains( start ) )
return std::nullopt;
for( SHAPE_POLY_SET::CONST_SEGMENT_ITERATOR seg = aPoly.CIterateSegments(); seg; ++seg )
{
if( OPT_VECTOR2I intersection = ( *seg ).Intersect( aSeg ) )
{
if( ( *intersection - start ).SquaredEuclideanNorm() <
( endpoint - start ).SquaredEuclideanNorm() )
endpoint = *intersection;
}
}
if( start == endpoint )
return std::nullopt;
return OPT_VECTOR2I( endpoint );
}
OPT_VECTOR2I PCB_DIMENSION_BASE::segCircleIntersection( CIRCLE& aCircle, SEG& aSeg, bool aStart )
{
VECTOR2I start( aStart ? aSeg.A : aSeg.B );
VECTOR2I endpoint( aStart ? aSeg.B : aSeg.A );
if( aCircle.Contains( start ) )
return std::nullopt;
std::vector<VECTOR2I> intersections = aCircle.Intersect( aSeg );
for( VECTOR2I& intersection : aCircle.Intersect( aSeg ) )
{
if( ( intersection - start ).SquaredEuclideanNorm() <
( endpoint - start ).SquaredEuclideanNorm() )
endpoint = intersection;
}
if( start == endpoint )
return std::nullopt;
return OPT_VECTOR2I( endpoint );
}
void PCB_DIMENSION_BASE::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, void PCB_DIMENSION_BASE::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer,
int aClearance, int aError, ERROR_LOC aErrorLoc, int aClearance, int aError, ERROR_LOC aErrorLoc,
bool aIgnoreLineWidth ) const bool aIgnoreLineWidth ) const
@ -761,21 +794,7 @@ void PCB_DIM_ALIGNED::updateGeometry()
// The ideal crossbar, if the text doesn't collide // The ideal crossbar, if the text doesn't collide
SEG crossbar( m_crossBarStart, m_crossBarEnd ); SEG crossbar( m_crossBarStart, m_crossBarEnd );
// Now we can draw 0, 1, or 2 crossbar lines depending on how the polygon collides CollectKnockedOutSegments( polyBox, crossbar, m_shapes );
bool containsA = polyBox.Contains( crossbar.A );
bool containsB = polyBox.Contains( crossbar.B );
OPT_VECTOR2I endpointA = segPolyIntersection( polyBox, crossbar );
OPT_VECTOR2I endpointB = segPolyIntersection( polyBox, crossbar, false );
if( endpointA )
m_shapes.emplace_back( new SHAPE_SEGMENT( crossbar.A, *endpointA ) );
if( endpointB )
m_shapes.emplace_back( new SHAPE_SEGMENT( *endpointB, crossbar.B ) );
if( !containsA && !containsB && !endpointA && !endpointB )
m_shapes.emplace_back( new SHAPE_SEGMENT( crossbar ) );
// Add arrows // Add arrows
VECTOR2I arrowEndPos( m_arrowLength, 0 ); VECTOR2I arrowEndPos( m_arrowLength, 0 );
@ -789,7 +808,6 @@ void PCB_DIM_ALIGNED::updateGeometry()
m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarEnd, m_crossBarEnd - arrowEndNeg ) ); m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarEnd, m_crossBarEnd - arrowEndNeg ) );
} }
void PCB_DIM_ALIGNED::updateText() void PCB_DIM_ALIGNED::updateText()
{ {
VECTOR2I crossbarCenter( ( m_crossBarEnd - m_crossBarStart ) / 2 ); VECTOR2I crossbarCenter( ( m_crossBarEnd - m_crossBarStart ) / 2 );
@ -956,21 +974,7 @@ void PCB_DIM_ORTHOGONAL::updateGeometry()
// The ideal crossbar, if the text doesn't collide // The ideal crossbar, if the text doesn't collide
SEG crossbar( m_crossBarStart, m_crossBarEnd ); SEG crossbar( m_crossBarStart, m_crossBarEnd );
// Now we can draw 0, 1, or 2 crossbar lines depending on how the polygon collides CollectKnockedOutSegments( polyBox, crossbar, m_shapes );
bool containsA = polyBox.Contains( crossbar.A );
bool containsB = polyBox.Contains( crossbar.B );
OPT_VECTOR2I endpointA = segPolyIntersection( polyBox, crossbar );
OPT_VECTOR2I endpointB = segPolyIntersection( polyBox, crossbar, false );
if( endpointA )
m_shapes.emplace_back( new SHAPE_SEGMENT( crossbar.A, *endpointA ) );
if( endpointB )
m_shapes.emplace_back( new SHAPE_SEGMENT( *endpointB, crossbar.B ) );
if( !containsA && !containsB && !endpointA && !endpointB )
m_shapes.emplace_back( new SHAPE_SEGMENT( crossbar ) );
// Add arrows // Add arrows
EDA_ANGLE crossBarAngle( m_crossBarEnd - m_crossBarStart ); EDA_ANGLE crossBarAngle( m_crossBarEnd - m_crossBarStart );
@ -1328,16 +1332,8 @@ void PCB_DIM_RADIAL::updateGeometry()
SEG arrowSeg( m_end, m_end + radial ); SEG arrowSeg( m_end, m_end + radial );
SEG textSeg( arrowSeg.B, GetTextPos() ); SEG textSeg( arrowSeg.B, GetTextPos() );
OPT_VECTOR2I arrowSegEnd = segPolyIntersection( polyBox, arrowSeg ); CollectKnockedOutSegments( polyBox, arrowSeg, m_shapes );
OPT_VECTOR2I textSegEnd = segPolyIntersection( polyBox, textSeg ); CollectKnockedOutSegments( polyBox, textSeg, m_shapes );
if( arrowSegEnd )
arrowSeg.B = *arrowSegEnd;
if( textSegEnd )
textSeg.B = *textSegEnd;
m_shapes.emplace_back( new SHAPE_SEGMENT( arrowSeg ) );
// Add arrows // Add arrows
VECTOR2I arrowEndPos( m_arrowLength, 0 ); VECTOR2I arrowEndPos( m_arrowLength, 0 );
@ -1347,8 +1343,6 @@ void PCB_DIM_RADIAL::updateGeometry()
m_shapes.emplace_back( new SHAPE_SEGMENT( m_end, m_end + arrowEndPos ) ); m_shapes.emplace_back( new SHAPE_SEGMENT( m_end, m_end + arrowEndPos ) );
m_shapes.emplace_back( new SHAPE_SEGMENT( m_end, m_end + arrowEndNeg ) ); m_shapes.emplace_back( new SHAPE_SEGMENT( m_end, m_end + arrowEndNeg ) );
m_shapes.emplace_back( new SHAPE_SEGMENT( textSeg ) );
} }

View File

@ -313,18 +313,6 @@ protected:
template<typename ShapeType> template<typename ShapeType>
void addShape( const ShapeType& aShape ); void addShape( const ShapeType& aShape );
/**
* Find the intersection between a given segment and polygon outline.
*
* @param aPoly is the polygon to collide.
* @param aSeg is the segment to collide.
* @param aStart if true will start from aSeg.A, otherwise aSeg.B.
* @return a point on aSeg that collides with aPoly closest to the start, if one exists.
*/
static OPT_VECTOR2I segPolyIntersection( const SHAPE_POLY_SET& aPoly, const SEG& aSeg,
bool aStart = true );
static OPT_VECTOR2I segCircleIntersection( CIRCLE& aCircle, SEG& aSeg, bool aStart = true );
// Value format // Value format
bool m_overrideTextEnabled; ///< Manually specify the displayed measurement value bool m_overrideTextEnabled; ///< Manually specify the displayed measurement value
wxString m_valueString; ///< Displayed value when m_overrideValue = true wxString m_valueString; ///< Displayed value when m_overrideValue = true