Pcbnew fix arc edition
This commit is contained in:
parent
abc64f228b
commit
133d082cc5
|
@ -91,6 +91,23 @@ static const wxChar ShowRouterDebugGraphics[] = wxT( "ShowRouterDebugGraphics" )
|
||||||
*/
|
*/
|
||||||
static const wxChar CompactFileSave[] = wxT( "CompactSave" );
|
static const wxChar CompactFileSave[] = wxT( "CompactSave" );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For drawsegments - arcs.
|
||||||
|
* Distance from an arc end point and the estimated end point,
|
||||||
|
* when rotating from the start point to the end point.
|
||||||
|
* 0 will not allow any approximate result, and the arc will not show.
|
||||||
|
* Squared value for performances, in system unit.
|
||||||
|
*/
|
||||||
|
static const wxChar DrawArcAccuracy[] = wxT( "DrawArcAccuracy" );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For drawsegments - arcs.
|
||||||
|
* When drawing an arc, the angle ( center - start ) - ( start - end ),
|
||||||
|
* can be limited to avoid extremely high radii.
|
||||||
|
* The value is the tan( angle )
|
||||||
|
*/
|
||||||
|
static const wxChar DrawArcCenterStartEndMaxAngle[] = wxT( "DrawArcCenterStartEndMaxAngle" );
|
||||||
|
|
||||||
} // namespace KEYS
|
} // namespace KEYS
|
||||||
|
|
||||||
|
|
||||||
|
@ -168,9 +185,11 @@ ADVANCED_CFG::ADVANCED_CFG()
|
||||||
|
|
||||||
// Init defaults - this is done in case the config doesn't exist,
|
// Init defaults - this is done in case the config doesn't exist,
|
||||||
// then the values will remain as set here.
|
// then the values will remain as set here.
|
||||||
m_realTimeConnectivity = true;
|
m_realTimeConnectivity = true;
|
||||||
m_coroutineStackSize = AC_STACK::default_stack;
|
m_coroutineStackSize = AC_STACK::default_stack;
|
||||||
m_ShowRouterDebugGraphics = false;
|
m_ShowRouterDebugGraphics = false;
|
||||||
|
m_drawArcAccuracy = 10.0;
|
||||||
|
m_drawArcCenterStartEndMaxAngle = 50.0;
|
||||||
|
|
||||||
loadFromConfigFile();
|
loadFromConfigFile();
|
||||||
}
|
}
|
||||||
|
@ -220,6 +239,12 @@ void ADVANCED_CFG::loadSettings( wxConfigBase& aCfg )
|
||||||
configParams.push_back( new PARAM_CFG_BOOL( true, AC_KEYS::CompactFileSave,
|
configParams.push_back( new PARAM_CFG_BOOL( true, AC_KEYS::CompactFileSave,
|
||||||
&m_CompactSave, false ) );
|
&m_CompactSave, false ) );
|
||||||
|
|
||||||
|
configParams.push_back( new PARAM_CFG_DOUBLE(
|
||||||
|
true, AC_KEYS::DrawArcAccuracy, &m_drawArcAccuracy, 10.0, 0.0, 100000.0 ) );
|
||||||
|
|
||||||
|
configParams.push_back( new PARAM_CFG_DOUBLE( true, AC_KEYS::DrawArcCenterStartEndMaxAngle,
|
||||||
|
&m_drawArcCenterStartEndMaxAngle, 50.0, 0.0, 100000.0 ) );
|
||||||
|
|
||||||
wxConfigLoadSetups( &aCfg, configParams );
|
wxConfigLoadSetups( &aCfg, configParams );
|
||||||
|
|
||||||
for( auto param : configParams )
|
for( auto param : configParams )
|
||||||
|
|
|
@ -68,6 +68,20 @@ public:
|
||||||
*/
|
*/
|
||||||
static const ADVANCED_CFG& GetCfg();
|
static const ADVANCED_CFG& GetCfg();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For drawsegments - arcs.
|
||||||
|
* Distance from an arc end point and the estimated end point,
|
||||||
|
* when rotating from the start point to the end point.
|
||||||
|
*/
|
||||||
|
double m_drawArcAccuracy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For drawsegments - arcs.
|
||||||
|
* When drawing an arc, the angle ( center - start ) - ( start - end )
|
||||||
|
* can be limited to avoid extremely high radii.
|
||||||
|
*/
|
||||||
|
double m_drawArcCenterStartEndMaxAngle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extra fill clearance for zone fills
|
* Extra fill clearance for zone fills
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -115,6 +115,10 @@ void DRAWSEGMENT::Move( const wxPoint& aMoveVector )
|
||||||
m_Poly.Move( VECTOR2I( aMoveVector ) );
|
m_Poly.Move( VECTOR2I( aMoveVector ) );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case S_ARC:
|
||||||
|
m_ThirdPoint += aMoveVector;
|
||||||
|
break;
|
||||||
|
|
||||||
case S_CURVE:
|
case S_CURVE:
|
||||||
m_BezierC1 += aMoveVector;
|
m_BezierC1 += aMoveVector;
|
||||||
m_BezierC2 += aMoveVector;
|
m_BezierC2 += aMoveVector;
|
||||||
|
@ -352,11 +356,7 @@ wxPoint DRAWSEGMENT::GetArcEnd() const
|
||||||
switch( m_Shape )
|
switch( m_Shape )
|
||||||
{
|
{
|
||||||
case S_ARC:
|
case S_ARC:
|
||||||
// rotate the starting point of the arc, given by m_End, through the
|
endPoint = m_ThirdPoint;
|
||||||
// angle m_Angle to get the ending point of the arc.
|
|
||||||
// m_Start is the arc centre
|
|
||||||
endPoint = m_End; // m_End = start point of arc
|
|
||||||
RotatePoint( &endPoint, m_Start, -m_Angle );
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -403,11 +403,29 @@ double DRAWSEGMENT::GetArcAngleStart() const
|
||||||
return angleStart;
|
return angleStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double DRAWSEGMENT::GetArcAngleEnd() const
|
||||||
|
{
|
||||||
|
// due to the Y axis orient atan2 needs - y value
|
||||||
|
double angleStart = ArcTangente( GetArcEnd().y - GetCenter().y,
|
||||||
|
GetArcEnd().x - GetCenter().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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DRAWSEGMENT::SetAngle( double aAngle )
|
void DRAWSEGMENT::SetAngle( double aAngle )
|
||||||
{
|
{
|
||||||
|
// Mark as depreciated.
|
||||||
|
// m_Angle does not define the arc anymore
|
||||||
// m_Angle must be >= -360 and <= +360 degrees
|
// m_Angle must be >= -360 and <= +360 degrees
|
||||||
m_Angle = NormalizeAngle360Max( aAngle );
|
m_Angle = NormalizeAngle360Max( aAngle );
|
||||||
|
m_ThirdPoint = m_End;
|
||||||
|
RotatePoint( &m_ThirdPoint, m_Start, -m_Angle );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,7 @@ protected:
|
||||||
int m_Width; ///< thickness of lines ...
|
int m_Width; ///< thickness of lines ...
|
||||||
wxPoint m_Start; ///< Line start point or Circle and Arc center
|
wxPoint m_Start; ///< Line start point or Circle and Arc center
|
||||||
wxPoint m_End; ///< Line end point or circle and arc start point
|
wxPoint m_End; ///< Line end point or circle and arc start point
|
||||||
|
wxPoint m_ThirdPoint; ///< Used only for Arcs: arc end point
|
||||||
|
|
||||||
STROKE_T m_Shape; ///< Shape: line, Circle, Arc
|
STROKE_T m_Shape; ///< Shape: line, Circle, Arc
|
||||||
int m_Type; ///< Used in complex associations ( Dimensions.. )
|
int m_Type; ///< Used in complex associations ( Dimensions.. )
|
||||||
|
@ -148,6 +149,17 @@ public:
|
||||||
void SetEndY( int y ) { m_End.y = y; }
|
void SetEndY( int y ) { m_End.y = y; }
|
||||||
void SetEndX( int x ) { m_End.x = x; }
|
void SetEndX( int x ) { m_End.x = x; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function GetThirdPoint
|
||||||
|
* returns the third point point of the graphic
|
||||||
|
*/
|
||||||
|
const wxPoint& GetThirdPoint() const { return m_ThirdPoint; }
|
||||||
|
int GetThirdPointY() { return m_ThirdPoint.y; }
|
||||||
|
int GetThirdPointX() { return m_ThirdPoint.x; }
|
||||||
|
void SetThirdPoint( const wxPoint& aPoint ) { m_ThirdPoint = aPoint; }
|
||||||
|
void SetThirdPointY( int y ) { m_ThirdPoint.y = y; }
|
||||||
|
void SetThirdPointX( int x ) { m_ThirdPoint.x = x; }
|
||||||
|
|
||||||
// Some attributes are read only, since they are "calculated" from
|
// Some attributes are read only, since they are "calculated" from
|
||||||
// m_Start, m_End, and m_Angle.
|
// m_Start, m_End, and m_Angle.
|
||||||
// No Set...() function for these attributes.
|
// No Set...() function for these attributes.
|
||||||
|
@ -164,6 +176,12 @@ public:
|
||||||
*/
|
*/
|
||||||
double GetArcAngleStart() const;
|
double GetArcAngleStart() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* function GetArcAngleEnd()
|
||||||
|
* @return the angle of the ending point of this arc, between 0 and 3600 in 0.1 deg
|
||||||
|
*/
|
||||||
|
double GetArcAngleEnd() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function GetRadius
|
* Function GetRadius
|
||||||
* returns the radius of this item
|
* returns the radius of this item
|
||||||
|
@ -184,6 +202,13 @@ public:
|
||||||
void SetArcStart( const wxPoint& aArcStartPoint )
|
void SetArcStart( const wxPoint& aArcStartPoint )
|
||||||
{ m_End = aArcStartPoint; }
|
{ m_End = aArcStartPoint; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the start arc point. can be used for circles
|
||||||
|
* to initialize one point of the cicumference
|
||||||
|
*/
|
||||||
|
void SetArcEnd( const wxPoint& aArcEndPoint )
|
||||||
|
{ m_ThirdPoint = aArcEndPoint; }
|
||||||
|
|
||||||
/** For arcs and circles:
|
/** For arcs and circles:
|
||||||
*/
|
*/
|
||||||
void SetCenter( const wxPoint& aCenterPoint ) { m_Start = aCenterPoint; }
|
void SetCenter( const wxPoint& aCenterPoint ) { m_Start = aCenterPoint; }
|
||||||
|
|
|
@ -967,9 +967,9 @@ void PCB_PAINTER::draw( const DRAWSEGMENT* aSegment, int aLayer )
|
||||||
|
|
||||||
case S_ARC:
|
case S_ARC:
|
||||||
m_gal->DrawArcSegment( start, aSegment->GetRadius(),
|
m_gal->DrawArcSegment( start, aSegment->GetRadius(),
|
||||||
DECIDEG2RAD( aSegment->GetArcAngleStart() ),
|
DECIDEG2RAD( aSegment->GetArcAngleStart() ),
|
||||||
DECIDEG2RAD( aSegment->GetArcAngleStart() + aSegment->GetAngle() ),
|
DECIDEG2RAD( aSegment->GetArcAngleStart() + aSegment->GetAngle() ), // Change this
|
||||||
thickness );
|
thickness );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case S_CIRCLE:
|
case S_CIRCLE:
|
||||||
|
|
|
@ -1258,6 +1258,9 @@ static void updateArcFromConstructionMgr( const KIGFX::PREVIEW::ARC_GEOM_MANAGER
|
||||||
aArc.SetArcStart( { vec.x, vec.y } );
|
aArc.SetArcStart( { vec.x, vec.y } );
|
||||||
|
|
||||||
aArc.SetAngle( RAD2DECIDEG( -aMgr.GetSubtended() ) );
|
aArc.SetAngle( RAD2DECIDEG( -aMgr.GetSubtended() ) );
|
||||||
|
|
||||||
|
vec = aMgr.GetEndRadiusEnd();
|
||||||
|
aArc.SetArcEnd( { vec.x, vec.y } );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
|
#include <advanced_config.h>
|
||||||
#include <tool/tool_manager.h>
|
#include <tool/tool_manager.h>
|
||||||
#include <view/view_controls.h>
|
#include <view/view_controls.h>
|
||||||
#include <gal/graphics_abstraction_layer.h>
|
#include <gal/graphics_abstraction_layer.h>
|
||||||
|
@ -541,28 +542,251 @@ void POINT_EDITOR::updateItem() const
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
const VECTOR2I& cursorPos = getViewControls()->GetCursorPosition();
|
||||||
|
VECTOR2I oldCenter = segment->GetCenter();
|
||||||
|
double newAngle;
|
||||||
|
bool clockwise;
|
||||||
|
|
||||||
if( mid != segment->GetArcMid() )
|
if( mid != segment->GetArcMid() )
|
||||||
{
|
{
|
||||||
|
// This allows the user to go on the sides of the arc
|
||||||
|
mid = cursorPos;
|
||||||
|
// Find the new center
|
||||||
center = GetArcCenter( start, mid, end );
|
center = GetArcCenter( start, mid, end );
|
||||||
|
|
||||||
segment->SetCenter( wxPoint( center.x, center.y ) );
|
segment->SetCenter( wxPoint( center.x, center.y ) );
|
||||||
m_editPoints->Point( ARC_CENTER ).SetPosition( center );
|
m_editPoints->Point( ARC_CENTER ).SetPosition( center );
|
||||||
|
|
||||||
|
// Check if the new arc is CW or CCW
|
||||||
|
VECTOR2D startLine = start - center;
|
||||||
|
VECTOR2D endLine = end - center;
|
||||||
|
newAngle = RAD2DECIDEG( endLine.Angle() - startLine.Angle() );
|
||||||
|
VECTOR2D v1, v2;
|
||||||
|
v1 = start - mid;
|
||||||
|
v2 = end - mid;
|
||||||
|
double theta = RAD2DECIDEG( v1.Angle() );
|
||||||
|
RotatePoint( &( v1.x ), &( v1.y ), theta );
|
||||||
|
RotatePoint( &( v2.x ), &( v2.y ), theta );
|
||||||
|
clockwise = ( ( v1.Angle() - v2.Angle() ) > 0 );
|
||||||
|
|
||||||
|
// Normalize the angle
|
||||||
|
if( clockwise && newAngle < 0.0 )
|
||||||
|
newAngle += 3600.0;
|
||||||
|
else if( !clockwise && newAngle > 0.0 )
|
||||||
|
newAngle -= 3600.0;
|
||||||
|
|
||||||
|
// Accuracy test
|
||||||
|
// First, get the angle
|
||||||
|
VECTOR2I endTest = start;
|
||||||
|
RotatePoint( &( endTest.x ), &( endTest.y ), center.x, center.y, -newAngle );
|
||||||
|
double distance = ( endTest - end ).SquaredEuclideanNorm();
|
||||||
|
|
||||||
|
if( distance > ADVANCED_CFG::GetCfg().m_drawArcAccuracy )
|
||||||
|
{
|
||||||
|
// Cancel Everything
|
||||||
|
// If the accuracy is low, we can't draw precisely the arc.
|
||||||
|
// It may happen when the radius is *high*
|
||||||
|
segment->SetCenter( wxPoint( oldCenter.x, oldCenter.y ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
segment->SetAngle( newAngle );
|
||||||
|
segment->SetArcEnd( wxPoint( end.x, end.y ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, update the edit point position
|
||||||
|
// Express the point in a cercle-centered coordinate system.
|
||||||
|
mid = cursorPos - center;
|
||||||
|
|
||||||
|
double sqRadius = ( end - center ).SquaredEuclideanNorm();
|
||||||
|
|
||||||
|
// Special case, because the tangent would lead to +/- infinity
|
||||||
|
if( mid.x == 0 )
|
||||||
|
{
|
||||||
|
mid.y = mid.y > 0 ? sqrt( sqRadius ) : -sqrt( sqRadius );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double tan = mid.y / static_cast<double>( mid.x );
|
||||||
|
double tmp = mid.x;
|
||||||
|
// Circle : x^2 + y^2 = R ^ 2
|
||||||
|
// In this coordinate system, the angular position of the cursor is (r, theta)
|
||||||
|
// The line coming from the center of the circle is y = start.y / start.x * x
|
||||||
|
// The intersection fulfills : x^2 = R^2 / ( 1 + ( start.y / start.x ) ^ 2 )
|
||||||
|
tmp = sqrt( sqRadius
|
||||||
|
/ ( ( 1.0
|
||||||
|
+ mid.y / static_cast<double>( mid.x ) * mid.y
|
||||||
|
/ static_cast<double>( mid.x ) ) ) );
|
||||||
|
// Move to the correct quadrant
|
||||||
|
tmp = mid.x > 0 ? tmp : -tmp;
|
||||||
|
mid.y = mid.y / static_cast<double>( mid.x ) * tmp;
|
||||||
|
mid.x = tmp;
|
||||||
|
}
|
||||||
|
// Go back to the main coordinate system
|
||||||
|
mid = mid + center;
|
||||||
|
|
||||||
|
m_editPoints->Point( ARC_MID ).SetPosition( mid );
|
||||||
}
|
}
|
||||||
|
else if( ( start != segment->GetArcStart() ) || ( end != segment->GetArcEnd() ) )
|
||||||
|
{
|
||||||
|
|
||||||
segment->SetArcStart( wxPoint( start.x, start.y ) );
|
VECTOR2D startLine = start - center;
|
||||||
|
VECTOR2D endLine = end - center;
|
||||||
|
newAngle = RAD2DECIDEG( endLine.Angle() - startLine.Angle() );
|
||||||
|
|
||||||
VECTOR2D startLine = start - center;
|
VECTOR2I *p1, *p2, *p3;
|
||||||
VECTOR2D endLine = end - center;
|
|
||||||
double newAngle = RAD2DECIDEG( endLine.Angle() - startLine.Angle() );
|
|
||||||
|
|
||||||
// Adjust the new angle to (counter)clockwise setting
|
// p1 does not move, p2 does.
|
||||||
bool clockwise = ( segment->GetAngle() > 0 );
|
bool movingStart;
|
||||||
|
bool arcValid = true;
|
||||||
|
|
||||||
if( clockwise && newAngle < 0.0 )
|
if( start != segment->GetArcStart() )
|
||||||
newAngle += 3600.0;
|
{
|
||||||
else if( !clockwise && newAngle > 0.0 )
|
start = cursorPos;
|
||||||
newAngle -= 3600.0;
|
p1 = &end;
|
||||||
|
p2 = &start;
|
||||||
|
p3 = ∣
|
||||||
|
movingStart = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
end = cursorPos;
|
||||||
|
p1 = &start;
|
||||||
|
p2 = &end;
|
||||||
|
p3 = ∣
|
||||||
|
movingStart = false;
|
||||||
|
}
|
||||||
|
|
||||||
segment->SetAngle( newAngle );
|
VECTOR2D v1, v2, v3, v4;
|
||||||
|
|
||||||
|
// Move the coordinate system
|
||||||
|
v1 = *p1 - center;
|
||||||
|
v2 = *p2 - center;
|
||||||
|
v3 = *p3 - center;
|
||||||
|
|
||||||
|
VECTOR2D u1, u2, u3;
|
||||||
|
|
||||||
|
u1 = v1 / v1.EuclideanNorm();
|
||||||
|
u2 = v3 - ( u1.x * v3.x + u1.y * v3.y ) * u1;
|
||||||
|
u2 = u2 / u2.EuclideanNorm();
|
||||||
|
|
||||||
|
// [ u1, u3 ] is a base centered on the circle with:
|
||||||
|
// u1 : unit vector toward the point that does not move
|
||||||
|
// u2 : unit vector toward the mid point.
|
||||||
|
|
||||||
|
// Get vectors v1, and v2 in that coordinate system.
|
||||||
|
|
||||||
|
double det = u1.x * u2.y - u2.x * u1.y;
|
||||||
|
double tmpx = v1.x * u2.y - v1.y * u2.x;
|
||||||
|
double tmpy = -v1.x * u1.y + v1.y * u1.x;
|
||||||
|
v1.x = tmpx;
|
||||||
|
v1.y = tmpy;
|
||||||
|
v1 = v1 / det;
|
||||||
|
|
||||||
|
tmpx = v2.x * u2.y - v2.y * u2.x;
|
||||||
|
tmpy = -v2.x * u1.y + v2.y * u1.x;
|
||||||
|
v2.x = tmpx;
|
||||||
|
v2.y = tmpy;
|
||||||
|
v2 = v2 / det;
|
||||||
|
|
||||||
|
double R = v1.EuclideanNorm();
|
||||||
|
bool transformCircle = false;
|
||||||
|
bool invertY = ( v2.y < 0 );
|
||||||
|
|
||||||
|
/* p2
|
||||||
|
* X***
|
||||||
|
* ** <---- This is the arc
|
||||||
|
* y ^ **
|
||||||
|
* | R *
|
||||||
|
* | <-----------> *
|
||||||
|
* x------x------>--------x p1
|
||||||
|
* C' <----> C x
|
||||||
|
* delta
|
||||||
|
*
|
||||||
|
* p1 does not move, and the tangent at p1 remains the same.
|
||||||
|
* => The new center, C', will be on the C-p1 axis.
|
||||||
|
* p2 moves
|
||||||
|
*
|
||||||
|
* The radius of the new circle is delta + R
|
||||||
|
*
|
||||||
|
* || C' p2 || = || C' P1 ||
|
||||||
|
* is the same as :
|
||||||
|
* ( delta + p2.x ) ^ 2 + p2.y ^ 2 = ( R + delta ) ^ 2
|
||||||
|
*
|
||||||
|
* delta = ( R^2 - p2.x ^ 2 - p2.y ^2 ) / ( 2 * p2.x - 2 * R )
|
||||||
|
*
|
||||||
|
* We can use this equation for any point p2 with p2.x < R
|
||||||
|
*/
|
||||||
|
|
||||||
|
if( v2.x == R )
|
||||||
|
{
|
||||||
|
// Straight line, do nothing
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( v2.x > R )
|
||||||
|
{
|
||||||
|
// If we need to invert the curvature.
|
||||||
|
// We modify the input so we can use the same equation
|
||||||
|
transformCircle = true;
|
||||||
|
v2.x = 2 * R - v2.x;
|
||||||
|
}
|
||||||
|
// We can keep the tangent constraint.
|
||||||
|
double delta = ( R * R - v2.x * v2.x - v2.y * v2.y ) / ( 2 * v2.x - 2 * R );
|
||||||
|
|
||||||
|
// This is just to limit the radius, so nothing overflows later when drawing.
|
||||||
|
if( abs( v2.y / ( R - v2.x ) )
|
||||||
|
> ADVANCED_CFG::GetCfg().m_drawArcCenterStartEndMaxAngle )
|
||||||
|
{
|
||||||
|
arcValid = false;
|
||||||
|
}
|
||||||
|
// v4 is the new center
|
||||||
|
v4 = ( !transformCircle ) ? VECTOR2D( -delta, 0 ) :
|
||||||
|
VECTOR2D( 2 * R + delta, 0 );
|
||||||
|
|
||||||
|
clockwise = segment->GetAngle() > 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;
|
||||||
|
v4.y = tmpy;
|
||||||
|
|
||||||
|
center = v4 + center;
|
||||||
|
|
||||||
|
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 )
|
||||||
|
{
|
||||||
|
segment->SetAngle( newAngle );
|
||||||
|
segment->SetCenter( wxPoint( center.x, center.y ) );
|
||||||
|
|
||||||
|
if( movingStart )
|
||||||
|
{
|
||||||
|
segment->SetArcStart( wxPoint( start.x, start.y ) );
|
||||||
|
// Set angle computes the end point, so re-force it now.
|
||||||
|
segment->SetArcEnd( wxPoint( end.x, end.y ) );
|
||||||
|
m_editPoints->Point( ARC_START ).SetPosition( start );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
segment->SetArcEnd( wxPoint( end.x, end.y ) );
|
||||||
|
m_editPoints->Point( ARC_END ).SetPosition( end );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_editPoints->Point( ARC_CENTER ).SetPosition( center );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue