Index: trunk/src/polygon.h =================================================================== --- trunk/src/polygon.h (revision 12320) +++ trunk/src/polygon.h (revision 12321) @@ -89,6 +89,9 @@ pcb_bool pcb_poly_is_rect_in_p(pcb_coord_t, pcb_coord_t, pcb_coord_t, pcb_coord_t, pcb_poly_t *); pcb_bool pcb_poly_isects_poly(pcb_polyarea_t *, pcb_poly_t *, pcb_bool); pcb_bool pcb_pline_isect_line(pcb_pline_t *pl, pcb_coord_t lx1, pcb_coord_t ly1, pcb_coord_t lx2, pcb_coord_t ly2); +pcb_bool pcb_pline_isect_circ(pcb_pline_t *pl, pcb_coord_t cx, pcb_coord_t cy, pcb_coord_t r); /* cirlce contour crosses polyline contour */ +pcb_bool pcb_pline_embraces_circ(pcb_pline_t *pl, pcb_coord_t cx, pcb_coord_t cy, pcb_coord_t r); /* circle is within the polyline; caller must make sure they do not cross! */ +pcb_bool pcb_pline_overlaps_circ(pcb_pline_t *pl, pcb_coord_t cx, pcb_coord_t cy, pcb_coord_t r); /* circle is within or is crossing the polyline */ pcb_bool pcb_poly_morph(pcb_layer_t *, pcb_poly_t *); void pcb_poly_no_holes_dicer(pcb_poly_t * p, const pcb_box_t * clip, void (*emit) (pcb_pline_t *, void *), void *user_data); void pcb_poly_to_polygons_on_layer(pcb_data_t *, pcb_layer_t *, pcb_polyarea_t *, pcb_flag_t); Index: trunk/src/polygon1.c =================================================================== --- trunk/src/polygon1.c (revision 12320) +++ trunk/src/polygon1.c (revision 12321) @@ -54,6 +54,7 @@ #include "polyarea.h" #include "obj_common.h" #include "macro.h" +#include "box.h" #define ROUND(a) (long)((a) > 0 ? ((a) + 0.5) : ((a) - 0.5)) @@ -3234,6 +3235,124 @@ return pcb_r_search(pl->tree, &lbx, NULL, pline_isect_line_cb, &ctx, NULL) == PCB_R_DIR_CANCEL; } +/* + * pcb_pline_isect_circle() + * (C) 2017 Tibor 'Igor2' Palinkas +*/ + +typedef struct { + pcb_coord_t cx, cy, r; +} pline_isect_circ_t; + +static pcb_r_dir_t pline_isect_circ_cb(const pcb_box_t * b, void *cl) +{ + pline_isect_circ_t *ctx = (pline_isect_circ_t *)cl; + struct seg *s = (struct seg *)b; + pcb_vector_t S1, S2; + pcb_vector_t ray1, ray2; + double ox, oy, dx, dy, l; + + dx = s->v->point[0] - s->v->next->point[0]; + dy = s->v->point[1] - s->v->next->point[1]; + l = sqrt(PCB_SQUARE(dx) + PCB_SQUARE(dy)); + ox = -dy / l * (double)ctx->r; + oy = dx / l * (double)ctx->r; + + ray1[0] = ctx->cx - ox; ray1[1] = ctx->cy - oy; + ray2[0] = ctx->cx + ox; ray2[1] = ctx->cy + oy; + + if (pcb_vect_inters2(s->v->point, s->v->next->point, ray1, ray2, S1, S2)) + return PCB_R_DIR_CANCEL; /* found */ + + return PCB_R_DIR_NOT_FOUND; +} + +pcb_bool pcb_pline_isect_circ(pcb_pline_t *pl, pcb_coord_t cx, pcb_coord_t cy, pcb_coord_t r) +{ + pline_isect_circ_t ctx; + pcb_box_t cbx; + ctx.cx = cx; ctx.cy = cy; ctx.r = r; + cbx.X1 = cx - r; cbx.Y1 = cy - r; + cbx.X2 = cx + r; cbx.Y2 = cy + r; + + if (pl->tree == NULL) + pl->tree = (pcb_rtree_t *) make_edge_tree(pl); + + return pcb_r_search(pl->tree, &cbx, NULL, pline_isect_circ_cb, &ctx, NULL) == PCB_R_DIR_CANCEL; +} + + +/* + * pcb_pline_embraces_circle() + * If the circle does not intersect the polygon (the caller needs to check this) + * return whether the circle is fully within the polygon or not. + * Shoots a ray to the right from center+radius, then one to the left from + * center-radius; if both ray cross odd number of pline segments, we are in + * (or intersecting). + * (C) 2017 Tibor 'Igor2' Palinkas +*/ +static pcb_r_dir_t pline_embraces_circ_cb(const pcb_box_t * b, void *cl) +{ + int *cnt = (int *)cl; + (*cnt)++; + return PCB_R_DIR_NOT_FOUND; +} + +pcb_bool pcb_pline_embraces_circ(pcb_pline_t *pl, pcb_coord_t cx, pcb_coord_t cy, pcb_coord_t r) +{ + pcb_box_t bx; + int cnt; + + bx.Y1 = cy; bx.Y2 = cy+1; + if (pl->tree == NULL) + pl->tree = (pcb_rtree_t *) make_edge_tree(pl); + + /* ray to the right */ + bx.X1 = cx + r; + bx.X2 = COORD_MAX; + cnt = 0; + pcb_r_search(pl->tree, &bx, NULL, pline_embraces_circ_cb, &cnt, NULL); + if ((cnt % 2) == 0) + return pcb_false; + + /* ray to the right */ + bx.X1 = cx - r; + bx.X2 = -COORD_MAX; + cnt = 0; + pcb_r_search(pl->tree, &bx, NULL, pline_embraces_circ_cb, &cnt, NULL); + if ((cnt % 2) == 0) + return pcb_false; + + return pcb_true; +} + +/* + * pcb_pline_isect_circle() + * (C) 2017 Tibor 'Igor2' Palinkas +*/ +pcb_bool pcb_pline_overlaps_circ(pcb_pline_t *pl, pcb_coord_t cx, pcb_coord_t cy, pcb_coord_t r) +{ + pcb_box_t cbx, pbx; + cbx.X1 = cx - r; cbx.Y1 = cy - r; + cbx.X2 = cx + r; cbx.Y2 = cy + r; + pbx.X1 = pl->xmin; pbx.Y1 = pl->ymin; + pbx.X2 = pl->xmax; pbx.Y2 = pl->ymax; + + /* if there's no overlap in bounding boxes, don't do any expensive calc */ + if (!(pcb_box_intersect(&cbx, &pbx))) + return pcb_false; + + if (pl->tree == NULL) + pl->tree = (pcb_rtree_t *) make_edge_tree(pl); + + if (pcb_pline_isect_circ(pl, cx, cy, r)) + return pcb_true; + + return pcb_pline_embraces_circ(pl, cx, cy, r); +} + + + /* how about expanding polygons so that edges can be arcs rather than * lines. Consider using the third coordinate to store the radius of the * arc. The arc would pass through the vertex points. Positive radius