Segmentize an arc.
255{
261 int p2_side = 0;
263 double radius;
264 double increment;
265 double angle_shift = 0;
266 double a1, a2, a3;
269 int points_added = 0;
270 int reverse = 0;
271 int segments = 0;
272
273 LWDEBUG(2,
"lwarc_linearize called.");
274
275 LWDEBUGF(2,
" curve is CIRCULARSTRING(%.15g %.15f, %.15f %.15f, %.15f %15f)",
276 t1->
x, t1->
y, t2->
x, t2->
y, t3->
x, t3->
y);
277
279
280 LWDEBUGF(2,
" p2 side is %d", p2_side);
281
282
284 {
285
290 p2_side = 1;
291 reverse = 1;
292 }
293
295 LWDEBUGF(2,
" center is POINT(%.15g %.15g) - radius:%g", center.
x, center.
y, radius);
296
297
298 if ( p1->
x == p3->
x && p1->
y == p3->
y )
300
301
302 if ( (radius < 0.0 || p2_side == 0) && ! is_circle )
303 return 0;
304
305
306
307 if ( p2_side == -1 )
309 else
311
312
313
314 switch(tolerance_type)
315 {
318 break;
321 break;
324 break;
325 default:
326 lwerror(
"lwarc_linearize: unsupported tolerance type %d", tolerance_type);
327 return -1;
328 }
329
330 if (increment < 0)
331 {
332
333
334
335 return -1;
336 }
337
338
339 a1 = atan2(p1->
y - center.
y, p1->
x - center.
x);
340 a2 = atan2(p2->
y - center.
y, p2->
x - center.
x);
341 a3 = atan2(p3->
y - center.
y, p3->
x - center.
x);
342
343 LWDEBUGF(2,
"lwarc_linearize A1:%g (%g) A2:%g (%g) A3:%g (%g)",
344 a1, a1*180/M_PI, a2, a2*180/M_PI, a3, a3*180/M_PI);
345
346
347 double total_angle = clockwise ? a1 - a3 : a3 - a1;
348 if ( total_angle <= 0 ) total_angle += M_PI * 2;
349
350
351
352
353
354 int min_segs = is_circle ? 3 : 2;
355 segments = ceil(total_angle / increment);
356 if (segments < min_segs)
357 {
358 segments = min_segs;
359 increment = total_angle / min_segs;
360 }
361
363 {
364 LWDEBUGF(2,
"lwarc_linearize SYMMETRIC requested - total angle %g deg", total_angle * 180 / M_PI);
365
367 {
368
369 segments = trunc(total_angle / increment);
370
371
372
373
374 double angle_remainder = total_angle - (increment * segments);
375
376
377
378
379 angle_shift = angle_remainder / 2.0;
380
382 "lwarc_linearize RETAIN_ANGLE operation requested - "
383 "total angle %g, steps %d, increment %g, remainder %g",
384 total_angle * 180 / M_PI,
385 segments,
386 increment * 180 / M_PI,
387 angle_remainder * 180 / M_PI);
388 }
389 else
390 {
391
392 segments = ceil(total_angle / increment);
393
394 increment = total_angle / segments;
395
397 "lwarc_linearize SYMMETRIC operation requested - "
398 "total angle %g degrees - LINESTRING(%g %g,%g %g,%g %g) - S:%d - I:%g",
399 total_angle * 180 / M_PI,
406 segments,
407 increment * 180 / M_PI);
408 }
409 }
410
411
412 if ( clockwise )
413 {
414 LWDEBUG(2,
" Clockwise sweep");
415 increment *= -1;
416 angle_shift *= -1;
417
418 if ( a3 > a1 )
419 a3 -= 2.0 * M_PI;
420 if ( a2 > a1 )
421 a2 -= 2.0 * M_PI;
422 }
423
424 else
425 {
426 LWDEBUG(2,
" Counterclockwise sweep");
427
428 if ( a3 < a1 )
429 a3 += 2.0 * M_PI;
430 if ( a2 < a1 )
431 a2 += 2.0 * M_PI;
432 }
433
434
435 if( is_circle )
436 {
437 increment = fabs(increment);
438 segments = ceil(total_angle / increment);
439 if (segments < 3)
440 {
441 segments = 3;
442 increment = total_angle / 3;
443 }
444 a3 = a1 + 2.0 * M_PI;
445 a2 = a1 + M_PI;
447 angle_shift = 0.0;
448 }
449
450 LWDEBUGF(2,
"lwarc_linearize angle_shift:%g, increment:%g",
451 angle_shift * 180/M_PI, increment * 180/M_PI);
452
453 if ( reverse )
454 {
455
456
457 const int capacity = 8;
459 }
460 else
461 {
462
463
464 pa = to;
465
467 ++points_added;
468 }
469
470
471 int seg_start = 1;
472 int seg_end = segments;
473 if (angle_shift != 0.0)
474 {
475
476
477 seg_start = 0;
478 seg_end = segments + 1;
479 }
480 LWDEBUGF(2,
"a1:%g (%g deg), a3:%g (%g deg), inc:%g, shi:%g, cw:%d",
481 a1, a1 * 180 / M_PI, a3, a3 * 180 / M_PI, increment, angle_shift, clockwise);
482 for (
int s = seg_start;
s < seg_end;
s++)
483 {
484 double angle = a1 + increment *
s + angle_shift;
485 LWDEBUGF(2,
" SA: %g ( %g deg )", angle, angle*180/M_PI);
486 pt.
x = center.
x + radius * cos(angle);
487 pt.
y = center.
y + radius * sin(angle);
491 ++points_added;
492 }
493
494
495 if ( is_circle )
496 {
499 }
500
501 if ( reverse )
502 {
503 int i;
505 for ( i=pa->
npoints; i>0; i-- ) {
508 }
510 }
511
512 return points_added;
513}
int ptarray_remove_point(POINTARRAY *pa, uint32_t where)
Remove a point from an existing POINTARRAY.
@ LW_LINEARIZE_TOLERANCE_TYPE_MAX_ANGLE
Tolerance expresses the maximum angle between the radii generating approximation line vertices,...
@ LW_LINEARIZE_TOLERANCE_TYPE_SEGS_PER_QUAD
Tolerance expresses the number of segments to use for each quarter of circle (quadrant).
@ LW_LINEARIZE_TOLERANCE_TYPE_MAX_DEVIATION
Tolerance expresses the maximum distance between an arbitrary point on the curve and the closest poin...
POINTARRAY * ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
Create a new POINTARRAY with no points.
@ LW_LINEARIZE_FLAG_SYMMETRIC
Symmetric linearization means that the output vertices would be the same no matter the order of the p...
@ LW_LINEARIZE_FLAG_RETAIN_ANGLE
Retain angle instructs the engine to try its best to retain the requested angle between generating ra...
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *point)
void ptarray_free(POINTARRAY *pa)
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,...
#define LW_TRUE
Return types for functions with status returns.
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.
int ptarray_has_z(const POINTARRAY *pa)
int lw_segment_side(const POINT2D *p1, const POINT2D *p2, const POINT2D *q)
lw_segment_side()
int ptarray_has_m(const POINTARRAY *pa)
#define LWDEBUG(level, msg)
#define LWDEBUGF(level, msg,...)
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
static double angle_increment_using_max_deviation(double max_deviation, double radius)
static double interpolate_arc(double angle, double a1, double a2, double a3, double zm1, double zm2, double zm3)
static double angle_increment_using_segments_per_quad(double tol)
static double angle_increment_using_max_angle(double tol)