Large rework of BEZIER_POLY
Add direct handling of quadratic beziers to save compute time and number of points. Update cubic interpolation to reduce number of points generated for a given smoothness Cache data on open and used cached data to avoid multiple re-calcs Remove minimum line length and number of segments and replace with standard max error level. Allows us to specify the tolerance of bezier interpolation
This commit is contained in:
+35
-34
@@ -352,6 +352,7 @@ void EDA_SHAPE::scale( double aScale )
|
||||
scalePt( m_end );
|
||||
scalePt( m_bezierC1 );
|
||||
scalePt( m_bezierC2 );
|
||||
RebuildBezierToSegmentsPointsList( m_stroke.GetWidth() / 2 );
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -488,12 +489,7 @@ void EDA_SHAPE::flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
|
||||
m_bezierC2.y = aCentre.y - ( m_bezierC2.y - aCentre.y );
|
||||
}
|
||||
|
||||
// Rebuild the poly points shape
|
||||
{
|
||||
std::vector<VECTOR2I> ctrlPoints = { m_start, m_bezierC1, m_bezierC2, m_end };
|
||||
BEZIER_POLY converter( ctrlPoints );
|
||||
converter.GetPoly( m_bezierPoints, m_stroke.GetWidth() );
|
||||
}
|
||||
RebuildBezierToSegmentsPointsList( m_stroke.GetWidth() / 2 );
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -503,7 +499,7 @@ void EDA_SHAPE::flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
|
||||
}
|
||||
|
||||
|
||||
void EDA_SHAPE::RebuildBezierToSegmentsPointsList( int aMinSegLen )
|
||||
void EDA_SHAPE::RebuildBezierToSegmentsPointsList( int aMaxError )
|
||||
{
|
||||
// Has meaning only for SHAPE_T::BEZIER
|
||||
if( m_shape != SHAPE_T::BEZIER )
|
||||
@@ -513,30 +509,18 @@ void EDA_SHAPE::RebuildBezierToSegmentsPointsList( int aMinSegLen )
|
||||
}
|
||||
|
||||
// Rebuild the m_BezierPoints vertex list that approximate the Bezier curve
|
||||
m_bezierPoints = buildBezierToSegmentsPointsList( aMinSegLen );
|
||||
|
||||
// Ensure last point respects aMinSegLen parameter
|
||||
if( m_bezierPoints.size() > 2 )
|
||||
{
|
||||
int idx = m_bezierPoints.size() - 1;
|
||||
|
||||
if( VECTOR2I( m_bezierPoints[idx] - m_bezierPoints[idx] - 1 ).EuclideanNorm() < aMinSegLen )
|
||||
{
|
||||
m_bezierPoints[idx - 1] = m_bezierPoints[idx];
|
||||
m_bezierPoints.pop_back();
|
||||
}
|
||||
}
|
||||
m_bezierPoints = buildBezierToSegmentsPointsList( aMaxError );
|
||||
}
|
||||
|
||||
|
||||
const std::vector<VECTOR2I> EDA_SHAPE::buildBezierToSegmentsPointsList( int aMinSegLen ) const
|
||||
const std::vector<VECTOR2I> EDA_SHAPE::buildBezierToSegmentsPointsList( int aMaxError ) const
|
||||
{
|
||||
std::vector<VECTOR2I> bezierPoints;
|
||||
|
||||
// Rebuild the m_BezierPoints vertex list that approximate the Bezier curve
|
||||
std::vector<VECTOR2I> ctrlPoints = { m_start, m_bezierC1, m_bezierC2, m_end };
|
||||
BEZIER_POLY converter( ctrlPoints );
|
||||
converter.GetPoly( bezierPoints, aMinSegLen );
|
||||
converter.GetPoly( bezierPoints, aMaxError );
|
||||
|
||||
return bezierPoints;
|
||||
}
|
||||
@@ -930,16 +914,25 @@ bool EDA_SHAPE::hitTest( const VECTOR2I& aPosition, int aAccuracy ) const
|
||||
}
|
||||
|
||||
case SHAPE_T::BEZIER:
|
||||
const_cast<EDA_SHAPE*>( this )->RebuildBezierToSegmentsPointsList( GetWidth() );
|
||||
{
|
||||
const std::vector<VECTOR2I>* pts = &m_bezierPoints;
|
||||
std::vector<VECTOR2I> updatedBezierPoints;
|
||||
|
||||
for( unsigned int i= 1; i < m_bezierPoints.size(); i++)
|
||||
if( m_bezierPoints.empty() )
|
||||
{
|
||||
if( TestSegmentHit( aPosition, m_bezierPoints[ i - 1], m_bezierPoints[i], maxdist ) )
|
||||
BEZIER_POLY converter( m_start, m_bezierC1, m_bezierC2, m_end );
|
||||
converter.GetPoly( updatedBezierPoints, aAccuracy / 2 );
|
||||
pts = &updatedBezierPoints;
|
||||
}
|
||||
|
||||
for( unsigned int i = 1; i < pts->size(); i++ )
|
||||
{
|
||||
if( TestSegmentHit( aPosition, ( *pts )[i - 1], ( *pts )[i], maxdist ) )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
case SHAPE_T::SEGMENT:
|
||||
return TestSegmentHit( aPosition, GetStart(), GetEnd(), maxdist );
|
||||
|
||||
@@ -1132,12 +1125,20 @@ bool EDA_SHAPE::hitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) co
|
||||
|
||||
// Account for the width of the line
|
||||
arect.Inflate( GetWidth() / 2 );
|
||||
unsigned count = m_bezierPoints.size();
|
||||
const std::vector<VECTOR2I>* pts = &m_bezierPoints;
|
||||
std::vector<VECTOR2I> updatedBezierPoints;
|
||||
|
||||
for( unsigned ii = 1; ii < count; ii++ )
|
||||
if( m_bezierPoints.empty() )
|
||||
{
|
||||
VECTOR2I vertex = m_bezierPoints[ii - 1];
|
||||
VECTOR2I vertexNext = m_bezierPoints[ii];
|
||||
BEZIER_POLY converter( m_start, m_bezierC1, m_bezierC2, m_end );
|
||||
converter.GetPoly( updatedBezierPoints, aAccuracy / 2 );
|
||||
pts = &updatedBezierPoints;
|
||||
}
|
||||
|
||||
for( unsigned ii = 1; ii < pts->size(); ii++ )
|
||||
{
|
||||
VECTOR2I vertex = ( *pts )[ii - 1];
|
||||
VECTOR2I vertexNext = ( *pts )[ii];
|
||||
|
||||
// Test if the point is within aRect
|
||||
if( arect.Contains( vertex ) )
|
||||
@@ -1278,7 +1279,7 @@ std::vector<SHAPE*> EDA_SHAPE::makeEffectiveShapes( bool aEdgeOnly, bool aLineCh
|
||||
|
||||
case SHAPE_T::BEZIER:
|
||||
{
|
||||
std::vector<VECTOR2I> bezierPoints = buildBezierToSegmentsPointsList( width );
|
||||
std::vector<VECTOR2I> bezierPoints = buildBezierToSegmentsPointsList( width / 2 );
|
||||
VECTOR2I start_pt = bezierPoints[0];
|
||||
|
||||
for( unsigned int jj = 1; jj < bezierPoints.size(); jj++ )
|
||||
@@ -1381,7 +1382,7 @@ void EDA_SHAPE::beginEdit( const VECTOR2I& aPosition )
|
||||
SetBezierC2( aPosition );
|
||||
m_editState = 1;
|
||||
|
||||
RebuildBezierToSegmentsPointsList( GetWidth() );
|
||||
RebuildBezierToSegmentsPointsList( GetWidth() / 2 );
|
||||
break;
|
||||
|
||||
case SHAPE_T::POLY:
|
||||
@@ -1463,7 +1464,7 @@ void EDA_SHAPE::calcEdit( const VECTOR2I& aPosition )
|
||||
case 3: SetBezierC2( aPosition ); break;
|
||||
}
|
||||
|
||||
RebuildBezierToSegmentsPointsList( GetWidth() );
|
||||
RebuildBezierToSegmentsPointsList( GetWidth() / 2 );
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1792,7 +1793,7 @@ void EDA_SHAPE::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, int aClearance
|
||||
std::vector<VECTOR2I> ctrlPts = { GetStart(), GetBezierC1(), GetBezierC2(), GetEnd() };
|
||||
BEZIER_POLY converter( ctrlPts );
|
||||
std::vector<VECTOR2I> poly;
|
||||
converter.GetPoly( poly, GetWidth() );
|
||||
converter.GetPoly( poly, aError );
|
||||
|
||||
for( unsigned ii = 1; ii < poly.size(); ii++ )
|
||||
TransformOvalToPolygon( aBuffer, poly[ii - 1], poly[ii], width, aError, aErrorLoc );
|
||||
|
||||
Reference in New Issue
Block a user