Segmentize an arc.
148 double angle_shift = 0;
149 double a1, a2, a3, angle;
152 int points_added = 0;
155 LWDEBUG(2,
"lwarc_linearize called.");
157 LWDEBUGF(2,
" curve is CIRCULARSTRING(%.15g %.15f, %.15f %.15f, %.15f %15f)",
158 t1->
x, t1->
y, t2->
x, t2->
y, t3->
x, t3->
y);
162 LWDEBUGF(2,
" p2 side is %d", p2_side);
177 LWDEBUGF(2,
" center is POINT(%.15g %.15g) - radius:%g", center.
x, center.
y, radius);
180 if ( p1->
x == p3->
x && p1->
y == p3->
y )
184 if ( (radius < 0.0 || p2_side == 0) && ! is_circle )
196 int perQuad = rint(tol);
198 if ( perQuad != tol )
200 lwerror(
"lwarc_linearize: segments per quadrant must be an integer value, got %.15g", tol, perQuad);
205 lwerror(
"lwarc_linearize: segments per quadrant must be at least 1, got %d", perQuad);
208 increment = fabs(M_PI_2 / perQuad);
209 LWDEBUGF(2,
"lwarc_linearize: perQuad:%d, increment:%g (%g degrees)", perQuad, increment, increment*180/M_PI);
214 double halfAngle, maxErr;
217 lwerror(
"lwarc_linearize: max deviation must be bigger than 0, got %.15g", tol);
246 if ( maxErr > radius * 2 )
249 LWDEBUGF(2,
"lwarc_linearize: tolerance %g is too big, " 250 "using arc-max 2 * radius == %g", tol, maxErr);
253 halfAngle = acos( 1.0 - maxErr / radius );
256 if ( halfAngle != 0 )
break;
257 LWDEBUGF(2,
"lwarc_linearize: tolerance %g is too small for this arc" 258 " to compute approximation angle, doubling it", maxErr);
261 increment = 2 * halfAngle;
262 LWDEBUGF(2,
"lwarc_linearize: maxDiff:%g, radius:%g, halfAngle:%g, increment:%g (%g degrees)", tol, radius, halfAngle, increment, increment*180/M_PI);
267 if ( increment <= 0 )
269 lwerror(
"lwarc_linearize: max angle must be bigger than 0, got %.15g", tol);
275 lwerror(
"lwarc_linearize: unsupported tolerance type %d", tolerance_type);
280 a1 = atan2(p1->
y - center.
y, p1->
x - center.
x);
281 a2 = atan2(p2->
y - center.
y, p2->
x - center.
x);
282 a3 = atan2(p3->
y - center.
y, p3->
x - center.
x);
284 LWDEBUGF(2,
"lwarc_linearize A1:%g (%g) A2:%g (%g) A3:%g (%g)",
285 a1, a1*180/M_PI, a2, a2*180/M_PI, a3, a3*180/M_PI);
287 if ( flags & LW_LINEARIZE_FLAG_SYMMETRIC )
290 double angle = clockwise ? a1 - a3 : a3 - a1;
291 if ( angle < 0 ) angle += M_PI * 2;
292 LWDEBUGF(2,
"lwarc_linearize SYMMETRIC requested - total angle %g deg",
297 int steps = trunc(angle / increment);
299 double angle_reminder = angle - ( increment * steps );
300 angle_shift = angle_reminder / 2.0;
302 LWDEBUGF(2,
"lwarc_linearize RETAIN_ANGLE operation requested - " 303 "total angle %g, steps %d, increment %g, reminder %g",
304 angle * 180 / M_PI, steps, increment * 180 / M_PI,
305 angle_reminder * 180 / M_PI);
310 int segs = ceil(angle / increment);
312 increment = angle/segs;
314 LWDEBUGF(2,
"lwarc_linearize SYMMETRIC operation requested - " 315 "total angle %g degrees - LINESTRING(%g %g,%g %g,%g %g) - S:%d - I:%g",
316 angle*180/M_PI, p1->
x, p1->
y, center.
x, center.
y, p3->
x, p3->
y,
317 segs, increment*180/M_PI);
324 LWDEBUG(2,
" Clockwise sweep");
336 LWDEBUG(2,
" Counterclockwise sweep");
347 increment = fabs(increment);
348 a3 = a1 + 2.0 * M_PI;
353 LWDEBUGF(2,
"lwarc_linearize angle_shift:%g, increment:%g",
354 angle_shift * 180/M_PI, increment * 180/M_PI);
357 const int capacity = 8;
367 if ( angle_shift ) angle_shift -= increment;
368 LWDEBUGF(2,
"a1:%g (%g deg), a3:%g (%g deg), inc:%g, shi:%g, cw:%d",
369 a1, a1 * 180 / M_PI, a3, a3 * 180 / M_PI, increment, angle_shift, clockwise);
370 for ( angle = a1 + increment + angle_shift; clockwise ? angle > a3 : angle < a3; angle += increment )
372 LWDEBUGF(2,
" SA: %g ( %g deg )", angle, angle*180/M_PI);
373 pt.
x = center.
x + radius * cos(angle);
374 pt.
y = center.
y + radius * sin(angle);
393 for ( i=pa->
npoints; i>0; i-- ) {
double lw_arc_center(const POINT2D *p1, const POINT2D *p2, const POINT2D *p3, POINT2D *result)
Determines the center of the circle defined by the three given points.
Tolerance expresses the maximum angle between the radii generating approximation line vertices...
POINTARRAY * ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
Create a new POINTARRAY with no points.
void ptarray_free(POINTARRAY *pa)
#define LWDEBUG(level, msg)
Tolerance expresses the maximum distance between an arbitrary point on the curve and the closest poin...
int ptarray_append_point(POINTARRAY *pa, const POINT4D *pt, int allow_duplicates)
Append a point to the end of an existing POINTARRAY If allow_duplicate is LW_FALSE, then a duplicate point will not be added.
#define LW_TRUE
Return types for functions with status returns.
static double interpolate_arc(double angle, double a1, double a2, double a3, double zm1, double zm2, double zm3)
Symmetric linearization means that the output vertices would be the same no matter the order of the p...
Tolerance expresses the number of segments to use for each quarter of circle (quadrant).
int ptarray_has_m(const POINTARRAY *pa)
int ptarray_remove_point(POINTARRAY *pa, int where)
Remove a point from an existing POINTARRAY.
Retain angle instructs the engine to try its best to retain the requested angle between generating ra...
int ptarray_has_z(const POINTARRAY *pa)
int lw_segment_side(const POINT2D *p1, const POINT2D *p2, const POINT2D *q)
lw_segment_side()
#define LWDEBUGF(level, msg,...)
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
int getPoint4d_p(const POINTARRAY *pa, int n, POINT4D *point)