31 #ifndef _SVG_ELLIPTICAL_ARC_H_
32 #define _SVG_ELLIPTICAL_ARC_H_
48 double _rx,
double _ry,
49 bool _large_arc,
bool _sweep,
50 double _rot_angle = 0.0
52 : m_initial_point(_initial_point), m_final_point(_final_point),
53 m_rx(_rx), m_ry(_ry), m_rot_angle(_rot_angle),
54 m_large_arc(_large_arc), m_sweep(_sweep)
56 assert( (ray(X) >= 0) && (ray(Y) >= 0) );
57 if ( are_near(initialPoint(), finalPoint()) )
59 m_start_angle = m_end_angle = 0;
60 m_center = initialPoint();
64 calculate_center_and_extreme_angles();
67 std::cerr <<
"start_angle: " <<
decimal_round(rad_to_deg(m_start_angle),2) <<
" ( " << m_start_angle <<
" )" << std::endl
68 <<
"end_angle: " <<
decimal_round(rad_to_deg(m_end_angle),2) <<
" ( " << m_end_angle <<
" )" << std::endl
69 <<
"center: " << m_center << std::endl;
73 double center(Geom::Dim2 i)
const
83 Point initialPoint()
const
85 return m_initial_point;
88 Point finalPoint()
const
93 double start_angle()
const
98 double end_angle()
const
103 double ray(Geom::Dim2 i)
const
105 return (i == 0) ? m_rx : m_ry;
108 bool large_arc_flag()
const
118 bool sweep_flag()
const
128 double rotation_angle()
const
133 void setInitial(
const Point _point)
135 m_initial_point = _point;
136 calculate_center_and_extreme_angles();
139 void setFinal(
const Point _point)
141 m_final_point = _point;
142 calculate_center_and_extreme_angles();
145 void setExtremes(
const Point& _initial_point,
const Point& _final_point )
147 m_initial_point = _initial_point;
148 m_final_point = _final_point;
149 calculate_center_and_extreme_angles();
152 bool isDegenerate()
const
154 return are_near(initialPoint(), finalPoint());
157 double valueAt(
Coord t, Dim2 d)
const
159 Coord tt = from_01_to_02PI(t);
160 double sin_rot_angle = std::sin(rotation_angle());
161 double cos_rot_angle = std::cos(rotation_angle());
164 return ray(X) * cos_rot_angle * std::cos(tt)
165 - ray(Y) * sin_rot_angle * std::sin(tt)
170 return ray(X) * sin_rot_angle * std::cos(tt)
171 + ray(Y) * cos_rot_angle * std::sin(tt)
178 Coord tt = from_01_to_02PI(t);
179 double sin_rot_angle = std::sin(rotation_angle());
180 double cos_rot_angle = std::cos(rotation_angle());
181 Matrix m( ray(X) * cos_rot_angle, ray(X) * sin_rot_angle,
182 -ray(Y) * sin_rot_angle, ray(Y) * cos_rot_angle,
183 center(X), center(Y) );
184 Point p( std::cos(tt), std::sin(tt) );
191 Coord et = start_angle() + ( sweep_flag() ? sweep_angle() : -sweep_angle() );
192 Linear param(start_angle(), et);
194 Coord cos_rot_angle = std::cos(rotation_angle());
195 Coord sin_rot_angle = std::sin(rotation_angle());
199 SBasis arc_x = ray(X) * cos(param,4);
200 SBasis arc_y = ray(Y) * sin(param,4);
202 arc[0] = arc_x * cos_rot_angle - arc_y * sin_rot_angle +
Linear(center(X),center(X));
203 arc[1] = arc_x * sin_rot_angle + arc_y * cos_rot_angle + Linear(center(Y),center(Y));
207 std::pair<EllipticalArc, EllipticalArc>
208 subdivide(
Coord t)
const
212 assert( arc1 != NULL && arc2 != NULL);
213 std::pair<EllipticalArc, EllipticalArc> arc_pair(*arc1, *arc2);
221 static const double M_2PI = 2*M_PI;
223 arc->m_initial_point = pointAt(f);
224 arc->m_final_point = pointAt(t);
227 double sa = sweep_angle();
229 arc->m_start_angle = m_start_angle + sa * f;
230 if ( arc->m_start_angle > M_2PI || are_near(arc->m_start_angle, M_2PI) )
231 arc->m_start_angle -= M_2PI;
232 arc->m_end_angle = m_start_angle + sa * t;
233 if ( arc->m_end_angle > M_2PI || are_near(arc->m_end_angle, M_2PI) )
234 arc->m_end_angle -= M_2PI;
238 if (f > t) arc->m_sweep = !m_sweep;
239 if ( m_large_arc && (arc->sweep_angle() < M_PI) )
240 arc->m_large_arc =
false;
248 rarc->m_sweep = !m_sweep;
249 rarc->m_initial_point = m_final_point;
250 rarc->m_final_point = m_initial_point;
251 rarc->m_start_angle = m_end_angle;
252 rarc->m_end_angle = m_start_angle;
258 double sweep_angle()
const
260 Coord d = end_angle() - start_angle();
261 if ( !sweep_flag() ) d = -d;
262 if ( d < 0 || are_near(d, 0) )
271 Coord angle = start_angle() + sweep_angle() * t;
272 if ( (angle > 2*M_PI) || are_near(angle, 2*M_PI) )
278 Coord angle = start_angle() - sweep_angle() * t;
279 if ( angle < 0 ) angle += 2*M_PI;
285 void calculate_center_and_extreme_angles()
287 const double M_HALF_PI = M_PI/2;
288 const double M_2PI = 2*M_PI;
290 double sin_rot_angle = std::sin(rotation_angle());
291 double cos_rot_angle = std::cos(rotation_angle());
293 Point sp = sweep_flag() ? initialPoint() : finalPoint();
294 Point ep = sweep_flag() ? finalPoint() : initialPoint();
296 Matrix m( ray(X) * cos_rot_angle, ray(X) * sin_rot_angle,
297 -ray(Y) * sin_rot_angle, ray(Y) * cos_rot_angle,
300 Point sol = (ep - sp) * im;
301 std::cerr <<
"sol : " << sol << std::endl;
302 double half_sum_angle = std::atan2(-sol[X], sol[Y]);
303 double half_diff_angle;
304 if ( are_near(std::fabs(half_sum_angle), M_HALF_PI) )
306 double anti_sgn_hsa = (half_sum_angle > 0) ? -1 : 1;
307 double arg = anti_sgn_hsa * sol[X] / 2;
309 if ( are_near(arg, 1) )
311 else if ( are_near(arg, -1) )
312 half_diff_angle = M_PI;
315 assert( -1 < arg && arg < 1 );
317 half_diff_angle = std::acos( arg );
320 half_diff_angle = M_HALF_PI - half_diff_angle;
324 double arg = sol[Y] / ( 2 * std::cos(half_sum_angle) );
326 if ( are_near(arg, 1) )
327 half_diff_angle = M_HALF_PI;
328 else if ( are_near(arg, -1) )
329 half_diff_angle = -M_HALF_PI;
332 assert( -1 < arg && arg < 1 );
334 half_diff_angle = std::asin( arg );
337 std::cerr <<
"half_sum_angle : " <<
decimal_round(rad_to_deg(half_sum_angle),2) <<
" ( " << half_sum_angle <<
" )" << std::endl;
338 std::cerr <<
"half_diff_angle : " <<
decimal_round(rad_to_deg(half_diff_angle),2) <<
" ( " << half_diff_angle <<
" )" << std::endl;
342 if ( ( m_large_arc && half_diff_angle > 0 )
343 || (!m_large_arc && half_diff_angle < 0 ) )
345 half_diff_angle = -half_diff_angle;
347 if ( half_sum_angle < 0 ) half_sum_angle += M_2PI;
348 if ( half_diff_angle < 0 ) half_diff_angle += M_PI;
349 std::cerr <<
"half_sum_angle : " <<
decimal_round(rad_to_deg(half_sum_angle),2) <<
" ( " << half_sum_angle <<
" )" << std::endl;
350 std::cerr <<
"half_diff_angle : " <<
decimal_round(rad_to_deg(half_diff_angle),2) <<
" ( " << half_diff_angle <<
" )" << std::endl;
352 m_start_angle = half_sum_angle - half_diff_angle;
353 m_end_angle = half_sum_angle + half_diff_angle;
355 if ( m_start_angle < 0 ) m_start_angle += M_2PI;
356 if ( m_end_angle > M_2PI || are_near(m_end_angle, M_2PI) ) m_end_angle -= M_2PI;
357 sol[0] = std::cos(m_start_angle);
358 sol[1] = std::sin(m_start_angle);
359 m_center = sp - sol * m;
362 double angle = m_start_angle;
363 m_start_angle = m_end_angle;
369 Point m_initial_point, m_final_point;
370 double m_rx, m_ry, m_rot_angle;
371 bool m_large_arc, m_sweep;
373 double m_start_angle, m_end_angle;
double decimal_round(double const x, int const places)
Definition: utils.h:73
Definition: svg-elliptical-arc.h:44
double Coord
Definition: coord.h:45
Various trigoniometric helper functions.
Matrix inverse() const
Definition: matrix.cpp:174
Cartesian point.
Definition: point.h:20
Definition: concepts.h:43