作図ソフト dia の改良版
修訂 | 42cde4cb7ad762284d39abb5d9de56f668c9796b (tree) |
---|---|
時間 | 2014-06-08 17:58:16 |
作者 | Hans Breuer <hans@breu...> |
Commiter | Hans Breuer |
Misc - Ngon: special handling for Hexagram and more
Drawing a crossing star take a little more points to be properly filled
if the number of rays and windings are not relatively prime. Some more
code needed to do that for {n/3} and higher.
See http://en.wikipedia.org/wiki/Star_polygon for more details.
@@ -518,6 +518,23 @@ void point_perp(Point *p, real a, real b, real c, Point *perp) { | ||
518 | 518 | return; |
519 | 519 | } |
520 | 520 | |
521 | +gboolean | |
522 | +line_line_intersection (Point *crossing, | |
523 | + const Point *p1, const Point *p2, | |
524 | + const Point *p3, const Point *p4) | |
525 | +{ | |
526 | + real d = (p1->x - p2->x) * (p3->y - p4->y) - (p1->y - p2->y) * (p3->x - p4->x); | |
527 | + real a, b; | |
528 | + | |
529 | + if (fabs(d) < 0.0000001) | |
530 | + return FALSE; | |
531 | + a = p1->x * p2->y - p1->y * p2->x; | |
532 | + b = p3->x * p4->y - p3->y * p4->x; | |
533 | + crossing->x = (a * (p3->x - p4->x) - (p1->x - p2->x) * b) / d; | |
534 | + crossing->y = (a * (p3->y - p4->y) - (p1->y - p2->y) * b) / d; | |
535 | + return TRUE; | |
536 | +} | |
537 | + | |
521 | 538 | /* Compute a circular arc fillet between lines L1 (p1 to p2) |
522 | 539 | and L2 (p3 to p4) with radius r. |
523 | 540 | The circle center is c. |
@@ -377,6 +377,9 @@ void transform_bezpoint (BezPoint *bpt, const DiaMatrix *m); | ||
377 | 377 | real dot2(Point *p1, Point *p2); |
378 | 378 | void line_coef(real *a, real *b, real *c, Point *p1, Point *p2); |
379 | 379 | real line_to_point(real a, real b , real c, Point *p); |
380 | +gboolean line_line_intersection (Point *crossing, | |
381 | + const Point *p1, const Point *p2, | |
382 | + const Point *p3, const Point *p4); | |
380 | 383 | void point_perp(Point *p, real a, real b, real c, Point *perp); |
381 | 384 | gboolean fillet(Point *p1, Point *p2, Point *p3, Point *p4, |
382 | 385 | real r, Point *c, real *pa, real *aa); |
@@ -523,6 +523,7 @@ EXPORTS | ||
523 | 523 | new_layer |
524 | 524 | |
525 | 525 | line_bbox |
526 | + line_line_intersection | |
526 | 527 | |
527 | 528 | dia_error_quark |
528 | 529 |
@@ -364,10 +364,9 @@ _ngon_make_name (Ngon *ng) | ||
364 | 364 | /*! |
365 | 365 | * \brief Sort points to produce a star with crossing edges |
366 | 366 | * |
367 | - * We could support the different possibilities explained by | |
367 | + * We support the different possibilities explained by | |
368 | 368 | * http://en.wikipedia.org/wiki/Star_polygon |
369 | - * but first need a good user interface to select between this | |
370 | - * number of point dependent selection. | |
369 | + * via the density parameter mostly. | |
371 | 370 | */ |
372 | 371 | static void |
373 | 372 | _ngon_adjust_for_crossing (Ngon *ng) |
@@ -380,10 +379,35 @@ _ngon_adjust_for_crossing (Ngon *ng) | ||
380 | 379 | g_array_insert_vals (points, 0, |
381 | 380 | &g_array_index (ng->points, Point, 0), |
382 | 381 | ng->points->len); |
383 | - for (i = 1; i < n; ++i) { | |
384 | - int j = (i * step) % n; | |
385 | - g_array_index (ng->points, Point, i).x = g_array_index (points, Point, j).x; | |
386 | - g_array_index (ng->points, Point, i).y = g_array_index (points, Point, j).y; | |
382 | + if (1 == step && n > 5 && (n % 2) == 0) { | |
383 | + /* calculate the crossing of edges as extra point */ | |
384 | + Point crossing; | |
385 | + if (!line_line_intersection (&crossing, | |
386 | + &g_array_index (points, Point, 0), &g_array_index (points, Point, n-2), | |
387 | + &g_array_index (points, Point, 1), &g_array_index (points, Point, n-1))) | |
388 | + g_warning ("No intersection?"); | |
389 | + step = 2; | |
390 | + for (i = 0; i < n/2; ++i) { | |
391 | + int j = (i * step) % n; | |
392 | + g_array_index (ng->points, Point, i).x = g_array_index (points, Point, j).x; | |
393 | + g_array_index (ng->points, Point, i).y = g_array_index (points, Point, j).y; | |
394 | + } | |
395 | + /* go backward for the second half */ | |
396 | + for (i = 0; i < n/2; ++i) { | |
397 | + int j = (n - 1 - i * step) % n; | |
398 | + g_array_index (ng->points, Point, i + n/2).x = g_array_index (points, Point, j).x; | |
399 | + g_array_index (ng->points, Point, i + n/2).y = g_array_index (points, Point, j).y; | |
400 | + } | |
401 | + /* insert the crossing point at the end */ | |
402 | + g_array_insert_val (ng->points, n, crossing); | |
403 | + /* insert the crossing point in the middle */ | |
404 | + g_array_insert_val (ng->points, n/2, crossing); | |
405 | + } else { | |
406 | + for (i = 1; i < n; ++i) { | |
407 | + int j = (i * step) % n; | |
408 | + g_array_index (ng->points, Point, i).x = g_array_index (points, Point, j).x; | |
409 | + g_array_index (ng->points, Point, i).y = g_array_index (points, Point, j).y; | |
410 | + } | |
387 | 411 | } |
388 | 412 | g_array_free (points, TRUE); |
389 | 413 | } |
@@ -405,11 +429,15 @@ _ngon_update_data (Ngon *ng) | ||
405 | 429 | n = ng->num_rays * 2; |
406 | 430 | |
407 | 431 | /* ensure density stays in range */ |
408 | - if (ng->last_density > ng->density) | |
409 | - ng->density = _calc_step (ng->num_rays, ng->density); | |
410 | - else | |
432 | + if (ng->last_density > ng->density) { | |
433 | + real temp = _calc_step (ng->num_rays, ng->density); | |
434 | + /* special case for Hexagram and above */ | |
435 | + if (temp == 1 && ng->kind == NGON_CROSSING && ng->num_rays > 5) | |
436 | + temp = 2; | |
437 | + ng->density = temp; | |
438 | + } else { | |
411 | 439 | ng->density = _calc_step_up (ng->num_rays, ng->density); |
412 | - | |
440 | + } | |
413 | 441 | _ngon_make_name (ng); |
414 | 442 | if (1 || n != ng->points->len) { |
415 | 443 | /* recalculate all points */ |