Finish arc rework and push out to file formats.
This commit is contained in:
parent
b52529521e
commit
f9861b4a6c
|
@ -33,12 +33,13 @@
|
|||
#include <macros.h>
|
||||
#include <math/util.h> // for KiROUND
|
||||
#include <eda_shape.h>
|
||||
|
||||
#include <plotters/plotter.h>
|
||||
|
||||
EDA_SHAPE::EDA_SHAPE( SHAPE_T aType, int aLineWidth, FILL_T aFill ) :
|
||||
m_shape( aType ),
|
||||
m_width( aLineWidth ),
|
||||
m_fill( aFill )
|
||||
m_fill( aFill ),
|
||||
m_editState( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -432,38 +433,29 @@ void EDA_SHAPE::SetCenter( const wxPoint& aCenter )
|
|||
wxPoint EDA_SHAPE::GetArcMid() const
|
||||
{
|
||||
wxPoint mid = m_start;
|
||||
RotatePoint( &mid, m_arcCenter, -m_arcAngle / 2.0 );
|
||||
RotatePoint( &mid, m_arcCenter, -GetArcAngle() / 2.0 );
|
||||
return mid;
|
||||
}
|
||||
|
||||
|
||||
double EDA_SHAPE::GetArcAngleStart() const
|
||||
void EDA_SHAPE::CalcArcAngles( double& aStartAngle, double& aEndAngle ) const
|
||||
{
|
||||
wxPoint arcStart = GetStart();
|
||||
wxPoint center = getCenter();
|
||||
double angleStart = ArcTangente( arcStart.y - center.y, arcStart.x - center.x );
|
||||
VECTOR2D startRadial( GetStart() - getCenter() );
|
||||
VECTOR2D endRadial( GetEnd() - getCenter() );
|
||||
|
||||
// Normalize it to 0 ... 360 deg, to avoid discontinuity for angles near 180 deg
|
||||
// because 180 deg and -180 are very near angles when ampping betewwen -180 ... 180 deg.
|
||||
// and this is not easy to handle in calculations
|
||||
NORMALIZE_ANGLE_POS( angleStart );
|
||||
aStartAngle = 180.0 / M_PI * atan2( startRadial.y, startRadial.x );
|
||||
aEndAngle = 180.0 / M_PI * atan2( endRadial.y, endRadial.x );
|
||||
|
||||
return angleStart;
|
||||
}
|
||||
if( aEndAngle == aStartAngle )
|
||||
aEndAngle = aStartAngle + 360.0; // ring, not null
|
||||
|
||||
|
||||
double EDA_SHAPE::GetArcAngleEnd() const
|
||||
{
|
||||
wxPoint arcEnd = GetEnd();
|
||||
wxPoint center = getCenter();
|
||||
double angleStart = ArcTangente( arcEnd.y - center.y, arcEnd.x - center.x );
|
||||
|
||||
// Normalize it to 0 ... 360 deg, to avoid discontinuity for angles near 180 deg
|
||||
// because 180 deg and -180 are very near angles when ampping betewwen -180 ... 180 deg.
|
||||
// and this is not easy to handle in calculations
|
||||
NORMALIZE_ANGLE_POS( angleStart );
|
||||
|
||||
return angleStart;
|
||||
if( aStartAngle > aEndAngle )
|
||||
{
|
||||
if( aEndAngle < 0 )
|
||||
aEndAngle = NormalizeAngleDegrees( aEndAngle, 0.0, 360.0 );
|
||||
else
|
||||
aStartAngle = NormalizeAngleDegrees( aStartAngle, -360.0, 0.0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -495,34 +487,30 @@ void EDA_SHAPE::SetArcGeometry( const wxPoint& aStart, const wxPoint& aMid, cons
|
|||
m_start = aStart;
|
||||
m_end = aEnd;
|
||||
m_arcCenter = CalcArcCenter( aStart, aMid, aEnd );
|
||||
}
|
||||
|
||||
|
||||
double EDA_SHAPE::GetArcAngle() const
|
||||
{
|
||||
VECTOR2D startLine = m_start - m_arcCenter;
|
||||
VECTOR2D endLine = aEnd - m_arcCenter;
|
||||
bool clockwise = m_arcAngle > 0;
|
||||
VECTOR2D endLine = m_end - m_arcCenter;
|
||||
|
||||
m_arcAngle = RAD2DECIDEG( endLine.Angle() - startLine.Angle() );
|
||||
double arcAngle = RAD2DECIDEG( endLine.Angle() - startLine.Angle() );
|
||||
|
||||
if( clockwise && m_arcAngle < 0.0 )
|
||||
m_arcAngle += 3600.0;
|
||||
else if( !clockwise && m_arcAngle > 0.0 )
|
||||
m_arcAngle -= 3600.0;
|
||||
if( arcAngle < 0.0 )
|
||||
arcAngle += 3600.0;
|
||||
|
||||
return arcAngle;
|
||||
}
|
||||
|
||||
|
||||
void EDA_SHAPE::SetArcAngle( double aAngle )
|
||||
void EDA_SHAPE::SetArcAngleAndEnd( double aAngle, bool aCheckNegativeAngle )
|
||||
{
|
||||
// m_Angle must be >= -360 and <= +360 degrees
|
||||
m_arcAngle = NormalizeAngle360Max( aAngle );
|
||||
}
|
||||
|
||||
|
||||
void EDA_SHAPE::SetArcAngleAndEnd( double aAngle )
|
||||
{
|
||||
// m_Angle must be >= -360 and <= +360 degrees
|
||||
m_arcAngle = NormalizeAngle360Max( aAngle );
|
||||
|
||||
m_end = m_start;
|
||||
RotatePoint( &m_end, m_arcCenter, -m_arcAngle );
|
||||
RotatePoint( &m_end, m_arcCenter, -NormalizeAngle360Max( aAngle ) );
|
||||
|
||||
if( aCheckNegativeAngle && aAngle < 0 )
|
||||
std::swap( m_start, m_end );
|
||||
}
|
||||
|
||||
|
||||
|
@ -684,39 +672,28 @@ bool EDA_SHAPE::hitTest( const wxPoint& aPosition, int aAccuracy ) const
|
|||
case SHAPE_T::ARC:
|
||||
{
|
||||
wxPoint relPos = aPosition - getCenter();
|
||||
int radius = GetRadius();
|
||||
int dist = KiROUND( EuclideanNorm( relPos ) );
|
||||
int radius = GetRadius();
|
||||
int dist = KiROUND( EuclideanNorm( relPos ) );
|
||||
|
||||
if( abs( radius - dist ) <= maxdist )
|
||||
{
|
||||
// For arcs, the test point angle must be >= arc angle start
|
||||
// and <= arc angle end
|
||||
// However angle values > 360 deg are not easy to handle
|
||||
// so we calculate the relative angle between arc start point and teast point
|
||||
// this relative arc should be < arc angle if arc angle > 0 (CW arc)
|
||||
// and > arc angle if arc angle < 0 (CCW arc)
|
||||
double arc_angle_start = GetArcAngleStart(); // Always 0.0 ... 360 deg, in 0.1 deg
|
||||
double arc_swept_angle = GetArcAngleEnd() - arc_angle_start;
|
||||
double startAngle;
|
||||
double endAngle;
|
||||
CalcArcAngles( startAngle, endAngle );
|
||||
|
||||
double arc_hittest = ArcTangente( relPos.y, relPos.x );
|
||||
double relPosAngle = 180.0 / M_PI * atan2( relPos.y, relPos.x );
|
||||
|
||||
// Calculate relative angle between the starting point of the arc, and the test point
|
||||
arc_hittest -= arc_angle_start;
|
||||
if( relPosAngle >= startAngle && relPosAngle <= endAngle )
|
||||
return true;
|
||||
|
||||
// Normalise arc_hittest between 0 ... 360 deg
|
||||
NORMALIZE_ANGLE_POS( arc_hittest );
|
||||
relPosAngle = NormalizeAngleDegrees( relPosAngle, 0.0, 360.0 );
|
||||
|
||||
if( relPosAngle >= startAngle && relPosAngle <= endAngle )
|
||||
return true;
|
||||
|
||||
// Check angle: inside the arc angle when it is > 0 and outside the not drawn arc when
|
||||
// it is < 0
|
||||
if( arc_swept_angle >= 0.0 )
|
||||
return arc_hittest <= arc_swept_angle;
|
||||
else
|
||||
return arc_hittest >= ( 3600.0 + arc_swept_angle );
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
case SHAPE_T::BEZIER:
|
||||
|
@ -1012,16 +989,12 @@ void EDA_SHAPE::computeArcBBox( EDA_RECT& aBBox ) const
|
|||
quarter = 1;
|
||||
}
|
||||
|
||||
int radius = GetRadius();
|
||||
int angle = (int) GetArcAngleStart() % 900 + m_arcAngle;
|
||||
bool directionCW = ( m_arcAngle > 0 ); // Is the direction of arc clockwise?
|
||||
|
||||
// Make the angle positive, so we go clockwise and merge points belonging to the arc
|
||||
if( !directionCW )
|
||||
{
|
||||
angle = 900 - angle;
|
||||
quarter = ( quarter + 3 ) % 4; // -1 modulo arithmetic
|
||||
}
|
||||
int radius = GetRadius();
|
||||
VECTOR2I startRadial = GetStart() - getCenter();
|
||||
VECTOR2I endRadial = GetEnd() - getCenter();
|
||||
double angleStart = ArcTangente( startRadial.y, startRadial.x );
|
||||
double arcAngle = RAD2DECIDEG( endRadial.Angle() - startRadial.Angle() );
|
||||
int angle = (int) NormalizeAnglePos( angleStart ) % 900 + NormalizeAnglePos( arcAngle );
|
||||
|
||||
while( angle > 900 )
|
||||
{
|
||||
|
@ -1033,18 +1006,13 @@ void EDA_SHAPE::computeArcBBox( EDA_RECT& aBBox ) const
|
|||
case 3: aBBox.Merge( wxPoint( m_arcCenter.x + radius, m_arcCenter.y ) ); break; // right
|
||||
}
|
||||
|
||||
if( directionCW )
|
||||
++quarter;
|
||||
else
|
||||
quarter += 3; // -1 modulo arithmetic
|
||||
|
||||
quarter %= 4;
|
||||
++quarter %= 4;
|
||||
angle -= 900;
|
||||
}
|
||||
|
||||
aBBox.Inflate( m_width ); // Technically m_width / 2, but it doesn't hurt to have the
|
||||
// bounding box a bit large to account for drawing clearances,
|
||||
// etc.
|
||||
aBBox.Inflate( GetWidth() ); // Technically m_width / 2, but it doesn't hurt to have the
|
||||
// bounding box a bit large to account for drawing clearances,
|
||||
// etc.
|
||||
}
|
||||
|
||||
|
||||
|
@ -1065,7 +1033,7 @@ std::vector<SHAPE*> EDA_SHAPE::MakeEffectiveShapes() const
|
|||
switch( m_shape )
|
||||
{
|
||||
case SHAPE_T::ARC:
|
||||
effectiveShapes.emplace_back( new SHAPE_ARC( m_arcCenter, m_start, m_arcAngle / 10.0,
|
||||
effectiveShapes.emplace_back( new SHAPE_ARC( m_arcCenter, m_start, GetArcAngle() / 10.0,
|
||||
m_width ) );
|
||||
break;
|
||||
|
||||
|
@ -1193,6 +1161,221 @@ int EDA_SHAPE::GetPointCount() const
|
|||
}
|
||||
|
||||
|
||||
void EDA_SHAPE::beginEdit( const wxPoint& aPosition )
|
||||
{
|
||||
switch( GetShape() )
|
||||
{
|
||||
case SHAPE_T::SEGMENT:
|
||||
case SHAPE_T::CIRCLE:
|
||||
case SHAPE_T::RECT:
|
||||
SetStart( aPosition );
|
||||
SetEnd( aPosition );
|
||||
break;
|
||||
|
||||
case SHAPE_T::ARC:
|
||||
SetArcGeometry( aPosition, aPosition, aPosition );
|
||||
m_editState = 1;
|
||||
break;
|
||||
|
||||
case SHAPE_T::POLY:
|
||||
m_poly.NewOutline();
|
||||
m_poly.Outline( 0 ).SetClosed( false );
|
||||
|
||||
// Start and end of the first segment (co-located for now)
|
||||
m_poly.Outline( 0 ).Append( aPosition );
|
||||
m_poly.Outline( 0 ).Append( aPosition, true );
|
||||
break;
|
||||
|
||||
default:
|
||||
UNIMPLEMENTED_FOR( SHAPE_T_asString() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool EDA_SHAPE::continueEdit( const wxPoint& aPosition )
|
||||
{
|
||||
switch( GetShape() )
|
||||
{
|
||||
case SHAPE_T::ARC:
|
||||
case SHAPE_T::SEGMENT:
|
||||
case SHAPE_T::CIRCLE:
|
||||
case SHAPE_T::RECT:
|
||||
return false;
|
||||
|
||||
case SHAPE_T::POLY:
|
||||
{
|
||||
SHAPE_LINE_CHAIN& poly = m_poly.Outline( 0 );
|
||||
|
||||
// do not add zero-length segments
|
||||
if( poly.CPoint( poly.GetPointCount() - 2 ) != poly.CLastPoint() )
|
||||
poly.Append( aPosition, true );
|
||||
}
|
||||
return true;
|
||||
|
||||
default:
|
||||
UNIMPLEMENTED_FOR( SHAPE_T_asString() );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EDA_SHAPE::calcEdit( const wxPoint& aPosition )
|
||||
{
|
||||
#define sq( x ) pow( x, 2 )
|
||||
|
||||
switch( GetShape() )
|
||||
{
|
||||
case SHAPE_T::SEGMENT:
|
||||
case SHAPE_T::CIRCLE:
|
||||
case SHAPE_T::RECT:
|
||||
SetEnd( aPosition );
|
||||
break;
|
||||
|
||||
case SHAPE_T::ARC:
|
||||
{
|
||||
int radius = GetRadius();
|
||||
|
||||
// Edit state 0: drawing: place start
|
||||
// Edit state 1: drawing: place end (center calculated for 90-degree subtended angle)
|
||||
// Edit state 2: point edit: move start (center calculated for invariant subtended angle)
|
||||
// Edit state 3: point edit: move end (center calculated for invariant subtended angle)
|
||||
// Edit state 4: point edit: move center
|
||||
// Edit state 5: point edit: move arc-mid-point
|
||||
|
||||
switch( m_editState )
|
||||
{
|
||||
case 0:
|
||||
SetArcGeometry( aPosition, aPosition, aPosition );
|
||||
return;
|
||||
|
||||
case 1:
|
||||
m_end = aPosition;
|
||||
radius = KiROUND( sqrt( sq( GetLineLength( m_start, m_end ) ) / 2.0 ) );
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
{
|
||||
wxPoint v = m_start - m_end;
|
||||
double chordBefore = sq( v.x ) + sq( v.y );
|
||||
|
||||
if( m_editState == 2 )
|
||||
m_start = aPosition;
|
||||
else
|
||||
m_end = aPosition;
|
||||
|
||||
v = m_start - m_end;
|
||||
double chordAfter = sq( v.x ) + sq( v.y );
|
||||
double ratio = chordAfter / chordBefore;
|
||||
|
||||
if( ratio != 0 )
|
||||
{
|
||||
radius = std::max( int( sqrt( sq( radius ) * ratio ) ) + 1,
|
||||
int( sqrt( chordAfter ) / 2 ) + 1 );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
{
|
||||
double chordA = GetLineLength( m_start, aPosition );
|
||||
double chordB = GetLineLength( m_end, aPosition );
|
||||
radius = int( ( chordA + chordB ) / 2.0 ) + 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 5:
|
||||
SetArcGeometry( GetStart(), aPosition, GetEnd() );
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate center based on start, end, and radius
|
||||
//
|
||||
// Let 'l' be the length of the chord and 'm' the middle point of the chord
|
||||
double l = GetLineLength( m_start, m_end );
|
||||
wxPoint m = ( m_start + m_end ) / 2;
|
||||
|
||||
// Calculate 'd', the vector from the chord midpoint to the center
|
||||
wxPoint d;
|
||||
d.x = KiROUND( sqrt( sq( radius ) - sq( l/2 ) ) * ( m_start.y - m_end.y ) / l );
|
||||
d.y = KiROUND( sqrt( sq( radius ) - sq( l/2 ) ) * ( m_end.x - m_start.x ) / l );
|
||||
|
||||
wxPoint c1 = m + d;
|
||||
wxPoint c2 = m - d;
|
||||
|
||||
// Solution gives us 2 centers; we need to pick one:
|
||||
switch( m_editState )
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
// Keep center clockwise from chord while drawing
|
||||
wxPoint chordVector = m_end - m_start;
|
||||
double chordAngle = ArcTangente( chordVector.y, chordVector.x );
|
||||
NORMALIZE_ANGLE_POS( chordAngle );
|
||||
|
||||
wxPoint c1Test = c1;
|
||||
RotatePoint( &c1Test, m_start, -chordAngle );
|
||||
|
||||
m_arcCenter = c1Test.x > 0 ? c2 : c1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
// Pick the one closer to the old center
|
||||
m_arcCenter = GetLineLength( c1, m_arcCenter ) < GetLineLength( c2, m_arcCenter ) ? c1 : c2;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
// Pick the one closer to the mouse position
|
||||
m_arcCenter = GetLineLength( c1, aPosition ) < GetLineLength( c2, aPosition ) ? c1 : c2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SHAPE_T::POLY:
|
||||
m_poly.Outline( 0 ).SetPoint( m_poly.Outline( 0 ).GetPointCount() - 1, aPosition );
|
||||
break;
|
||||
|
||||
default:
|
||||
UNIMPLEMENTED_FOR( SHAPE_T_asString() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EDA_SHAPE::endEdit()
|
||||
{
|
||||
switch( GetShape() )
|
||||
{
|
||||
case SHAPE_T::ARC:
|
||||
case SHAPE_T::SEGMENT:
|
||||
case SHAPE_T::CIRCLE:
|
||||
case SHAPE_T::RECT:
|
||||
break;
|
||||
|
||||
case SHAPE_T::POLY:
|
||||
{
|
||||
SHAPE_LINE_CHAIN& poly = m_poly.Outline( 0 );
|
||||
|
||||
// do not include last point twice
|
||||
if( poly.GetPointCount() > 2 )
|
||||
{
|
||||
if( poly.CPoint( poly.GetPointCount() - 2 ) == poly.CLastPoint() )
|
||||
{
|
||||
poly.SetClosed( true );
|
||||
poly.Remove( poly.GetPointCount() - 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
UNIMPLEMENTED_FOR( SHAPE_T_asString() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EDA_SHAPE::SwapShape( EDA_SHAPE* aImage )
|
||||
{
|
||||
EDA_SHAPE* image = dynamic_cast<EDA_SHAPE*>( aImage );
|
||||
|
@ -1203,7 +1386,6 @@ void EDA_SHAPE::SwapShape( EDA_SHAPE* aImage )
|
|||
std::swap( m_end, image->m_end );
|
||||
std::swap( m_arcCenter, image->m_arcCenter );
|
||||
std::swap( m_shape, image->m_shape );
|
||||
std::swap( m_arcAngle, image->m_arcAngle );
|
||||
std::swap( m_bezierC1, image->m_bezierC1 );
|
||||
std::swap( m_bezierC2, image->m_bezierC2 );
|
||||
std::swap( m_bezierPoints, image->m_bezierPoints );
|
||||
|
@ -1242,4 +1424,44 @@ int EDA_SHAPE::Compare( const EDA_SHAPE* aOther ) const
|
|||
TEST( (int) m_fill, (int) aOther->m_fill );
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct EDA_SHAPE_DESC
|
||||
{
|
||||
EDA_SHAPE_DESC()
|
||||
{
|
||||
ENUM_MAP<SHAPE_T>::Instance()
|
||||
.Map( SHAPE_T::SEGMENT, _HKI( "Segment" ) )
|
||||
.Map( SHAPE_T::RECT, _HKI( "Rectangle" ) )
|
||||
.Map( SHAPE_T::ARC, _HKI( "Arc" ) )
|
||||
.Map( SHAPE_T::CIRCLE, _HKI( "Circle" ) )
|
||||
.Map( SHAPE_T::POLY, _HKI( "Polygon" ) )
|
||||
.Map( SHAPE_T::BEZIER, _HKI( "Bezier" ) );
|
||||
ENUM_MAP<PLOT_DASH_TYPE>::Instance()
|
||||
.Map( PLOT_DASH_TYPE::DEFAULT, _HKI( "Default" ) )
|
||||
.Map( PLOT_DASH_TYPE::SOLID, _HKI( "Solid" ) )
|
||||
.Map( PLOT_DASH_TYPE::DASH, _HKI( "Dashed" ) )
|
||||
.Map( PLOT_DASH_TYPE::DOT, _HKI( "Dotted" ) )
|
||||
.Map( PLOT_DASH_TYPE::DASHDOT, _HKI( "Dash-Dot" ) );
|
||||
|
||||
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
|
||||
REGISTER_TYPE( EDA_SHAPE );
|
||||
propMgr.AddProperty( new PROPERTY_ENUM<EDA_SHAPE, SHAPE_T>( _HKI( "Shape" ),
|
||||
&EDA_SHAPE::SetShape, &EDA_SHAPE::GetShape ) );
|
||||
propMgr.AddProperty( new PROPERTY<EDA_SHAPE, int>( _HKI( "Start X" ),
|
||||
&EDA_SHAPE::SetStartX, &EDA_SHAPE::GetStartX ) );
|
||||
propMgr.AddProperty( new PROPERTY<EDA_SHAPE, int>( _HKI( "Start Y" ),
|
||||
&EDA_SHAPE::SetStartY, &EDA_SHAPE::GetStartY ) );
|
||||
propMgr.AddProperty( new PROPERTY<EDA_SHAPE, int>( _HKI( "End X" ),
|
||||
&EDA_SHAPE::SetEndX, &EDA_SHAPE::GetEndX ) );
|
||||
propMgr.AddProperty( new PROPERTY<EDA_SHAPE, int>( _HKI( "End Y" ),
|
||||
&EDA_SHAPE::SetEndY, &EDA_SHAPE::GetEndY ) );
|
||||
// TODO: m_arcCenter, m_bezierC1, m_bezierC2, m_poly
|
||||
propMgr.AddProperty( new PROPERTY<EDA_SHAPE, int>( _HKI( "Line Width" ),
|
||||
&EDA_SHAPE::SetWidth, &EDA_SHAPE::GetWidth ) );
|
||||
}
|
||||
} _EDA_SHAPE_DESC;
|
||||
|
||||
ENUM_TO_WXANY( SHAPE_T )
|
||||
ENUM_TO_WXANY( PLOT_DASH_TYPE )
|
||||
|
|
|
@ -35,8 +35,7 @@ const int fill_tab[3] = { 'N', 'F', 'f' };
|
|||
LIB_ITEM::LIB_ITEM( KICAD_T aType, LIB_SYMBOL* aSymbol, int aUnit, int aConvert ) :
|
||||
EDA_ITEM( aSymbol, aType ),
|
||||
m_unit( aUnit ),
|
||||
m_convert( aConvert ),
|
||||
m_editState( 0 )
|
||||
m_convert( aConvert )
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -126,12 +126,6 @@ public:
|
|||
*/
|
||||
virtual void CalcEdit( const wxPoint& aPosition ) {}
|
||||
|
||||
/**
|
||||
* For use by more complex editing routines that need to indicate what phase they are in.
|
||||
* @param aState
|
||||
*/
|
||||
virtual void SetEditState( int aState ) { m_editState = aState; }
|
||||
|
||||
/**
|
||||
* Draw an item
|
||||
*
|
||||
|
@ -320,8 +314,6 @@ protected:
|
|||
* body styles. This is typially used for representing DeMorgan variants in KiCad.
|
||||
*/
|
||||
int m_convert;
|
||||
|
||||
int m_editState;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -254,7 +254,9 @@ void LIB_SHAPE::print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset,
|
|||
c = aTransform.TransformCoordinate( getCenter() ) + aOffset;
|
||||
|
||||
CalcArcAngles( t1, t2 );
|
||||
aTransform.MapAngles( &t1, &t2 );
|
||||
|
||||
if( t1 > t2 )
|
||||
aTransform.MapAngles( &t1, &t2 );
|
||||
}
|
||||
|
||||
if( forceNoFill || GetFillType() == FILL_T::NO_FILL )
|
||||
|
@ -264,7 +266,7 @@ void LIB_SHAPE::print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset,
|
|||
switch( GetShape() )
|
||||
{
|
||||
case SHAPE_T::ARC:
|
||||
GRArc1( nullptr, DC, pt2.x, pt2.y, pt1.x, pt1.y, c.x, c.y, penWidth, color );
|
||||
GRArc1( nullptr, DC, pt1.x, pt1.y, pt2.x, pt2.y, c.x, c.y, penWidth, color );
|
||||
break;
|
||||
|
||||
case SHAPE_T::CIRCLE:
|
||||
|
@ -295,7 +297,7 @@ void LIB_SHAPE::print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset,
|
|||
switch( GetShape() )
|
||||
{
|
||||
case SHAPE_T::ARC:
|
||||
GRFilledArc( nullptr, DC, c.x, c.y, t1, t2, GetRadius(), penWidth, color, color );
|
||||
GRFilledArc( nullptr, DC, c.x, c.y, -t2, -t1, GetRadius(), penWidth, color, color );
|
||||
break;
|
||||
|
||||
case SHAPE_T::CIRCLE:
|
||||
|
@ -333,7 +335,7 @@ const EDA_RECT LIB_SHAPE::GetBoundingBox() const
|
|||
}
|
||||
|
||||
|
||||
void LIB_SHAPE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, MSG_PANEL_ITEMS& aList )
|
||||
void LIB_SHAPE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
|
||||
{
|
||||
LIB_ITEM::GetMsgPanelInfo( aFrame, aList );
|
||||
|
||||
|
@ -390,225 +392,6 @@ BITMAPS LIB_SHAPE::GetMenuImage() const
|
|||
}
|
||||
|
||||
|
||||
void LIB_SHAPE::BeginEdit( const wxPoint& aPosition )
|
||||
{
|
||||
switch( GetShape() )
|
||||
{
|
||||
case SHAPE_T::SEGMENT:
|
||||
case SHAPE_T::CIRCLE:
|
||||
case SHAPE_T::RECT:
|
||||
SetPosition( aPosition );
|
||||
SetEnd( aPosition );
|
||||
break;
|
||||
|
||||
case SHAPE_T::ARC:
|
||||
SetArcGeometry( aPosition, aPosition, aPosition );
|
||||
SetEditState( 1 );
|
||||
break;
|
||||
|
||||
case SHAPE_T::POLY:
|
||||
m_poly.NewOutline();
|
||||
m_poly.Outline( 0 ).SetClosed( false );
|
||||
|
||||
// Start and end of the first segment (co-located for now)
|
||||
m_poly.Outline( 0 ).Append( aPosition );
|
||||
m_poly.Outline( 0 ).Append( aPosition, true );
|
||||
break;
|
||||
|
||||
default:
|
||||
UNIMPLEMENTED_FOR( SHAPE_T_asString() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool LIB_SHAPE::ContinueEdit( const wxPoint& aPosition )
|
||||
{
|
||||
switch( GetShape() )
|
||||
{
|
||||
case SHAPE_T::ARC:
|
||||
case SHAPE_T::SEGMENT:
|
||||
case SHAPE_T::CIRCLE:
|
||||
case SHAPE_T::RECT:
|
||||
return false;
|
||||
|
||||
case SHAPE_T::POLY:
|
||||
{
|
||||
SHAPE_LINE_CHAIN& poly = m_poly.Outline( 0 );
|
||||
|
||||
// do not add zero-length segments
|
||||
if( poly.CPoint( poly.GetPointCount() - 2 ) != poly.CLastPoint() )
|
||||
poly.Append( aPosition, true );
|
||||
}
|
||||
return true;
|
||||
|
||||
default:
|
||||
UNIMPLEMENTED_FOR( SHAPE_T_asString() );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LIB_SHAPE::CalcEdit( const wxPoint& aPosition )
|
||||
{
|
||||
#define sq( x ) pow( x, 2 )
|
||||
|
||||
switch( GetShape() )
|
||||
{
|
||||
case SHAPE_T::SEGMENT:
|
||||
case SHAPE_T::CIRCLE:
|
||||
case SHAPE_T::RECT:
|
||||
SetEnd( aPosition );
|
||||
break;
|
||||
|
||||
case SHAPE_T::ARC:
|
||||
{
|
||||
int radius = GetRadius();
|
||||
|
||||
// Edit state 0: drawing: place start
|
||||
// Edit state 1: drawing: place end (center calculated for 90-degree subtended angle)
|
||||
// Edit state 2: point edit: move start (center calculated for invariant subtended angle)
|
||||
// Edit state 3: point edit: move end (center calculated for invariant subtended angle)
|
||||
// Edit state 4: point edit: move center
|
||||
// Edit state 5: point edit: move arc-mid-point
|
||||
|
||||
switch( m_editState )
|
||||
{
|
||||
case 0:
|
||||
SetArcGeometry( aPosition, aPosition, aPosition );
|
||||
return;
|
||||
|
||||
case 1:
|
||||
m_end = aPosition;
|
||||
radius = KiROUND( sqrt( sq( GetLineLength( m_start, m_end ) ) / 2.0 ) );
|
||||
break;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
{
|
||||
wxPoint v = m_start - m_end;
|
||||
double chordBefore = sq( v.x ) + sq( v.y );
|
||||
|
||||
if( m_editState == 2 )
|
||||
m_start = aPosition;
|
||||
else
|
||||
m_end = aPosition;
|
||||
|
||||
v = m_start - m_end;
|
||||
double chordAfter = sq( v.x ) + sq( v.y );
|
||||
double ratio = chordAfter / chordBefore;
|
||||
|
||||
if( ratio != 0 )
|
||||
{
|
||||
radius = std::max( int( sqrt( sq( radius ) * ratio ) ) + 1,
|
||||
int( sqrt( chordAfter ) / 2 ) + 1 );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
{
|
||||
double chordA = GetLineLength( m_start, aPosition );
|
||||
double chordB = GetLineLength( m_end, aPosition );
|
||||
radius = int( ( chordA + chordB ) / 2.0 ) + 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 5:
|
||||
SetArcGeometry( GetStart(), aPosition, GetEnd() );
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate center based on start, end, and radius
|
||||
//
|
||||
// Let 'l' be the length of the chord and 'm' the middle point of the chord
|
||||
double l = GetLineLength( m_start, m_end );
|
||||
wxPoint m = ( m_start + m_end ) / 2;
|
||||
|
||||
// Calculate 'd', the vector from the chord midpoint to the center
|
||||
wxPoint d;
|
||||
d.x = KiROUND( sqrt( sq( radius ) - sq( l/2 ) ) * ( m_start.y - m_end.y ) / l );
|
||||
d.y = KiROUND( sqrt( sq( radius ) - sq( l/2 ) ) * ( m_end.x - m_start.x ) / l );
|
||||
|
||||
wxPoint c1 = m + d;
|
||||
wxPoint c2 = m - d;
|
||||
|
||||
// Solution gives us 2 centers; we need to pick one:
|
||||
switch( m_editState )
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
// Keep center clockwise from chord while drawing
|
||||
wxPoint chordVector = m_end - m_start;
|
||||
double chordAngle = ArcTangente( chordVector.y, chordVector.x );
|
||||
NORMALIZE_ANGLE_POS( chordAngle );
|
||||
|
||||
wxPoint c1Test = c1;
|
||||
RotatePoint( &c1Test, m_start, -chordAngle );
|
||||
|
||||
m_arcCenter = c1Test.x > 0 ? c2 : c1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
// Pick the one closer to the old center
|
||||
m_arcCenter = GetLineLength( c1, m_arcCenter ) < GetLineLength( c2, m_arcCenter ) ? c1 : c2;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
// Pick the one closer to the mouse position
|
||||
m_arcCenter = GetLineLength( c1, aPosition ) < GetLineLength( c2, aPosition ) ? c1 : c2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SHAPE_T::POLY:
|
||||
m_poly.Outline( 0 ).SetPoint( m_poly.Outline( 0 ).GetPointCount() - 1, aPosition );
|
||||
break;
|
||||
|
||||
default:
|
||||
UNIMPLEMENTED_FOR( SHAPE_T_asString() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LIB_SHAPE::EndEdit()
|
||||
{
|
||||
switch( GetShape() )
|
||||
{
|
||||
case SHAPE_T::ARC:
|
||||
case SHAPE_T::SEGMENT:
|
||||
case SHAPE_T::CIRCLE:
|
||||
case SHAPE_T::RECT:
|
||||
break;
|
||||
|
||||
case SHAPE_T::POLY:
|
||||
{
|
||||
SHAPE_LINE_CHAIN& poly = m_poly.Outline( 0 );
|
||||
|
||||
if( poly.GetPointCount() > 2 )
|
||||
{
|
||||
if( poly.CPoint( poly.GetPointCount() - 2 ) == poly.CLastPoint() )
|
||||
{
|
||||
poly.SetClosed( true );
|
||||
poly.Remove( poly.GetPointCount() - 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
poly.SetClosed( false );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
wxFAIL_MSG( "LIB_SHAPE::EndEdit not implemented for " + SHAPE_T_asString() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LIB_SHAPE::AddPoint( const wxPoint& aPosition )
|
||||
{
|
||||
if( GetShape() == SHAPE_T::POLY )
|
||||
|
@ -625,30 +408,6 @@ void LIB_SHAPE::AddPoint( const wxPoint& aPosition )
|
|||
}
|
||||
|
||||
|
||||
double LIB_SHAPE::GetArcAngleStart() const
|
||||
{
|
||||
int startAngle, endAngle;
|
||||
CalcArcAngles( startAngle, endAngle );
|
||||
|
||||
if( startAngle > endAngle )
|
||||
TRANSFORM().MapAngles( &startAngle, &endAngle );
|
||||
|
||||
return startAngle;
|
||||
}
|
||||
|
||||
|
||||
double LIB_SHAPE::GetArcAngleEnd() const
|
||||
{
|
||||
int startAngle, endAngle;
|
||||
CalcArcAngles( startAngle, endAngle );
|
||||
|
||||
if( startAngle > endAngle )
|
||||
TRANSFORM().MapAngles( &startAngle, &endAngle );
|
||||
|
||||
return endAngle;
|
||||
}
|
||||
|
||||
|
||||
void LIB_SHAPE::CalcArcAngles( int& aStartAngle, int& aEndAngle ) const
|
||||
{
|
||||
wxPoint centerStartVector = GetStart() - GetCenter();
|
||||
|
|
|
@ -71,10 +71,11 @@ public:
|
|||
|
||||
void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
|
||||
|
||||
void BeginEdit( const wxPoint& aStartPoint ) override;
|
||||
bool ContinueEdit( const wxPoint& aPosition ) override;
|
||||
void CalcEdit( const wxPoint& aPosition ) override;
|
||||
void EndEdit() override;
|
||||
void BeginEdit( const wxPoint& aStartPoint ) override { beginEdit( aStartPoint ); }
|
||||
bool ContinueEdit( const wxPoint& aPosition ) override { return continueEdit( aPosition ); }
|
||||
void CalcEdit( const wxPoint& aPosition ) override { calcEdit( aPosition ); }
|
||||
void EndEdit() override { endEdit(); }
|
||||
void SetEditState( int aState ) { setEditState( aState ); }
|
||||
|
||||
void AddPoint( const wxPoint& aPosition );
|
||||
|
||||
|
@ -82,13 +83,11 @@ public:
|
|||
|
||||
void MoveTo( const wxPoint& aPosition ) override;
|
||||
|
||||
wxPoint GetPosition() const override { return getPosition(); }
|
||||
wxPoint GetPosition() const override { return getPosition(); }
|
||||
void SetPosition( const wxPoint& aPosition ) override { setPosition( aPosition ); }
|
||||
|
||||
wxPoint GetCenter() const { return getCenter(); }
|
||||
|
||||
double GetArcAngleStart() const override;
|
||||
double GetArcAngleEnd() const override;
|
||||
void CalcArcAngles( int& aStartAngle, int& aEndAngle ) const;
|
||||
|
||||
void MirrorHorizontal( const wxPoint& aCenter ) override;
|
||||
|
|
|
@ -39,7 +39,8 @@
|
|||
//#define SEXPR_SYMBOL_LIB_FILE_VERSION 20200827 // Remove host tag.
|
||||
//#define SEXPR_SYMBOL_LIB_FILE_VERSION 20200908 // Add include in BOM and on board support.
|
||||
//#define SEXPR_SYMBOL_LIB_FILE_VERSION 20201005 // Separate ki_fp_filters by spaces.
|
||||
#define SEXPR_SYMBOL_LIB_FILE_VERSION 20210619 // Change pin overbar syntax from `~...~` to `~{...}`.
|
||||
//#define SEXPR_SYMBOL_LIB_FILE_VERSION 20210619 // Change pin overbar syntax from `~...~` to `~{...}`.
|
||||
#define SEXPR_SYMBOL_LIB_FILE_VERSION 20211014 // Arc formatting.
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -1018,7 +1018,6 @@ LIB_SHAPE* SCH_SEXPR_PARSER::parseArc()
|
|||
}
|
||||
else if( hasAngles )
|
||||
{
|
||||
arc->SetCenter( pos );
|
||||
/**
|
||||
* This accounts for an oddity in the old library format, where the symbol is overdefined.
|
||||
* The previous draw (based on wxwidgets) used start point and end point and always drew
|
||||
|
@ -1032,9 +1031,12 @@ LIB_SHAPE* SCH_SEXPR_PARSER::parseArc()
|
|||
arc->SetStart( arc->GetEnd() );
|
||||
arc->SetEnd( temp );
|
||||
}
|
||||
arc->SetCenter( pos );
|
||||
}
|
||||
else
|
||||
{
|
||||
wxFAIL_MSG( "Setting arc without either midpoint or angles not implemented." );
|
||||
}
|
||||
|
||||
return arc.release();
|
||||
}
|
||||
|
|
|
@ -73,11 +73,12 @@ static const char* emptyString = "";
|
|||
/**
|
||||
* Fill token formatting helper.
|
||||
*/
|
||||
static void formatFill( const LIB_SHAPE* aItem, OUTPUTFORMATTER& aFormatter, int aNestLevel )
|
||||
static void formatFill( OUTPUTFORMATTER* aFormatter, int aNestLevel, FILL_T aFillMode,
|
||||
const COLOR4D& aFillColor )
|
||||
{
|
||||
const char* fillType;
|
||||
|
||||
switch( aItem->GetFillType() )
|
||||
switch( aFillMode )
|
||||
{
|
||||
default:
|
||||
case FILL_T::NO_FILL: fillType = "none"; break;
|
||||
|
@ -85,7 +86,7 @@ static void formatFill( const LIB_SHAPE* aItem, OUTPUTFORMATTER& aFormatter, int
|
|||
case FILL_T::FILLED_WITH_BG_BODYCOLOR: fillType = "background"; break;
|
||||
}
|
||||
|
||||
aFormatter.Print( aNestLevel, "(fill (type %s))", fillType );
|
||||
aFormatter->Print( aNestLevel, "(fill (type %s))", fillType );
|
||||
}
|
||||
|
||||
|
||||
|
@ -211,10 +212,10 @@ static double getSheetPinAngle( SHEET_SIDE aSide )
|
|||
{
|
||||
case SHEET_SIDE::UNDEFINED:
|
||||
case SHEET_SIDE::LEFT: retv = 180.0; break;
|
||||
case SHEET_SIDE::RIGHT: retv = 0.0; break;
|
||||
case SHEET_SIDE::TOP: retv = 90.0; break;
|
||||
case SHEET_SIDE::RIGHT: retv = 0.0; break;
|
||||
case SHEET_SIDE::TOP: retv = 90.0; break;
|
||||
case SHEET_SIDE::BOTTOM: retv = 270.0; break;
|
||||
default: wxFAIL; retv = 0.0; break;
|
||||
default: wxFAIL; retv = 0.0; break;
|
||||
}
|
||||
|
||||
return retv;
|
||||
|
@ -278,6 +279,156 @@ static void formatStroke( OUTPUTFORMATTER* aFormatter, int aNestLevel,
|
|||
}
|
||||
|
||||
|
||||
static void formatArc( OUTPUTFORMATTER* aFormatter, int aNestLevel, EDA_SHAPE* aArc, int x1, int x2,
|
||||
const STROKE_PARAMS& aStroke, FILL_T aFillMode, const COLOR4D& aFillColor,
|
||||
KIID aUuid = niluuid )
|
||||
{
|
||||
if( x1 > 1800 )
|
||||
x1 -= 3600;
|
||||
|
||||
if( x2 > 1800 )
|
||||
x2 -= 3600;
|
||||
|
||||
aFormatter->Print( aNestLevel, "(arc (start %s) (mid %s) (end %s)\n",
|
||||
FormatInternalUnits( aArc->GetStart() ).c_str(),
|
||||
FormatInternalUnits( aArc->GetArcMid() ).c_str(),
|
||||
FormatInternalUnits( aArc->GetEnd() ).c_str() );
|
||||
|
||||
formatStroke( aFormatter, aNestLevel + 1, aStroke );
|
||||
aFormatter->Print( 0, "\n" );
|
||||
formatFill( aFormatter, aNestLevel + 1, aFillMode, aFillColor );
|
||||
aFormatter->Print( 0, "\n" );
|
||||
|
||||
if( aUuid != niluuid )
|
||||
aFormatter->Print( aNestLevel + 1, "(uuid %s)\n", TO_UTF8( aUuid.AsString() ) );
|
||||
|
||||
aFormatter->Print( aNestLevel, ")\n" );
|
||||
}
|
||||
|
||||
|
||||
static void formatCircle( OUTPUTFORMATTER* aFormatter, int aNestLevel, EDA_SHAPE* aCircle,
|
||||
const STROKE_PARAMS& aStroke, FILL_T aFillMode, const COLOR4D& aFillColor,
|
||||
KIID aUuid = niluuid )
|
||||
{
|
||||
aFormatter->Print( aNestLevel, "(circle (center %s %s) (radius %s) (stroke (width %s)) ",
|
||||
FormatInternalUnits( aCircle->GetStart().x ).c_str(),
|
||||
FormatInternalUnits( aCircle->GetStart().y ).c_str(),
|
||||
FormatInternalUnits( aCircle->GetRadius() ).c_str(),
|
||||
FormatInternalUnits( aCircle->GetWidth() ).c_str() );
|
||||
|
||||
formatStroke( aFormatter, aNestLevel + 1, aStroke );
|
||||
aFormatter->Print( 0, "\n" );
|
||||
formatFill( aFormatter, aNestLevel + 1, aFillMode, aFillColor );
|
||||
aFormatter->Print( 0, "\n" );
|
||||
|
||||
if( aUuid != niluuid )
|
||||
aFormatter->Print( aNestLevel + 1, "(uuid %s)\n", TO_UTF8( aUuid.AsString() ) );
|
||||
|
||||
aFormatter->Print( aNestLevel, ")\n" );
|
||||
}
|
||||
|
||||
|
||||
static void formatRect( OUTPUTFORMATTER* aFormatter, int aNestLevel, EDA_SHAPE* aRect,
|
||||
const STROKE_PARAMS& aStroke, FILL_T aFillMode, const COLOR4D& aFillColor,
|
||||
KIID aUuid = niluuid )
|
||||
{
|
||||
aFormatter->Print( aNestLevel, "(rectangle (start %s %s) (end %s %s)\n",
|
||||
FormatInternalUnits( aRect->GetStart().x ).c_str(),
|
||||
FormatInternalUnits( aRect->GetStart().y ).c_str(),
|
||||
FormatInternalUnits( aRect->GetEnd().x ).c_str(),
|
||||
FormatInternalUnits( aRect->GetEnd().y ).c_str() );
|
||||
formatStroke( aFormatter, aNestLevel + 1, aStroke );
|
||||
aFormatter->Print( 0, "\n" );
|
||||
formatFill( aFormatter, aNestLevel + 1, aFillMode, aFillColor );
|
||||
aFormatter->Print( 0, "\n" );
|
||||
|
||||
if( aUuid != niluuid )
|
||||
aFormatter->Print( aNestLevel + 1, "(uuid %s)\n", TO_UTF8( aUuid.AsString() ) );
|
||||
|
||||
aFormatter->Print( aNestLevel, ")\n" );
|
||||
}
|
||||
|
||||
|
||||
static void formatBezier( OUTPUTFORMATTER* aFormatter, int aNestLevel, EDA_SHAPE* aBezier,
|
||||
const STROKE_PARAMS& aStroke, FILL_T aFillMode, const COLOR4D& aFillColor,
|
||||
KIID aUuid = niluuid )
|
||||
{
|
||||
aFormatter->Print( aNestLevel, "(bezier (pts " );
|
||||
|
||||
for( const wxPoint& pt : { aBezier->GetStart(), aBezier->GetBezierC1(),
|
||||
aBezier->GetBezierC2(), aBezier->GetEnd() } )
|
||||
{
|
||||
aFormatter->Print( 0, " (xy %s %s)",
|
||||
FormatInternalUnits( pt.x ).c_str(),
|
||||
FormatInternalUnits( pt.y ).c_str() );
|
||||
}
|
||||
|
||||
aFormatter->Print( 0, ")\n" ); // Closes pts token on same line.
|
||||
|
||||
formatStroke( aFormatter, aNestLevel + 1, aStroke );
|
||||
aFormatter->Print( 0, "\n" );
|
||||
formatFill( aFormatter, aNestLevel + 1, aFillMode, aFillColor );
|
||||
aFormatter->Print( 0, "\n" );
|
||||
|
||||
if( aUuid != niluuid )
|
||||
aFormatter->Print( aNestLevel + 1, "(uuid %s)\n", TO_UTF8( aUuid.AsString() ) );
|
||||
|
||||
aFormatter->Print( aNestLevel, ")\n" );
|
||||
}
|
||||
|
||||
|
||||
static void formatPoly( OUTPUTFORMATTER* aFormatter, int aNestLevel, EDA_SHAPE* aPolyLine,
|
||||
const STROKE_PARAMS& aStroke, FILL_T aFillMode, const COLOR4D& aFillColor,
|
||||
KIID aUuid = niluuid )
|
||||
{
|
||||
int newLine = 0;
|
||||
int lineCount = 1;
|
||||
aFormatter->Print( aNestLevel, "(polyline\n" );
|
||||
aFormatter->Print( aNestLevel + 1, "(pts" );
|
||||
|
||||
for( const VECTOR2I& pt : aPolyLine->GetPolyShape().Outline( 0 ).CPoints() )
|
||||
{
|
||||
if( newLine == 4 || !ADVANCED_CFG::GetCfg().m_CompactSave )
|
||||
{
|
||||
aFormatter->Print( 0, "\n" );
|
||||
aFormatter->Print( aNestLevel + 2, "(xy %s %s)",
|
||||
FormatInternalUnits( pt.x ).c_str(),
|
||||
FormatInternalUnits( pt.y ).c_str() );
|
||||
newLine = 0;
|
||||
lineCount += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
aFormatter->Print( 0, " (xy %s %s)",
|
||||
FormatInternalUnits( pt.x ).c_str(),
|
||||
FormatInternalUnits( pt.y ).c_str() );
|
||||
}
|
||||
|
||||
newLine += 1;
|
||||
}
|
||||
|
||||
if( lineCount == 1 )
|
||||
{
|
||||
aFormatter->Print( 0, ")\n" ); // Closes pts token on same line.
|
||||
}
|
||||
else
|
||||
{
|
||||
aFormatter->Print( 0, "\n" );
|
||||
aFormatter->Print( aNestLevel + 1, ")\n" ); // Closes pts token with multiple lines.
|
||||
}
|
||||
|
||||
formatStroke( aFormatter, aNestLevel + 1, aStroke );
|
||||
aFormatter->Print( 0, "\n" );
|
||||
formatFill( aFormatter, aNestLevel + 1, aFillMode, aFillColor );
|
||||
aFormatter->Print( 0, "\n" );
|
||||
|
||||
if( aUuid != niluuid )
|
||||
aFormatter->Print( aNestLevel + 1, "(uuid %s)\n", TO_UTF8( aUuid.AsString() ) );
|
||||
|
||||
aFormatter->Print( aNestLevel, ")\n" );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A cache assistant for the symbol library portion of the #SCH_PLUGIN API, and only for the
|
||||
* #SCH_SEXPR_PLUGIN, so therefore is private to this implementation file, i.e. not placed
|
||||
|
@ -300,14 +451,9 @@ class SCH_SEXPR_PLUGIN_CACHE
|
|||
|
||||
static void saveSymbolDrawItem( LIB_ITEM* aItem, OUTPUTFORMATTER& aFormatter,
|
||||
int aNestLevel );
|
||||
static void saveArc( LIB_SHAPE* aArc, OUTPUTFORMATTER& aFormatter, int aNestLevel = 0 );
|
||||
static void saveBezier( LIB_SHAPE* aBezier, OUTPUTFORMATTER& aFormatter, int aNestLevel = 0 );
|
||||
static void saveCircle( LIB_SHAPE* aCircle, OUTPUTFORMATTER& aFormatter, int aNestLevel = 0 );
|
||||
static void saveField( LIB_FIELD* aField, OUTPUTFORMATTER& aFormatter, int& aNextFreeFieldId,
|
||||
int aNestLevel );
|
||||
static void savePin( LIB_PIN* aPin, OUTPUTFORMATTER& aFormatter, int aNestLevel = 0 );
|
||||
static void savePolyLine( LIB_SHAPE* aPolyLine, OUTPUTFORMATTER& aFormatter, int aNestLevel = 0 );
|
||||
static void saveRectangle( LIB_SHAPE* aRect, OUTPUTFORMATTER& aFormatter, int aNestLevel = 0 );
|
||||
static void saveText( LIB_TEXT* aText, OUTPUTFORMATTER& aFormatter, int aNestLevel = 0 );
|
||||
|
||||
static void saveDcmInfoAsFields( LIB_SYMBOL* aSymbol, OUTPUTFORMATTER& aFormatter,
|
||||
|
@ -1763,15 +1909,39 @@ void SCH_SEXPR_PLUGIN_CACHE::saveSymbolDrawItem( LIB_ITEM* aItem, OUTPUTFORMATTE
|
|||
{
|
||||
case LIB_SHAPE_T:
|
||||
{
|
||||
LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( aItem );
|
||||
LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( aItem );
|
||||
STROKE_PARAMS stroke;
|
||||
FILL_T fillMode = shape->GetFillType();
|
||||
|
||||
stroke.SetWidth( shape->GetWidth() );
|
||||
|
||||
switch( shape->GetShape() )
|
||||
{
|
||||
case SHAPE_T::ARC: saveArc( shape, aFormatter, aNestLevel ); break;
|
||||
case SHAPE_T::CIRCLE: saveCircle( shape, aFormatter, aNestLevel ); break;
|
||||
case SHAPE_T::RECT: saveRectangle( shape, aFormatter, aNestLevel ); break;
|
||||
case SHAPE_T::BEZIER: saveBezier( shape, aFormatter, aNestLevel ); break;
|
||||
case SHAPE_T::POLY: savePolyLine( shape, aFormatter, aNestLevel ); break;
|
||||
case SHAPE_T::ARC:
|
||||
int x1;
|
||||
int x2;
|
||||
|
||||
shape->CalcArcAngles( x1, x2 );
|
||||
|
||||
formatArc( &aFormatter, aNestLevel, shape, x1, x2, stroke, fillMode, COLOR4D() );
|
||||
break;
|
||||
|
||||
case SHAPE_T::CIRCLE:
|
||||
formatCircle( &aFormatter, aNestLevel, shape, stroke, fillMode, COLOR4D() );
|
||||
break;
|
||||
|
||||
case SHAPE_T::RECT:
|
||||
formatRect( &aFormatter, aNestLevel, shape, stroke, fillMode, COLOR4D() );
|
||||
break;
|
||||
|
||||
case SHAPE_T::BEZIER:
|
||||
formatBezier(&aFormatter, aNestLevel, shape, stroke, fillMode, COLOR4D() );
|
||||
break;
|
||||
|
||||
case SHAPE_T::POLY:
|
||||
formatPoly( &aFormatter, aNestLevel, shape, stroke, fillMode, COLOR4D() );
|
||||
break;
|
||||
|
||||
default:
|
||||
UNIMPLEMENTED_FOR( shape->SHAPE_T_asString() );
|
||||
}
|
||||
|
@ -1793,81 +1963,6 @@ void SCH_SEXPR_PLUGIN_CACHE::saveSymbolDrawItem( LIB_ITEM* aItem, OUTPUTFORMATTE
|
|||
}
|
||||
|
||||
|
||||
void SCH_SEXPR_PLUGIN_CACHE::saveArc( LIB_SHAPE* aArc, OUTPUTFORMATTER& aFormatter, int aNestLevel )
|
||||
{
|
||||
int x1;
|
||||
int x2;
|
||||
|
||||
aArc->CalcArcAngles( x1, x2 );
|
||||
|
||||
if( x1 > 1800 )
|
||||
x1 -= 3600;
|
||||
|
||||
if( x2 > 1800 )
|
||||
x2 -= 3600;
|
||||
|
||||
aFormatter.Print( aNestLevel,
|
||||
"(arc (start %s %s) (end %s %s) (radius (at %s %s) (length %s) "
|
||||
"(angles %g %g))",
|
||||
FormatInternalUnits( aArc->GetStart().x ).c_str(),
|
||||
FormatInternalUnits( aArc->GetStart().y ).c_str(),
|
||||
FormatInternalUnits( aArc->GetEnd().x ).c_str(),
|
||||
FormatInternalUnits( aArc->GetEnd().y ).c_str(),
|
||||
FormatInternalUnits( aArc->GetCenter().x ).c_str(),
|
||||
FormatInternalUnits( aArc->GetCenter().y ).c_str(),
|
||||
FormatInternalUnits( aArc->GetRadius() ).c_str(),
|
||||
static_cast<double>( x1 ) / 10.0,
|
||||
static_cast<double>( x2 ) / 10.0 );
|
||||
|
||||
aFormatter.Print( 0, "\n" );
|
||||
aFormatter.Print( aNestLevel + 1, "(stroke (width %s)) ",
|
||||
FormatInternalUnits( aArc->GetWidth() ).c_str() );
|
||||
|
||||
formatFill( aArc, aFormatter, 0 );
|
||||
aFormatter.Print( 0, "\n" );
|
||||
aFormatter.Print( aNestLevel, ")\n" );
|
||||
}
|
||||
|
||||
|
||||
void SCH_SEXPR_PLUGIN_CACHE::saveBezier( LIB_SHAPE* aBezier, OUTPUTFORMATTER& aFormatter,
|
||||
int aNestLevel )
|
||||
{
|
||||
aFormatter.Print( aNestLevel, "(bezier\n" );
|
||||
aFormatter.Print( aNestLevel + 1, "(pts " );
|
||||
|
||||
for( const wxPoint& pt : { aBezier->GetStart(), aBezier->GetBezierC1(),
|
||||
aBezier->GetBezierC2(), aBezier->GetEnd() } )
|
||||
{
|
||||
aFormatter.Print( 0, " (xy %s %s)",
|
||||
FormatInternalUnits( pt.x ).c_str(),
|
||||
FormatInternalUnits( pt.y ).c_str() );
|
||||
}
|
||||
|
||||
aFormatter.Print( 0, ")\n" ); // Closes pts token on same line.
|
||||
|
||||
aFormatter.Print( aNestLevel + 1, "(stroke (width %s)) ",
|
||||
FormatInternalUnits( aBezier->GetWidth() ).c_str() );
|
||||
|
||||
formatFill( aBezier, aFormatter, 0 );
|
||||
aFormatter.Print( 0, "\n" );
|
||||
aFormatter.Print( aNestLevel, ")\n" );
|
||||
}
|
||||
|
||||
|
||||
void SCH_SEXPR_PLUGIN_CACHE::saveCircle( LIB_SHAPE* aCircle, OUTPUTFORMATTER& aFormatter,
|
||||
int aNestLevel )
|
||||
{
|
||||
aFormatter.Print( aNestLevel, "(circle (center %s %s) (radius %s) (stroke (width %s)) ",
|
||||
FormatInternalUnits( aCircle->GetPosition().x ).c_str(),
|
||||
FormatInternalUnits( aCircle->GetPosition().y ).c_str(),
|
||||
FormatInternalUnits( aCircle->GetRadius() ).c_str(),
|
||||
FormatInternalUnits( aCircle->GetWidth() ).c_str() );
|
||||
|
||||
formatFill( aCircle, aFormatter, 0 );
|
||||
aFormatter.Print( 0, ")\n" );
|
||||
}
|
||||
|
||||
|
||||
void SCH_SEXPR_PLUGIN_CACHE::saveField( LIB_FIELD* aField, OUTPUTFORMATTER& aFormatter,
|
||||
int& aNextFreeFieldId, int aNestLevel )
|
||||
{
|
||||
|
@ -1944,69 +2039,6 @@ void SCH_SEXPR_PLUGIN_CACHE::savePin( LIB_PIN* aPin, OUTPUTFORMATTER& aFormatter
|
|||
}
|
||||
|
||||
|
||||
void SCH_SEXPR_PLUGIN_CACHE::savePolyLine( LIB_SHAPE* aPolyLine, OUTPUTFORMATTER& aFormatter,
|
||||
int aNestLevel )
|
||||
{
|
||||
int newLine = 0;
|
||||
int lineCount = 1;
|
||||
aFormatter.Print( aNestLevel, "(polyline\n" );
|
||||
aFormatter.Print( aNestLevel + 1, "(pts" );
|
||||
|
||||
for( const VECTOR2I& pt : aPolyLine->GetPolyShape().Outline( 0 ).CPoints() )
|
||||
{
|
||||
if( newLine == 4 || !ADVANCED_CFG::GetCfg().m_CompactSave )
|
||||
{
|
||||
aFormatter.Print( 0, "\n" );
|
||||
aFormatter.Print( aNestLevel + 2, "(xy %s %s)",
|
||||
FormatInternalUnits( pt.x ).c_str(),
|
||||
FormatInternalUnits( pt.y ).c_str() );
|
||||
newLine = 0;
|
||||
lineCount += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
aFormatter.Print( 0, " (xy %s %s)",
|
||||
FormatInternalUnits( pt.x ).c_str(),
|
||||
FormatInternalUnits( pt.y ).c_str() );
|
||||
}
|
||||
|
||||
newLine += 1;
|
||||
}
|
||||
|
||||
if( lineCount == 1 )
|
||||
{
|
||||
aFormatter.Print( 0, ")\n" ); // Closes pts token on same line.
|
||||
}
|
||||
else
|
||||
{
|
||||
aFormatter.Print( 0, "\n" );
|
||||
aFormatter.Print( aNestLevel + 1, ")\n" ); // Closes pts token with multiple lines.
|
||||
}
|
||||
|
||||
aFormatter.Print( aNestLevel + 1, "(stroke (width %s)) ",
|
||||
FormatInternalUnits( aPolyLine->GetWidth() ).c_str() );
|
||||
formatFill( aPolyLine, aFormatter, 0 );
|
||||
aFormatter.Print( 0, "\n" );
|
||||
aFormatter.Print( aNestLevel, ")\n" );
|
||||
}
|
||||
|
||||
|
||||
void SCH_SEXPR_PLUGIN_CACHE::saveRectangle( LIB_SHAPE* aRect, OUTPUTFORMATTER& aFormatter,
|
||||
int aNestLevel )
|
||||
{
|
||||
aFormatter.Print( aNestLevel, "(rectangle (start %s %s) (end %s %s)\n",
|
||||
FormatInternalUnits( aRect->GetPosition().x ).c_str(),
|
||||
FormatInternalUnits( aRect->GetPosition().y ).c_str(),
|
||||
FormatInternalUnits( aRect->GetEnd().x ).c_str(),
|
||||
FormatInternalUnits( aRect->GetEnd().y ).c_str() );
|
||||
aFormatter.Print( aNestLevel + 1, "(stroke (width %s)) ",
|
||||
FormatInternalUnits( aRect->GetWidth() ).c_str() );
|
||||
formatFill( aRect, aFormatter, 0 );
|
||||
aFormatter.Print( 0, "\n" );
|
||||
aFormatter.Print( aNestLevel, ")\n" );
|
||||
}
|
||||
|
||||
|
||||
void SCH_SEXPR_PLUGIN_CACHE::saveText( LIB_TEXT* aText, OUTPUTFORMATTER& aFormatter,
|
||||
int aNestLevel )
|
||||
{
|
||||
|
|
|
@ -326,14 +326,11 @@ int EE_POINT_EDITOR::Main( const TOOL_EVENT& aEvent )
|
|||
modified = true;
|
||||
}
|
||||
|
||||
bool snap = !evt->DisableGridSnapping();
|
||||
bool snap = !evt->DisableGridSnapping();
|
||||
EDA_SHAPE* shape = dynamic_cast<EDA_SHAPE*>( item );
|
||||
|
||||
if( item->Type() == LIB_SHAPE_T
|
||||
&& static_cast<LIB_SHAPE*>( item )->GetShape() == SHAPE_T::ARC
|
||||
&& getEditedPointIndex() == ARC_CENTER )
|
||||
{
|
||||
if( shape && shape->GetShape() == SHAPE_T::ARC && getEditedPointIndex() == ARC_CENTER )
|
||||
snap = false;
|
||||
}
|
||||
|
||||
m_editedPoint->SetPosition( controls->GetCursorPosition( snap ) );
|
||||
|
||||
|
|
|
@ -120,13 +120,13 @@ public:
|
|||
void SetCenter( const wxPoint& aCenter );
|
||||
|
||||
/**
|
||||
* Set the angle for arcs, and normalizes it within the range 0 - 360 degrees.
|
||||
* Set the end point from the angle center and start.
|
||||
*
|
||||
* @param aAngle is tenths of degrees, but will soon be degrees.
|
||||
* @param aAngle is tenths of degrees.
|
||||
*/
|
||||
void SetArcAngle( double aAngle );
|
||||
void SetArcAngleAndEnd( double aAngle );
|
||||
double GetArcAngle() const { return m_arcAngle; }
|
||||
void SetArcAngleAndEnd( double aAngle, bool aCheckNegativeAngle = false );
|
||||
|
||||
double GetArcAngle() const;
|
||||
|
||||
// Some attributes are read only, since they are derived from m_Start, m_End, and m_Angle.
|
||||
// No Set...() function for these attributes.
|
||||
|
@ -135,14 +135,10 @@ public:
|
|||
std::vector<wxPoint> GetRectCorners() const;
|
||||
|
||||
/**
|
||||
* @return the angle of the starting point of this arc, between 0 and 3600 in 0.1 deg.
|
||||
* Calc arc start and end angles such that aStartAngle < aEndAngle. Each may be between
|
||||
* -360.0 and 360.0.
|
||||
*/
|
||||
virtual double GetArcAngleStart() const;
|
||||
|
||||
/**
|
||||
* @return the angle of the ending point of this arc, between 0 and 3600 in 0.1 deg.
|
||||
*/
|
||||
virtual double GetArcAngleEnd() const;
|
||||
void CalcArcAngles( double& aStartAngle, double& aEndAngle ) const;
|
||||
|
||||
int GetRadius() const;
|
||||
|
||||
|
@ -252,6 +248,12 @@ protected:
|
|||
|
||||
const std::vector<wxPoint> buildBezierToSegmentsPointsList( int aMinSegLen ) const;
|
||||
|
||||
void beginEdit( const wxPoint& aStartPoint );
|
||||
bool continueEdit( const wxPoint& aPosition );
|
||||
void calcEdit( const wxPoint& aPosition );
|
||||
void endEdit();
|
||||
void setEditState( int aState ) { m_editState = aState; }
|
||||
|
||||
protected:
|
||||
SHAPE_T m_shape; // Shape: line, Circle, Arc
|
||||
int m_width; // thickness of lines ...
|
||||
|
@ -260,13 +262,14 @@ protected:
|
|||
wxPoint m_end; // Line end point or Circle 3 o'clock point
|
||||
|
||||
wxPoint m_arcCenter; // Used only for Arcs: arc end point
|
||||
double m_arcAngle; // Used only for Arcs: Arc angle in 1/10 deg
|
||||
|
||||
wxPoint m_bezierC1; // Bezier Control Point 1
|
||||
wxPoint m_bezierC2; // Bezier Control Point 2
|
||||
|
||||
std::vector<wxPoint> m_bezierPoints;
|
||||
SHAPE_POLY_SET m_poly; // Stores the S_POLYGON shape
|
||||
|
||||
int m_editState;
|
||||
};
|
||||
|
||||
#endif // EDA_SHAPE_H
|
||||
|
|
|
@ -316,10 +316,7 @@ bool DIALOG_GRAPHIC_ITEM_PROPERTIES::TransferDataFromWindow()
|
|||
}
|
||||
|
||||
if( m_item->GetShape() == SHAPE_T::ARC )
|
||||
{
|
||||
m_item->SetCenter( CalcArcCenter( m_item->GetStart(), m_item->GetEnd(), m_AngleValue ) );
|
||||
m_item->SetArcAngle( m_AngleValue * 10.0 );
|
||||
}
|
||||
|
||||
if( m_fp_item )
|
||||
{
|
||||
|
|
|
@ -55,22 +55,23 @@ void FP_SHAPE::SetLocalCoord()
|
|||
|
||||
if( fp == NULL )
|
||||
{
|
||||
m_start0 = m_start;
|
||||
m_end0 = m_end;
|
||||
m_start0 = m_start;
|
||||
m_end0 = m_end;
|
||||
m_arcCenter0 = m_arcCenter;
|
||||
m_bezierC1_0 = m_bezierC1;
|
||||
m_bezierC2_0 = m_bezierC2;
|
||||
return;
|
||||
}
|
||||
|
||||
m_start0 = m_start - fp->GetPosition();
|
||||
m_end0 = m_end - fp->GetPosition();
|
||||
m_start0 = m_start - fp->GetPosition();
|
||||
m_end0 = m_end - fp->GetPosition();
|
||||
m_arcCenter0 = m_arcCenter - fp->GetPosition();
|
||||
m_bezierC1_0 = m_bezierC1 - fp->GetPosition();
|
||||
m_bezierC2_0 = m_bezierC2 - fp->GetPosition();
|
||||
m_bezierC1_0 = m_bezierC1 - fp->GetPosition();
|
||||
m_bezierC2_0 = m_bezierC2 - fp->GetPosition();
|
||||
|
||||
double angle = fp->GetOrientation();
|
||||
RotatePoint( &m_start0.x, &m_start0.y, -angle );
|
||||
RotatePoint( &m_end0.x, &m_end0.y, -angle );
|
||||
RotatePoint( &m_start0.x, &m_start0.y, -angle );
|
||||
RotatePoint( &m_end0.x, &m_end0.y, -angle );
|
||||
RotatePoint( &m_arcCenter0.x, &m_arcCenter0.y, -angle );
|
||||
RotatePoint( &m_bezierC1_0.x, &m_bezierC1_0.y, -angle );
|
||||
RotatePoint( &m_bezierC2_0.x, &m_bezierC2_0.y, -angle );
|
||||
|
@ -81,11 +82,11 @@ void FP_SHAPE::SetDrawCoord()
|
|||
{
|
||||
FOOTPRINT* fp = static_cast<FOOTPRINT*>( m_parent );
|
||||
|
||||
m_start = m_start0;
|
||||
m_end = m_end0;
|
||||
m_start = m_start0;
|
||||
m_end = m_end0;
|
||||
m_arcCenter = m_arcCenter0;
|
||||
m_bezierC1 = m_bezierC1_0;
|
||||
m_bezierC2 = m_bezierC2_0;
|
||||
m_bezierC1 = m_bezierC1_0;
|
||||
m_bezierC2 = m_bezierC2_0;
|
||||
|
||||
if( fp )
|
||||
{
|
||||
|
@ -95,11 +96,11 @@ void FP_SHAPE::SetDrawCoord()
|
|||
RotatePoint( &m_bezierC1.x, &m_bezierC1.y, fp->GetOrientation() );
|
||||
RotatePoint( &m_bezierC2.x, &m_bezierC2.y, fp->GetOrientation() );
|
||||
|
||||
m_start += fp->GetPosition();
|
||||
m_end += fp->GetPosition();
|
||||
m_start += fp->GetPosition();
|
||||
m_end += fp->GetPosition();
|
||||
m_arcCenter += fp->GetPosition();
|
||||
m_bezierC1 += fp->GetPosition();
|
||||
m_bezierC2 += fp->GetPosition();
|
||||
m_bezierC1 += fp->GetPosition();
|
||||
m_bezierC2 += fp->GetPosition();
|
||||
}
|
||||
|
||||
RebuildBezierToSegmentsPointsList( m_width );
|
||||
|
@ -172,13 +173,29 @@ void FP_SHAPE::SetCenter0( const wxPoint& aCenter )
|
|||
}
|
||||
|
||||
|
||||
void FP_SHAPE::SetArcAngleAndEnd0( double aAngle )
|
||||
wxPoint FP_SHAPE::GetArcMid0() const
|
||||
{
|
||||
PCB_SHAPE::SetArcAngle( aAngle );
|
||||
wxPoint mid0 = m_start0;
|
||||
RotatePoint( &mid0, m_arcCenter0, -GetArcAngle() / 2.0 );
|
||||
return mid0;
|
||||
}
|
||||
|
||||
wxPoint end = GetStart0();
|
||||
RotatePoint( &end, GetCenter0(), -m_arcAngle );
|
||||
SetEnd0( end );
|
||||
|
||||
void FP_SHAPE::SetArcAngleAndEnd0( double aAngle, bool aCheckNegativeAngle )
|
||||
{
|
||||
m_end0 = m_start0;
|
||||
RotatePoint( &m_end0, m_arcCenter0, -NormalizeAngle360Max( aAngle ) );
|
||||
|
||||
if( aCheckNegativeAngle && aAngle < 0 )
|
||||
std::swap( m_start0, m_end0 );
|
||||
}
|
||||
|
||||
|
||||
void FP_SHAPE::SetArcGeometry0( const wxPoint& aStart0, const wxPoint& aMid0, const wxPoint& aEnd0 )
|
||||
{
|
||||
m_start0 = aStart0;
|
||||
m_end0 = aEnd0;
|
||||
m_arcCenter0 = CalcArcCenter( aStart0, aMid0, aEnd0 );
|
||||
}
|
||||
|
||||
|
||||
|
@ -367,6 +384,11 @@ static struct FP_SHAPE_DESC
|
|||
{
|
||||
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
|
||||
REGISTER_TYPE( FP_SHAPE );
|
||||
propMgr.AddTypeCast( new TYPE_CAST<FP_SHAPE, BOARD_ITEM> );
|
||||
propMgr.AddTypeCast( new TYPE_CAST<FP_SHAPE, EDA_SHAPE> );
|
||||
propMgr.AddTypeCast( new TYPE_CAST<FP_SHAPE, PCB_SHAPE> );
|
||||
propMgr.InheritsAfter( TYPE_HASH( FP_SHAPE ), TYPE_HASH( BOARD_ITEM ) );
|
||||
propMgr.InheritsAfter( TYPE_HASH( FP_SHAPE ), TYPE_HASH( EDA_SHAPE ) );
|
||||
propMgr.InheritsAfter( TYPE_HASH( FP_SHAPE ), TYPE_HASH( PCB_SHAPE ) );
|
||||
|
||||
propMgr.AddProperty( new PROPERTY<FP_SHAPE, wxString>( _HKI( "Parent" ),
|
||||
|
|
|
@ -71,7 +71,9 @@ public:
|
|||
* Sets the angle for arcs, and normalizes it within the range 0 - 360 degrees.
|
||||
* @param aAngle is tenths of degrees, but will soon be degrees.
|
||||
*/
|
||||
void SetArcAngleAndEnd0( double aAngle );
|
||||
void SetArcAngleAndEnd0( double aAngle, bool aCheckNegativeAngle = false );
|
||||
|
||||
void SetArcGeometry0( const wxPoint& aStart, const wxPoint& aMid, const wxPoint& aEnd );
|
||||
|
||||
/**
|
||||
* Move an edge of the footprint.
|
||||
|
@ -121,6 +123,8 @@ public:
|
|||
wxPoint GetCenter0() const;
|
||||
void SetCenter0( const wxPoint& aPt );
|
||||
|
||||
wxPoint GetArcMid0() const;
|
||||
|
||||
/**
|
||||
* Set relative coordinates from draw coordinates.
|
||||
* Call in only when the geometry or the footprint is modified and therefore the relative
|
||||
|
|
|
@ -1408,12 +1408,16 @@ void PCB_PAINTER::draw( const PCB_SHAPE* aShape, int aLayer )
|
|||
}
|
||||
|
||||
case SHAPE_T::ARC:
|
||||
{
|
||||
double startAngle;
|
||||
double endAngle;
|
||||
aShape->CalcArcAngles( startAngle, endAngle );
|
||||
|
||||
if( sketch )
|
||||
{
|
||||
m_gal->DrawArcSegment( aShape->GetCenter(), aShape->GetRadius(),
|
||||
DECIDEG2RAD( aShape->GetArcAngleStart() ),
|
||||
DECIDEG2RAD( aShape->GetArcAngleStart() + aShape->GetArcAngle() ), // Change this
|
||||
thickness, m_maxError );
|
||||
DEG2RAD( startAngle ), DEG2RAD( endAngle ), thickness,
|
||||
m_maxError );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1421,11 +1425,11 @@ void PCB_PAINTER::draw( const PCB_SHAPE* aShape, int aLayer )
|
|||
m_gal->SetIsStroke( false );
|
||||
|
||||
m_gal->DrawArcSegment( aShape->GetCenter(), aShape->GetRadius(),
|
||||
DECIDEG2RAD( aShape->GetArcAngleStart() ),
|
||||
DECIDEG2RAD( aShape->GetArcAngleStart() + aShape->GetArcAngle() ), // Change this
|
||||
thickness, m_maxError );
|
||||
DEG2RAD( startAngle ), DEG2RAD( endAngle ), thickness,
|
||||
m_maxError );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SHAPE_T::CIRCLE:
|
||||
if( sketch )
|
||||
|
|
|
@ -820,11 +820,11 @@ void PCB_IO::format( const PCB_SHAPE* aShape, int aNestLevel ) const
|
|||
break;
|
||||
|
||||
case SHAPE_T::ARC:
|
||||
m_out->Print( aNestLevel, "(gr_arc%s (start %s) (end %s) (angle %s)",
|
||||
m_out->Print( aNestLevel, "(gr_arc%s (start %s) (mid %s) (end %s)",
|
||||
locked.c_str(),
|
||||
FormatInternalUnits( aShape->GetCenter() ).c_str(),
|
||||
FormatInternalUnits( aShape->GetStart() ).c_str(),
|
||||
FormatAngle( aShape->GetArcAngle() ).c_str() );
|
||||
FormatInternalUnits( aShape->GetArcMid() ).c_str(),
|
||||
FormatInternalUnits( aShape->GetEnd() ).c_str() );
|
||||
break;
|
||||
|
||||
case SHAPE_T::POLY:
|
||||
|
@ -954,11 +954,11 @@ void PCB_IO::format( const FP_SHAPE* aFPShape, int aNestLevel ) const
|
|||
break;
|
||||
|
||||
case SHAPE_T::ARC:
|
||||
m_out->Print( aNestLevel, "(fp_arc%s (start %s) (end %s) (angle %s)",
|
||||
m_out->Print( aNestLevel, "(fp_arc%s (start %s) (mid %s) (end %s)",
|
||||
locked.c_str(),
|
||||
FormatInternalUnits( aFPShape->GetCenter0() ).c_str(),
|
||||
FormatInternalUnits( aFPShape->GetStart0() ).c_str(),
|
||||
FormatAngle( aFPShape->GetArcAngle() ).c_str() );
|
||||
FormatInternalUnits( aFPShape->GetArcMid0() ).c_str(),
|
||||
FormatInternalUnits( aFPShape->GetEnd0() ).c_str() );
|
||||
break;
|
||||
|
||||
case SHAPE_T::POLY:
|
||||
|
@ -1630,10 +1630,10 @@ void PCB_IO::format( const PAD* aPad, int aNestLevel ) const
|
|||
break;
|
||||
|
||||
case SHAPE_T::ARC:
|
||||
m_out->Print( nested_level, "(gr_arc (start %s) (end %s) (angle %s)",
|
||||
FormatInternalUnits( primitive->GetCenter() ).c_str(),
|
||||
m_out->Print( aNestLevel, "(gr_arc (start %s) (mid %s) (end %s)",
|
||||
FormatInternalUnits( primitive->GetStart() ).c_str(),
|
||||
FormatAngle( primitive->GetArcAngle() ).c_str() );
|
||||
FormatInternalUnits( primitive->GetArcMid() ).c_str(),
|
||||
FormatInternalUnits( primitive->GetEnd() ).c_str() );
|
||||
break;
|
||||
|
||||
case SHAPE_T::CIRCLE:
|
||||
|
|
|
@ -101,9 +101,11 @@ class PCB_TEXT;
|
|||
//#define SEXPR_BOARD_FILE_VERSION 20210623 // Add support for reading/writing arcs in polygons
|
||||
//#define SEXPR_BOARD_FILE_VERSION 20210722 // Reading/writing group locked flags
|
||||
//#define SEXPR_BOARD_FILE_VERSION 20210824 // Opacity in 3D colors
|
||||
#define SEXPR_BOARD_FILE_VERSION 20210925 // Locked flag for fp_text
|
||||
//#define SEXPR_BOARD_FILE_VERSION 20210925 // Locked flag for fp_text
|
||||
#define SEXPR_BOARD_FILE_VERSION 20211014 // Arc formatting
|
||||
|
||||
#define BOARD_FILE_HOST_VERSION 20200825 ///< Earlier files than this include the host tag
|
||||
#define LEGACY_ARC_FORMATTING 20210925 ///< These were the last to use old arc formatting
|
||||
|
||||
#define CTL_OMIT_PAD_NETS (1 << 1) ///< Omit pads net names (useless in library)
|
||||
#define CTL_OMIT_TSTAMPS (1 << 2) ///< Omit component time stamp (useless in library)
|
||||
|
|
|
@ -2385,25 +2385,60 @@ PCB_SHAPE* PCB_PARSER::parsePCB_SHAPE()
|
|||
|
||||
token = NextTok();
|
||||
|
||||
// the start keyword actually gives the arc center
|
||||
// Allows also T_center for future change
|
||||
if( token != T_start && token != T_center )
|
||||
Expecting( T_start );
|
||||
if( m_requiredVersion <= LEGACY_ARC_FORMATTING )
|
||||
{
|
||||
// In legacy files the start keyword actually gives the arc center...
|
||||
if( token != T_start )
|
||||
Expecting( T_start );
|
||||
|
||||
pt.x = parseBoardUnits( "X coordinate" );
|
||||
pt.y = parseBoardUnits( "Y coordinate" );
|
||||
shape->SetCenter( pt );
|
||||
NeedRIGHT();
|
||||
NeedLEFT();
|
||||
token = NextTok();
|
||||
pt.x = parseBoardUnits( "X coordinate" );
|
||||
pt.y = parseBoardUnits( "Y coordinate" );
|
||||
shape->SetCenter( pt );
|
||||
NeedRIGHT();
|
||||
NeedLEFT();
|
||||
token = NextTok();
|
||||
|
||||
if( token != T_end ) // the end keyword actually gives the starting point of the arc
|
||||
Expecting( T_end );
|
||||
// ... and the end keyword gives the start point of the arc
|
||||
if( token != T_end )
|
||||
Expecting( T_end );
|
||||
|
||||
pt.x = parseBoardUnits( "X coordinate" );
|
||||
pt.y = parseBoardUnits( "Y coordinate" );
|
||||
shape->SetStart( pt );
|
||||
NeedRIGHT();
|
||||
}
|
||||
else
|
||||
{
|
||||
wxPoint start, mid, end;
|
||||
|
||||
if( token != T_start )
|
||||
Expecting( T_start );
|
||||
|
||||
start.x = parseBoardUnits( "X coordinate" );
|
||||
start.y = parseBoardUnits( "Y coordinate" );
|
||||
NeedRIGHT();
|
||||
NeedLEFT();
|
||||
token = NextTok();
|
||||
|
||||
if( token != T_mid )
|
||||
Expecting( T_mid );
|
||||
|
||||
mid.x = parseBoardUnits( "X coordinate" );
|
||||
mid.y = parseBoardUnits( "Y coordinate" );
|
||||
NeedRIGHT();
|
||||
NeedLEFT();
|
||||
token = NextTok();
|
||||
|
||||
if( token != T_end )
|
||||
Expecting( T_end );
|
||||
|
||||
end.x = parseBoardUnits( "X coordinate" );
|
||||
end.y = parseBoardUnits( "Y coordinate" );
|
||||
NeedRIGHT();
|
||||
|
||||
shape->SetArcGeometry( start, mid, end );
|
||||
}
|
||||
|
||||
pt.x = parseBoardUnits( "X coordinate" );
|
||||
pt.y = parseBoardUnits( "Y coordinate" );
|
||||
shape->SetStart( pt );
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_gr_circle:
|
||||
|
@ -2583,12 +2618,20 @@ PCB_SHAPE* PCB_PARSER::parsePCB_SHAPE()
|
|||
switch( token )
|
||||
{
|
||||
case T_angle:
|
||||
angle = parseDouble( "segment angle" ) * 10.0;
|
||||
if( m_requiredVersion <= LEGACY_ARC_FORMATTING )
|
||||
{
|
||||
angle = parseAngle( "arc angle" );
|
||||
|
||||
if( shape->GetShape() == SHAPE_T::ARC )
|
||||
shape->SetArcAngleAndEnd( angle );
|
||||
if( shape->GetShape() == SHAPE_T::ARC )
|
||||
shape->SetArcAngleAndEnd( angle, true );
|
||||
|
||||
NeedRIGHT();
|
||||
}
|
||||
else
|
||||
{
|
||||
Unexpected( T_angle );
|
||||
}
|
||||
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_layer:
|
||||
|
@ -2707,7 +2750,7 @@ PCB_TEXT* PCB_PARSER::parsePCB_TEXT()
|
|||
|
||||
if( token == T_NUMBER )
|
||||
{
|
||||
text->SetTextAngle( parseDouble() * 10.0 );
|
||||
text->SetTextAngle( parseAngle() );
|
||||
NeedRIGHT();
|
||||
}
|
||||
else if( token != T_RIGHT )
|
||||
|
@ -3272,7 +3315,7 @@ FOOTPRINT* PCB_PARSER::parseFOOTPRINT_unchecked( wxArrayString* aInitialComments
|
|||
|
||||
if( token == T_NUMBER )
|
||||
{
|
||||
footprint->SetOrientation( parseDouble() * 10.0 );
|
||||
footprint->SetOrientation( parseAngle() );
|
||||
NeedRIGHT();
|
||||
}
|
||||
else if( token != T_RIGHT )
|
||||
|
@ -3420,24 +3463,6 @@ FOOTPRINT* PCB_PARSER::parseFOOTPRINT_unchecked( wxArrayString* aInitialComments
|
|||
}
|
||||
|
||||
case T_fp_arc:
|
||||
{
|
||||
FP_SHAPE* shape = parseFP_SHAPE();
|
||||
|
||||
// Drop 0 and NaN angles as these can corrupt/crash the schematic
|
||||
if( std::isnormal( shape->GetArcAngle() ) )
|
||||
{
|
||||
shape->SetParent( footprint.get() );
|
||||
shape->SetDrawCoord();
|
||||
footprint->Add( shape, ADD_MODE::APPEND );
|
||||
}
|
||||
else
|
||||
{
|
||||
delete shape;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case T_fp_circle:
|
||||
case T_fp_curve:
|
||||
case T_fp_rect:
|
||||
|
@ -3574,7 +3599,7 @@ FP_TEXT* PCB_PARSER::parseFP_TEXT()
|
|||
|
||||
if( CurTok() == T_NUMBER )
|
||||
{
|
||||
text->SetTextAngle( parseDouble() * 10.0 );
|
||||
text->SetTextAngle( parseAngle() );
|
||||
NextTok();
|
||||
}
|
||||
|
||||
|
@ -3652,33 +3677,68 @@ FP_SHAPE* PCB_PARSER::parseFP_SHAPE()
|
|||
|
||||
token = NextTok();
|
||||
|
||||
// the start keyword actually gives the arc center
|
||||
// Allows also T_center for future change
|
||||
if( token != T_start && token != T_center )
|
||||
Expecting( T_start );
|
||||
if( m_requiredVersion <= LEGACY_ARC_FORMATTING )
|
||||
{
|
||||
// In legacy files the start keyword actually gives the arc center...
|
||||
if( token != T_start )
|
||||
Expecting( T_start );
|
||||
|
||||
pt.x = parseBoardUnits( "X coordinate" );
|
||||
pt.y = parseBoardUnits( "Y coordinate" );
|
||||
shape->SetCenter0( pt );
|
||||
NeedRIGHT();
|
||||
NeedLEFT();
|
||||
token = NextTok();
|
||||
pt.x = parseBoardUnits( "X coordinate" );
|
||||
pt.y = parseBoardUnits( "Y coordinate" );
|
||||
shape->SetCenter0( pt );
|
||||
NeedRIGHT();
|
||||
NeedLEFT();
|
||||
token = NextTok();
|
||||
|
||||
if( token != T_end ) // end keyword actually gives the starting point of the arc
|
||||
Expecting( T_end );
|
||||
// ... and the end keyword gives the start point of the arc
|
||||
if( token != T_end )
|
||||
Expecting( T_end );
|
||||
|
||||
pt.x = parseBoardUnits( "X coordinate" );
|
||||
pt.y = parseBoardUnits( "Y coordinate" );
|
||||
shape->SetStart0( pt );
|
||||
NeedRIGHT();
|
||||
NeedLEFT();
|
||||
token = NextTok();
|
||||
pt.x = parseBoardUnits( "X coordinate" );
|
||||
pt.y = parseBoardUnits( "Y coordinate" );
|
||||
shape->SetStart0( pt );
|
||||
NeedRIGHT();
|
||||
NeedLEFT();
|
||||
token = NextTok();
|
||||
|
||||
if( token != T_angle )
|
||||
Expecting( T_angle );
|
||||
if( token != T_angle )
|
||||
Expecting( T_angle );
|
||||
|
||||
shape->SetArcAngleAndEnd0( parseAngle( "segment angle" ), true );
|
||||
NeedRIGHT();
|
||||
}
|
||||
else
|
||||
{
|
||||
wxPoint start, mid, end;
|
||||
|
||||
if( token != T_start )
|
||||
Expecting( T_start );
|
||||
|
||||
start.x = parseBoardUnits( "X coordinate" );
|
||||
start.y = parseBoardUnits( "Y coordinate" );
|
||||
NeedRIGHT();
|
||||
NeedLEFT();
|
||||
token = NextTok();
|
||||
|
||||
if( token != T_mid )
|
||||
Expecting( T_mid );
|
||||
|
||||
mid.x = parseBoardUnits( "X coordinate" );
|
||||
mid.y = parseBoardUnits( "Y coordinate" );
|
||||
NeedRIGHT();
|
||||
NeedLEFT();
|
||||
token = NextTok();
|
||||
|
||||
if( token != T_end )
|
||||
Expecting( T_end );
|
||||
|
||||
end.x = parseBoardUnits( "X coordinate" );
|
||||
end.y = parseBoardUnits( "Y coordinate" );
|
||||
NeedRIGHT();
|
||||
|
||||
shape->SetArcGeometry0( start, mid, end );
|
||||
}
|
||||
|
||||
shape->SetArcAngleAndEnd0( parseDouble( "segment angle" ) * 10.0 );
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_fp_circle:
|
||||
|
@ -4053,7 +4113,7 @@ PAD* PCB_PARSER::parsePAD( FOOTPRINT* aParent )
|
|||
|
||||
if( token == T_NUMBER )
|
||||
{
|
||||
pad->SetOrientation( parseDouble() * 10.0 );
|
||||
pad->SetOrientation( parseAngle() );
|
||||
NeedRIGHT();
|
||||
}
|
||||
else if( token != T_RIGHT )
|
||||
|
|
|
@ -311,6 +311,16 @@ private:
|
|||
return parseDouble( GetTokenText( aToken ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse angles into deci-degrees.
|
||||
*/
|
||||
double parseAngle() { return parseDouble() * 10.0; }
|
||||
|
||||
inline double parseAngle( const char* aExpected )
|
||||
{
|
||||
return parseDouble( aExpected ) * 10.0;
|
||||
}
|
||||
|
||||
int parseBoardUnits();
|
||||
|
||||
int parseBoardUnits( const char* aExpected );
|
||||
|
|
|
@ -804,15 +804,21 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, FOOTPRINT* aFootprint )
|
|||
|
||||
wxPoint arc_centre = graphic->GetCenter0();
|
||||
double radius = graphic->GetRadius() + graphic->GetWidth()/2;
|
||||
double arcStartDeg = graphic->GetArcAngleStart() / 10.0;
|
||||
double arcAngleDeg = graphic->GetArcAngle() / 10.0;
|
||||
|
||||
VECTOR2I startRadial = graphic->GetStart() - graphic->GetCenter();
|
||||
double arcStartDeg = ArcTangente( startRadial.y, startRadial.x ) / 10;
|
||||
NORMALIZE_ANGLE_DEGREES_POS( arcStartDeg );
|
||||
|
||||
// For some obscure reason, FreeRouter does not show the same polygonal
|
||||
// shape for polygons CW and CCW. So used only the order of corners
|
||||
// giving the best look.
|
||||
if( arcAngleDeg < 0 )
|
||||
{
|
||||
arcStartDeg = graphic->GetArcAngleEnd() / 10.0;
|
||||
VECTOR2I endRadial = graphic->GetEnd() - graphic->GetCenter();
|
||||
arcStartDeg = ArcTangente( endRadial.y, endRadial.x ) / 10;
|
||||
NORMALIZE_ANGLE_DEGREES_POS( arcStartDeg );
|
||||
|
||||
arcAngleDeg = -arcAngleDeg;
|
||||
}
|
||||
|
||||
|
|
|
@ -815,7 +815,6 @@ int CONVERT_TOOL::SegmentToArc( const TOOL_EVENT& aEvent )
|
|||
arc->SetCenter( wxPoint( center ) );
|
||||
arc->SetStart( wxPoint( start ) );
|
||||
arc->SetEnd( wxPoint( end ) );
|
||||
arc->SetArcAngle( CalcArcAngle( start, mid, end ) );
|
||||
|
||||
commit.Add( arc );
|
||||
}
|
||||
|
|
|
@ -1721,8 +1721,6 @@ static void updateArcFromConstructionMgr( const KIGFX::PREVIEW::ARC_GEOM_MANAGER
|
|||
aArc.SetStart( (wxPoint) vec );
|
||||
vec = aMgr.GetEndRadiusEnd();
|
||||
aArc.SetEnd( (wxPoint) vec );
|
||||
|
||||
aArc.SetArcAngle( RAD2DECIDEG( -aMgr.GetSubtended() ) );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -627,7 +627,6 @@ PCB_LAYER_ID PAD_TOOL::explodePad( PAD* aPad )
|
|||
shape->SetStart( primitive->GetStart() );
|
||||
shape->SetEnd( primitive->GetEnd() );
|
||||
shape->SetCenter( primitive->GetCenter() );
|
||||
shape->SetArcAngle( primitive->GetArcAngle() );
|
||||
break;
|
||||
|
||||
case SHAPE_T::BEZIER:
|
||||
|
@ -766,7 +765,6 @@ void PAD_TOOL::recombinePad( PAD* aPad )
|
|||
pcbShape->SetStart( fpShape->GetStart() );
|
||||
pcbShape->SetEnd( fpShape->GetEnd() );
|
||||
pcbShape->SetCenter( fpShape->GetCenter() );
|
||||
pcbShape->SetArcAngle( fpShape->GetArcAngle() );
|
||||
break;
|
||||
|
||||
case SHAPE_T::BEZIER:
|
||||
|
|
|
@ -602,13 +602,8 @@ void PCB_POINT_EDITOR::editArcEndpointKeepTangent( PCB_SHAPE* aArc, const VECTOR
|
|||
VECTOR2I start = aStart;
|
||||
VECTOR2I end = aEnd;
|
||||
VECTOR2I center = aCenter;
|
||||
VECTOR2D startLine = aStart - aCenter;
|
||||
VECTOR2D endLine = aEnd - aCenter;
|
||||
double newAngle = RAD2DECIDEG( endLine.Angle() - startLine.Angle() );
|
||||
|
||||
bool clockwise;
|
||||
bool movingStart;
|
||||
bool arcValid = true;
|
||||
bool movingStart;
|
||||
bool arcValid = true;
|
||||
|
||||
VECTOR2I p1, p2, p3;
|
||||
// p1 does not move, p2 does.
|
||||
|
@ -723,24 +718,15 @@ void PCB_POINT_EDITOR::editArcEndpointKeepTangent( PCB_SHAPE* aArc, const VECTOR
|
|||
|
||||
// This is just to limit the radius, so nothing overflows later when drawing.
|
||||
if( abs( v2.y / ( R - v2.x ) ) > ADVANCED_CFG::GetCfg().m_DrawArcCenterMaxAngle )
|
||||
{
|
||||
arcValid = false;
|
||||
}
|
||||
|
||||
// Never recorded a problem, but still checking.
|
||||
if( !std::isfinite( delta ) )
|
||||
{
|
||||
arcValid = false;
|
||||
}
|
||||
|
||||
// v4 is the new center
|
||||
v4 = ( !transformCircle ) ? VECTOR2D( -delta, 0 ) : VECTOR2D( 2 * R + delta, 0 );
|
||||
|
||||
clockwise = aArc->GetArcAngle() > 0;
|
||||
|
||||
if( transformCircle )
|
||||
clockwise = !clockwise;
|
||||
|
||||
tmpx = v4.x * u1.x + v4.y * u2.x;
|
||||
tmpy = v4.x * u1.y + v4.y * u2.y;
|
||||
v4.x = tmpx;
|
||||
|
@ -748,24 +734,14 @@ void PCB_POINT_EDITOR::editArcEndpointKeepTangent( PCB_SHAPE* aArc, const VECTOR
|
|||
|
||||
center = v4 + aCenter;
|
||||
|
||||
startLine = start - center;
|
||||
endLine = end - center;
|
||||
newAngle = RAD2DECIDEG( endLine.Angle() - startLine.Angle() );
|
||||
|
||||
if( clockwise && newAngle < 0.0 )
|
||||
newAngle += 3600.0;
|
||||
else if( !clockwise && newAngle > 0.0 )
|
||||
newAngle -= 3600.0;
|
||||
|
||||
if( arcValid )
|
||||
{
|
||||
aArc->SetCenter( (wxPoint) aCenter );
|
||||
aArc->SetArcAngle( newAngle );
|
||||
aArc->SetCenter( (wxPoint) center );
|
||||
|
||||
if( movingStart )
|
||||
aArc->SetStart( (wxPoint) aStart );
|
||||
aArc->SetStart( (wxPoint) start );
|
||||
else
|
||||
aArc->SetEnd( (wxPoint) aEnd );
|
||||
aArc->SetEnd( (wxPoint) end );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -878,7 +854,6 @@ void PCB_POINT_EDITOR::editArcEndpointKeepCenter( PCB_SHAPE* aArc, const VECTOR2
|
|||
const VECTOR2I& aEnd,
|
||||
const VECTOR2I& aCursor ) const
|
||||
{
|
||||
bool clockwise;
|
||||
bool movingStart;
|
||||
|
||||
VECTOR2I p1, p2;
|
||||
|
@ -932,19 +907,7 @@ void PCB_POINT_EDITOR::editArcEndpointKeepCenter( PCB_SHAPE* aArc, const VECTOR2
|
|||
p1 = p1 + aCenter;
|
||||
p2 = p2 + aCenter;
|
||||
|
||||
clockwise = aArc->GetArcAngle() > 0;
|
||||
|
||||
VECTOR2D startLine = aStart - aCenter;
|
||||
VECTOR2D endLine = aEnd - aCenter;
|
||||
double newAngle = RAD2DECIDEG( endLine.Angle() - startLine.Angle() );
|
||||
|
||||
if( clockwise && newAngle < 0.0 )
|
||||
newAngle += 3600.0;
|
||||
else if( !clockwise && newAngle > 0.0 )
|
||||
newAngle -= 3600.0;
|
||||
|
||||
aArc->SetCenter( (wxPoint) aCenter );
|
||||
aArc->SetArcAngle( newAngle );
|
||||
|
||||
if( movingStart )
|
||||
aArc->SetStart( (wxPoint) aStart );
|
||||
|
|
Loading…
Reference in New Issue