1 // Arc.cpp
2 
3 // Copyright 2011, Dan Heeks
4 // This program is released under the BSD license. See the file COPYING for details.
5 
6 #include "Arc.h"
7 #include "Curve.h"
8 
SetDirWithPoint(const Point & p)9 void CArc::SetDirWithPoint(const Point& p)
10 {
11 	double angs = atan2(m_s.y - m_c.y, m_s.x - m_c.x);
12 	double ange = atan2(m_e.y - m_c.y, m_e.x - m_c.x);
13 	double angp = atan2(p.y - m_c.y, p.x - m_c.x);
14 	if(ange < angs)ange += 6.2831853071795864;
15 	if(angp < angs - 0.0000000000001)angp += 6.2831853071795864;
16 	if(angp > ange + 0.0000000000001)m_dir = false;
17 	else m_dir = true;
18 }
19 
IncludedAngle() const20 double CArc::IncludedAngle()const
21 {
22 	double angs = atan2(m_s.y - m_c.y, m_s.x - m_c.x);
23 	double ange = atan2(m_e.y - m_c.y, m_e.x - m_c.x);
24 	if(m_dir)
25 	{
26 		// make sure ange > angs
27 		if(ange < angs)ange += 6.2831853071795864;
28 	}
29 	else
30 	{
31 		// make sure angs > ange
32 		if(angs < ange)angs += 6.2831853071795864;
33 	}
34 
35 	return fabs(ange - angs);
36 }
37 
AlmostALine(double accuracy) const38 bool CArc::AlmostALine(double accuracy)const
39 {
40 	Point mid_point = MidParam(0.5);
41 	if(Line2d(m_s, m_e - m_s).Dist(mid_point) <= accuracy)
42 		return true;
43 
44 	const double max_arc_radius = 1.0 / geoff_geometry::TOLERANCE;
45 	double radius = m_c.dist(m_s);
46 	if (radius > max_arc_radius)
47 	{
48 		return true;	// We don't want to produce an arc whose radius is too large.
49 	}
50 
51 	return false;
52 }
53 
MidParam(double param) const54 Point CArc::MidParam(double param)const {
55 	/// returns a point which is 0-1 along arc
56 	if(fabs(param) < 0.00000000000001)return m_s;
57 	if(fabs(param - 1.0) < 0.00000000000001)return m_e;
58 
59 	Point p;
60 	Point v = m_s - m_c;
61 	v.Rotate(param * IncludedAngle());
62 	p = v + m_c;
63 
64 	return p;
65 }
66 
67 //segments - number of segments per full revolution!
68 //d_angle - determines the direction and the ammount of the arc to draw
GetSegments(void (* callbackfunc)(const double * p),double pixels_per_mm) const69 void CArc::GetSegments(void(*callbackfunc)(const double *p), double pixels_per_mm)const
70 {
71 	if(m_s == m_e)
72 		return;
73 
74 	Point Va = m_s - m_c;
75 	Point Vb = m_e - m_c;
76 
77 	double start_angle = atan2(Va.y, Va.x);
78 	double end_angle = atan2(Vb.y, Vb.x);
79 
80 	if(m_dir)
81 	{
82 		if(start_angle > end_angle)end_angle += 6.28318530717958;
83 	}
84 	else
85 	{
86 		if(start_angle < end_angle)end_angle -= 6.28318530717958;
87 	}
88 
89 	double radius = m_c.dist(m_s);
90 	double d_angle = end_angle - start_angle;
91 	int segments = (int)(fabs(pixels_per_mm * radius * d_angle / 6.28318530717958 + 1));
92 
93     double theta = d_angle / (double)segments;
94 	while(theta>1.0){segments*=2;theta = d_angle / (double)segments;}
95     double tangetial_factor = tan(theta);
96     double radial_factor = 1 - cos(theta);
97 
98     double x = radius * cos(start_angle);
99     double y = radius * sin(start_angle);
100 
101 	double pp[3] = {0.0, 0.0, 0.0};
102 
103    for(int i = 0; i < segments + 1; i++)
104     {
105 		Point p = m_c + Point(x, y);
106 		pp[0] = p.x;
107 		pp[1] = p.y;
108 		(*callbackfunc)(pp);
109 
110         double tx = -y;
111         double ty = x;
112 
113         x += tx * tangetial_factor;
114         y += ty * tangetial_factor;
115 
116         double rx = - x;
117         double ry = - y;
118 
119         x += rx * radial_factor;
120         y += ry * radial_factor;
121     }
122 }