[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [kig] /: - Introducing oriented circles to help avoid jumping points
From: Maurizio Paolini <paolini () dmf ! unicatt ! it>
Date: 2016-04-03 20:59:58
Message-ID: E1amp7m-0006fP-SZ () scm ! kde ! org
[Download RAW message or body]
Git commit e11d2061b9dd57e85813ab8f5288b8f778149496 by Maurizio Paolini.
Committed on 23/03/2016 at 14:07.
Pushed by paolini into branch 'master'.
- Introducing oriented circles to help avoid jumping points
- Allow for a circle degenerating into a line for CircleCircleIntersection
- Allow for oriented arcs (similarly to oriented circles)
- Treat the case of a circle that degenerates into a line in circle-line intersection,
also the case of both circles that degenerate to a line for a circle-circle intersection
comparison with machine epsilon is changed to much larger value, using isSingular
M +2 -2 misc/builtin_stuff.cc
M +2 -1 misc/common.cpp
M +123 -0 objects/arc_type.cc
M +20 -0 objects/arc_type.h
M +11 -6 objects/circle_imp.cc
M +4 -0 objects/circle_imp.h
M +132 -2 objects/circle_type.cc
M +17 -0 objects/circle_type.h
M +64 -2 objects/intersection_types.cc
M +18 -13 objects/other_imp.cc
M +4 -0 objects/other_imp.h
http://commits.kde.org/kig/e11d2061b9dd57e85813ab8f5288b8f778149496
diff --git a/misc/builtin_stuff.cc b/misc/builtin_stuff.cc
index e1de877..5e475b3 100644
--- a/misc/builtin_stuff.cc
+++ b/misc/builtin_stuff.cc
@@ -117,7 +117,7 @@ void setupBuiltinStuff()
actions->add( new ConstructibleAction( c, "objects_new_circlebcp", Qt::Key_C ) );
c = new SimpleObjectTypeConstructor(
- CircleBTPType::instance(), I18N_NOOP( "Circle by Three Points" ),
+ CircleBTPoType::instance(), I18N_NOOP( "Circle by Three Points" ),
I18N_NOOP( "A circle constructed through three points" ),
"circlebtp" );
ctors->add( c );
@@ -327,7 +327,7 @@ void setupBuiltinStuff()
actions->add( new ConstructibleAction( c, "objects_new_halflinebyvector", 0 ) );
c = new SimpleObjectTypeConstructor(
- ArcBTPType::instance(),
+ ArcBTPoType::instance(),
I18N_NOOP( "Arc by Three Points" ),
I18N_NOOP( "Construct an arc through three points." ),
"arc" );
diff --git a/misc/common.cpp b/misc/common.cpp
index 2e1fac9..3d95e8a 100644
--- a/misc/common.cpp
+++ b/misc/common.cpp
@@ -366,7 +366,8 @@ const Coordinate calcCenter(
double b2 = xao*xao + yao*yao;
double numerator = (xdo * yao - xao * ydo);
- if ( numerator == 0 )
+ /* mp: note that we should never compare with zero due to floating-point arithmetic */
+ if ( isSingular (xdo, ydo, xao, yao) )
{
// problem: xdo * yao == xao * ydo <=> xdo/ydo == xao / yao
// this means that the lines ac and ab have the same direction,
diff --git a/objects/arc_type.cc b/objects/arc_type.cc
index 26c05cc..82892be 100644
--- a/objects/arc_type.cc
+++ b/objects/arc_type.cc
@@ -156,6 +156,129 @@ const ObjectImpType* ArcBTPType::resultId() const
return ArcImp::stype();
}
+/* oriented arc by three points */
+
+static const ArgsParser::spec argsspecArcBTPo[] =
+{
+ { PointImp::stype(), constructarcstartingstat,
+ I18N_NOOP( "Select the start point of the new arc..." ), true },
+ { PointImp::stype(), I18N_NOOP( "Construct an arc through this point" ),
+ I18N_NOOP( "Select a point for the new arc to go through..." ), true },
+ { PointImp::stype(), I18N_NOOP( "Construct an arc ending at this point" ),
+ I18N_NOOP( "Select the end point of the new arc..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ArcBTPoType )
+
+ArcBTPoType::ArcBTPoType()
+ : ArgsParserObjectType( "ArcBTPo", argsspecArcBTPo, 3 )
+{
+}
+
+ArcBTPoType::~ArcBTPoType()
+{
+}
+
+const ArcBTPoType* ArcBTPoType::instance()
+{
+ static const ArcBTPoType t;
+ return &t;
+}
+
+ObjectImp* ArcBTPoType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args, 2 ) )
+ return new InvalidImp;
+
+ const Coordinate a =
+ static_cast<const PointImp*>( args[0] )->coordinate();
+ const Coordinate b =
+ static_cast<const PointImp*>( args[1] )->coordinate();
+ Coordinate center;
+ double angle = 0.;
+ double startangle = 0.;
+ int orientation = 1;
+ if ( args.size() == 3 )
+ {
+ Coordinate c = static_cast<const PointImp*>( args[2] )->coordinate();
+ center = calcCenter( a, b, c );
+ if ( ! center.valid() )
+ {
+/* TODO: return correctly oriented segment! */
+ if ( fabs( a.x - c.x ) > fabs( a.y - c.y ) )
+ {
+ if ( ( b.x - a.x)*(c.x - b.x) > 1e-12 ) return new SegmentImp(a, c);
+ } else
+ {
+ if ( ( b.y - a.y)*(c.y - b.y) > 1e-12 ) return new SegmentImp(a, c);
+ }
+ return new InvalidImp;
+ }
+ /* this is also done in calcCenter... should optimize in some way */
+ double xdo = b.x-a.x;
+ double ydo = b.y-a.y;
+
+ double xao = c.x-a.x;
+ double yao = c.y-a.y;
+
+ if ( xdo * yao - xao * ydo < 0.0 ) orientation = -1;
+
+ Coordinate ad = a - center;
+ Coordinate bd = b - center;
+ Coordinate cd = c - center;
+ double anglea = atan2( ad.y, ad.x );
+ double angleb = atan2( bd.y, bd.x );
+ double anglec = atan2( cd.y, cd.x );
+
+ // anglea should be smaller than anglec
+ if ( anglea > anglec )
+ {
+ double t = anglea;
+ anglea = anglec;
+ anglec = t;
+ };
+ if ( angleb > anglec || angleb < anglea )
+ {
+ startangle = anglec;
+ angle = 2 * M_PI + anglea - startangle;
+ }
+ else
+ {
+ startangle = anglea;
+ angle = anglec - anglea;
+ };
+ }
+ else
+ {
+ // find a center and angles that look natural..
+ center = (b+a)/2 + .6*(b-a).orthogonal();
+ Coordinate bd = b - center;
+ Coordinate ad = a - center;
+ startangle = atan2( ad.y, ad.x );
+ double halfangle = atan2( bd.y, bd.x ) - startangle;
+ if ( halfangle < - M_PI ) halfangle += 2*M_PI;
+ angle = 2 * halfangle;
+ };
+
+ double radius = ( a - center ).length();
+ return new ArcImp( center, orientation*radius, startangle, angle );
+}
+
+const ObjectImpType* ArcBTPoType::impRequirement( const ObjectImp*, const Args& ) const
+{
+ return PointImp::stype();
+}
+
+bool ArcBTPoType::inherits( int type ) const
+{
+ return Parent::inherits( type );
+}
+
+const ObjectImpType* ArcBTPoType::resultId() const
+{
+ return ArcImp::stype();
+}
+
/*
* arc by center, starting point and angle
*/
diff --git a/objects/arc_type.h b/objects/arc_type.h
index a9a7296..0238651 100644
--- a/objects/arc_type.h
+++ b/objects/arc_type.h
@@ -42,6 +42,26 @@ public:
};
/**
+ * an arc by a start point, an intermediate point and an end point
+ */
+class ArcBTPoType
+ : public ArgsParserObjectType
+{
+ typedef ArgsParserObjectType Parent;
+ ArcBTPoType();
+ ~ArcBTPoType();
+public:
+ static const ArcBTPoType* instance();
+
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+
+ const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const;
+
+ bool inherits( int type ) const;
+ const ObjectImpType* resultId() const;
+};
+
+/**
* an arc by a point (center), a starting point and an angle
*/
class ArcBCPAType
diff --git a/objects/circle_imp.cc b/objects/circle_imp.cc
index 7450ef6..9923c56 100644
--- a/objects/circle_imp.cc
+++ b/objects/circle_imp.cc
@@ -59,12 +59,12 @@ ObjectImp* CircleImp::transform( const Transformation& t ) const
void CircleImp::draw( KigPainter& p ) const
{
- p.drawCircle( mcenter, mradius );
+ p.drawCircle( mcenter, fabs( mradius ) );
}
bool CircleImp::contains( const Coordinate& p, int width, const KigWidget& w ) const
{
- return fabs((mcenter - p).length() - mradius) <= w.screenInfo().normalMiss( width );
+ return fabs((mcenter - p).length() - fabs( mradius )) <= w.screenInfo().normalMiss( width );
}
bool CircleImp::inRect( const Rect& r, int width, const KigWidget& w ) const
@@ -78,9 +78,9 @@ bool CircleImp::inRect( const Rect& r, int width, const KigWidget& w ) const
// we allow a miss of some pixels ..
double miss = w.screenInfo().normalMiss( width );
- double bigradius = mradius + miss;
+ double bigradius = fabs( mradius ) + miss;
bigradius *= bigradius;
- double smallradius = mradius - miss;
+ double smallradius = fabs( mradius ) - miss;
smallradius *= smallradius;
const int in = -1;
@@ -212,7 +212,12 @@ const Coordinate CircleImp::center() const
double CircleImp::radius() const
{
- return mradius;
+ return fabs( mradius );
+}
+
+double CircleImp::orientation() const
+{
+ return (mradius > 0)?1:(-1);
}
double CircleImp::surface() const
@@ -369,6 +374,6 @@ bool CircleImp::isPropertyDefinedOnOrThroughThisImp( int which ) const
Rect CircleImp::surroundingRect() const
{
- Coordinate d( mradius, mradius );
+ Coordinate d( fabs( mradius ), fabs( mradius ) );
return Rect( mcenter - d, mcenter + d );
}
diff --git a/objects/circle_imp.h b/objects/circle_imp.h
index dc63e06..0b1c4c8 100644
--- a/objects/circle_imp.h
+++ b/objects/circle_imp.h
@@ -74,6 +74,10 @@ public:
*/
double radius() const;
/**
+ * Return the orientation of this circle.
+ */
+ double orientation() const;
+ /**
* Return the square radius of this circle. Use this in preference
* to sqr( radius() ).
*/
diff --git a/objects/circle_type.cc b/objects/circle_type.cc
index 25ec233..ae221a8 100644
--- a/objects/circle_type.cc
+++ b/objects/circle_type.cc
@@ -130,8 +130,7 @@ ObjectImp* CircleBTPType::calc( const Args& args, const KigDocument& ) const
};
const Coordinate center = calcCenter( a, b, c );
- if ( center.valid() )
- return new CircleImp( center, (center - a ).length() );
+ if ( center.valid() ) return new CircleImp( center, (center - a ).length() );
/*
* case of collinear points, we need to identify the intermediate one
@@ -176,6 +175,132 @@ ObjectImp* CircleBTPType::calc( const Args& args, const KigDocument& ) const
return new LineImp( a, c );
}
+const CircleBTPoType* CircleBTPoType::instance()
+{
+ static const CircleBTPoType t;
+ return &t;
+}
+
+static const ArgsParser::spec argsspecCircleBTPo[] =
+{
+ { PointImp::stype(), constructcirclethroughpointstat,
+ I18N_NOOP( "Select a point for the new circle to go through..." ), true },
+ { PointImp::stype(), constructcirclethroughpointstat,
+ I18N_NOOP( "Select a point for the new circle to go through..." ), true },
+ { PointImp::stype(), constructcirclethroughpointstat,
+ I18N_NOOP( "Select a point for the new circle to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CircleBTPoType )
+
+CircleBTPoType::CircleBTPoType()
+ : ArgsParserObjectType( "CircleBTPo", argsspecCircleBTPo, 3 )
+{
+}
+
+CircleBTPoType::~CircleBTPoType()
+{
+}
+
+ObjectImp* CircleBTPoType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args, 2 ) ) return new InvalidImp;
+
+ const Coordinate a = static_cast<const PointImp*>( args[0] )->coordinate();
+ const Coordinate b = static_cast<const PointImp*>( args[1] )->coordinate();
+ Coordinate c;
+ if ( args.size() == 3 )
+ c = static_cast<const PointImp*>( args[2] )->coordinate();
+ else
+ {
+ // we pick the third point so that the three points form a
+ // triangle with equal sides...
+
+ // midpoint:
+ Coordinate m = ( b + a ) / 2;
+ if ( b.y != a.y )
+ {
+ // direction of the perpend:
+ double d = -(b.x-a.x)/(b.y-a.y);
+
+ // length:
+ // sqrt( 3 ) == tan( 60 ° ) == sqrt( 2^2 - 1^2 )
+ double l = 1.73205080756 * (a-b).length() / 2;
+
+ double d2 = d*d;
+ double l2 = l*l;
+ double dx = sqrt( l2 / ( d2 + 1 ) );
+ double dy = sqrt( l2 * d2 / ( d2 + 1 ) );
+ if( d < 0 ) dy = -dy;
+
+ c.x = m.x + dx;
+ c.y = m.y + dy;
+ }
+ else
+ {
+ c.x = m.x;
+ c.y = m.y + ( a.x - b.x );
+ };
+ };
+
+ const Coordinate center = calcCenter( a, b, c );
+ if ( center.valid() )
+ {
+ /* this is also done in calcCenter... should optimize in some way */
+ double xdo = b.x-a.x;
+ double ydo = b.y-a.y;
+
+ double xao = c.x-a.x;
+ double yao = c.y-a.y;
+
+ double determinant = (xdo * yao - xao * ydo);
+ if (determinant > 0) return new CircleImp( center, (center - a ).length() );
+ else return new CircleImp( center, -(center - a ).length() );
+ }
+
+ /*
+ * case of collinear points, we need to identify the intermediate one
+ */
+
+ double xmin = fmin( a.x, fmin( b.x, c.x) );
+ double xmax = fmax( a.x, fmax( b.x, c.x) );
+ double ymin = fmin( a.y, fmin( b.y, c.y) );
+ double ymax = fmax( a.y, fmax( b.y, c.y) );
+ double d, axy, bxy, cxy;
+
+ /* decide whether to work with x coordinate or y coordinate */
+
+ if ( xmax - xmin > ymax - ymin )
+ {
+ axy = a.x;
+ bxy = b.x;
+ cxy = c.x;
+ d = xmax - xmin;
+ } else
+ {
+ axy = a.y;
+ bxy = b.y;
+ cxy = c.y;
+ d = ymax - ymin;
+ }
+
+ if ( fabs( axy - cxy ) >= d ) // b between a and c
+ return new LineImp( a, c );
+ if ( fabs( cxy - bxy ) >= d ) // a between c and b
+ return new LineImp( c, b );
+
+ // otherwise: c between b and a
+ return new LineImp( b, a);
+
+ /*
+ * mp: note that the orientation of the new line is from a to c
+ * if b is intermediate, otherwise it is reversed whenever
+ * two of the three points cross each-other.
+ * This should give consistent results when intersecting circles that
+ * degenerate into lines
+ */
+}
+
const ObjectImpType* CircleBCPType::resultId() const
{
return CircleImp::stype();
@@ -186,6 +311,11 @@ const ObjectImpType* CircleBTPType::resultId() const
return CircleImp::stype();
}
+const ObjectImpType* CircleBTPoType::resultId() const
+{
+ return CircleImp::stype();
+}
+
static const ArgsParser::spec argsspecCircleBPR[] =
{
{ PointImp::stype(), constructcirclewithcenterstat,
diff --git a/objects/circle_type.h b/objects/circle_type.h
index 37cf400..33e2ff8 100644
--- a/objects/circle_type.h
+++ b/objects/circle_type.h
@@ -66,4 +66,21 @@ public:
const ObjectImpType* resultId() const;
};
+/**
+ * Circle by three points (with orientation)
+ */
+class CircleBTPoType
+ : public ArgsParserObjectType
+{
+ CircleBTPoType();
+ ~CircleBTPoType();
+
+public:
+ static const CircleBTPoType* instance();
+
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+
#endif
diff --git a/objects/intersection_types.cc b/objects/intersection_types.cc
index 2fd07be..e818ae9 100644
--- a/objects/intersection_types.cc
+++ b/objects/intersection_types.cc
@@ -57,6 +57,32 @@ const ConicLineIntersectionType* ConicLineIntersectionType::instance()
ObjectImp* ConicLineIntersectionType::calc( const Args& parents, const KigDocument& doc ) const
{
+ /*
+ * special case of a circle that degenerates into a line. This is possible e.g. for
+ * circles by three points when the points get aligned.
+ */
+ if ( parents.size() == 3 && parents[0]->inherits( AbstractLineImp::stype() ) &&
+ parents[1]->inherits( AbstractLineImp::stype() ) &&
+ parents[2]->inherits( IntImp::stype() ) )
+ {
+ int side = static_cast<const IntImp*>( parents[2] )->data();
+ assert( side == 1 || side == -1 );
+ const LineData degline = static_cast<const AbstractLineImp*>( parents[0] )->data();
+ const LineData line = static_cast<const AbstractLineImp*>( parents[1] )->data();
+ const double vecprod = degline.dir().y * line.dir().x - degline.dir().x * line.dir().y;
+ /*
+ * mp: In this case only one of the two points must be valid (the other is "pushed"
+ * to infinity). The choice of which one is done such that we avoid abrupt points exchange
+ * when dinamically movint points
+ */
+ if (side*vecprod < 0)
+ {
+ Coordinate p = calcIntersectionPoint( degline, line );
+ return new PointImp( p );
+ }
+ return new InvalidImp();
+ }
+
if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
int side = static_cast<const IntImp*>( parents[2] )->data();
@@ -70,7 +96,7 @@ ObjectImp* ConicLineIntersectionType::calc( const Args& parents, const KigDocume
// easy case..
const CircleImp* c = static_cast<const CircleImp*>( parents[0] );
ret = calcCircleLineIntersect(
- c->center(), c->squareRadius(), line, side );
+ c->center(), c->squareRadius(), line, c->orientation()*side );
}
else
{
@@ -493,6 +519,41 @@ const CircleCircleIntersectionType* CircleCircleIntersectionType::instance()
ObjectImp* CircleCircleIntersectionType::calc( const Args& parents, const KigDocument& ) const
{
+ if ( parents.size() == 3 &&
+ ( parents[0]->inherits( LineImp::stype() ) || parents[1]->inherits( LineImp::stype() ) ) &&
+ parents[2]->inherits( IntImp::stype() ) )
+ {
+ /* This the special case when one or both circles degenerate into a line
+ */
+ int il = 0;
+ int ori = 1;
+ if ( parents[1]->inherits( LineImp::stype() ) ) { il = 1; ori = -1; }
+ const LineData line = static_cast<const AbstractLineImp*>( parents[il] )->data();
+ int side = static_cast<const IntImp*>( parents[2] )->data();
+ assert( side == 1 || side == -1 );
+ if ( parents[1 - il]->inherits( CircleImp::stype() ) )
+ {
+ const CircleImp* c = static_cast<const CircleImp*>( parents[1 - il] );
+ const Coordinate o = c->center();
+ const double rsq = c->squareRadius();
+ ori *= c->orientation();
+ Coordinate ret = calcCircleLineIntersect( o, rsq, line, ori*side );
+ if ( ret.valid() ) return new PointImp( ret );
+ else return new InvalidImp;
+ } else {
+ // same code as for ConicLineIntersection with degenerate conic
+ assert (il == 1);
+ const LineData degline = static_cast<const AbstractLineImp*>( parents[0] )->data();
+ const double vecprod = degline.dir().y * line.dir().x - degline.dir().x * line.dir().y;
+ if (side*vecprod > 0)
+ {
+ Coordinate p = calcIntersectionPoint( degline, line );
+ return new PointImp( p );
+ }
+ return new InvalidImp();
+ }
+ }
+
if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
int side = static_cast<const IntImp*>( parents[2] )->data();
@@ -501,12 +562,13 @@ ObjectImp* CircleCircleIntersectionType::calc( const Args& parents, const KigDoc
const CircleImp* c2 = static_cast<const CircleImp*>( parents[1] );
const Coordinate o1 = c1->center();
const Coordinate o2 = c2->center();
+ const int ori = ( c1->orientation()*c2->orientation() < 0 )?(-1):(1);
const double r1sq = c1->squareRadius();
const Coordinate a = calcCircleRadicalStartPoint(
o1, o2, r1sq, c2->squareRadius()
);
const LineData line = LineData (a, Coordinate ( a.x -o2.y + o1.y, a.y + o2.x - o1.x ));
- Coordinate ret = calcCircleLineIntersect( o1, r1sq, line, side );
+ Coordinate ret = calcCircleLineIntersect( o1, r1sq, line, ori*side );
if ( ret.valid() ) return new PointImp( ret );
else return new InvalidImp;
}
diff --git a/objects/other_imp.cc b/objects/other_imp.cc
index d773196..7bc143e 100644
--- a/objects/other_imp.cc
+++ b/objects/other_imp.cc
@@ -346,7 +346,7 @@ ObjectImp* ArcImp::transform( const Transformation& t ) const
if ( ! t.isHomothetic() )
{
//CircleImp support = CircleImp( mcenter, mradius );
- ConicCartesianData data = CircleImp( mcenter, mradius ).cartesianData();
+ ConicCartesianData data = CircleImp( mcenter, fabs( mradius ) ).cartesianData();
//return new InvalidImp();
ConicArcImp conicarc = ConicArcImp( data, msa, ma );
return conicarc.transform ( t );
@@ -373,7 +373,7 @@ ObjectImp* ArcImp::transform( const Transformation& t ) const
void ArcImp::draw( KigPainter& p ) const
{
- p.drawArc( mcenter, mradius, msa, ma );
+ p.drawArc( mcenter, fabs( mradius ), msa, ma );
}
bool ArcImp::contains( const Coordinate& p, int width, const KigWidget& w ) const
@@ -467,7 +467,7 @@ ObjectImp* ArcImp::property( int which, const KigDocument& d ) const
else if ( which == Parent::numberOfProperties() + numprop++ )
return new PointImp( mcenter );
else if ( which == Parent::numberOfProperties() + numprop++ )
- return new DoubleImp( mradius );
+ return new DoubleImp( fabs( mradius ) );
else if ( which == Parent::numberOfProperties() + numprop++ )
return new AngleImp( mcenter, msa, ma, false );
else if ( which == Parent::numberOfProperties() + numprop++ )
@@ -477,7 +477,7 @@ ObjectImp* ArcImp::property( int which, const KigDocument& d ) const
else if ( which == Parent::numberOfProperties() + numprop++ )
return new DoubleImp( sectorSurface() );
else if ( which == Parent::numberOfProperties() + numprop++ )
- return new DoubleImp( mradius * ma );
+ return new DoubleImp( fabs( mradius ) * ma );
else if ( which == Parent::numberOfProperties() + numprop++ )
return new CircleImp( mcenter, mradius );
else if ( which == Parent::numberOfProperties() + numprop++ )
@@ -523,7 +523,7 @@ double ArcImp::getParam( const Coordinate& c, const KigDocument& ) const
const Coordinate ArcImp::getPoint( double p, const KigDocument& ) const
{
double angle = msa + p * ma;
- Coordinate d = Coordinate( cos( angle ), sin( angle ) ) * mradius;
+ Coordinate d = Coordinate( cos( angle ), sin( angle ) ) * fabs( mradius );
return mcenter + d;
}
@@ -534,7 +534,12 @@ const Coordinate ArcImp::center() const
double ArcImp::radius() const
{
- return mradius;
+ return fabs( mradius );
+}
+
+double ArcImp::orientation() const
+{
+ return ( mradius >= 0)?1:(-1);
}
double ArcImp::startAngle() const
@@ -550,13 +555,13 @@ double ArcImp::angle() const
Coordinate ArcImp::firstEndPoint() const
{
double angle = msa;
- return mcenter + Coordinate( cos( angle ), sin( angle ) ) * mradius;
+ return mcenter + Coordinate( cos( angle ), sin( angle ) ) * fabs( mradius );
}
Coordinate ArcImp::secondEndPoint() const
{
double angle = msa + ma;
- return mcenter + Coordinate( cos( angle ), sin( angle ) ) * mradius;
+ return mcenter + Coordinate( cos( angle ), sin( angle ) ) * fabs( mradius );
}
const Coordinate VectorImp::a() const
@@ -663,7 +668,7 @@ bool ArcImp::containsPoint( const Coordinate& p, const KigDocument& ) const
bool ArcImp::internalContainsPoint( const Coordinate& p, double threshold ) const
{
- return isOnArc( p, mcenter, mradius, msa, ma, threshold );
+ return isOnArc( p, mcenter, fabs( mradius ), msa, ma, threshold );
}
bool AngleImp::isPropertyDefinedOnOrThroughThisImp( int which ) const
@@ -724,13 +729,13 @@ Rect ArcImp::surroundingRect() const
// points, and all extreme x and y positions in between.
//Rect ret( mcenter, 0, 0 );
double a = msa;
- //ret.setContains( mcenter + mradius*Coordinate( cos( a ), sin( a ) ) );
- Rect ret ( mcenter + mradius*Coordinate( cos( a ), sin( a ) ), 0, 0 );
+ //ret.setContains( mcenter + fabs( mradius )*Coordinate( cos( a ), sin( a ) ) );
+ Rect ret ( mcenter + fabs( mradius )*Coordinate( cos( a ), sin( a ) ), 0, 0 );
a = msa + ma;
- ret.setContains( mcenter + mradius*Coordinate( cos( a ), sin( a ) ) );
+ ret.setContains( mcenter + fabs( mradius )*Coordinate( cos( a ), sin( a ) ) );
for ( a = -2*M_PI; a <= 2*M_PI; a+=M_PI/2 )
{
- Coordinate d = mcenter + mradius*Coordinate( cos( a ), sin( a ) );
+ Coordinate d = mcenter + fabs( mradius )*Coordinate( cos( a ), sin( a ) );
if ( msa <= a && a <= msa + ma )
ret.setContains( d );
}
diff --git a/objects/other_imp.h b/objects/other_imp.h
index 31feda6..17b7261 100644
--- a/objects/other_imp.h
+++ b/objects/other_imp.h
@@ -220,6 +220,10 @@ public:
*/
double radius() const;
/**
+ * Return the orientation of this arc (usually > 0)
+ */
+ double orientation() const;
+ /**
* Return the start angle in radians of this arc.
*/
double startAngle() const;
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic