pcb 4.1.1
An interactive printed circuit board layout editor.
|
00001 00079 #ifdef HAVE_CONFIG_H 00080 #include "config.h" 00081 #endif 00082 00083 #include <assert.h> 00084 #include <math.h> 00085 #include <memory.h> 00086 #include <setjmp.h> 00087 00088 #include "global.h" 00089 #include "box.h" 00090 #include "create.h" 00091 #include "crosshair.h" 00092 #include "data.h" 00093 #include "draw.h" 00094 #include "error.h" 00095 #include "find.h" 00096 #include "misc.h" 00097 #include "move.h" 00098 #include "pcb-printf.h" 00099 #include "polygon.h" 00100 #include "remove.h" 00101 #include "rtree.h" 00102 #include "search.h" 00103 #include "set.h" 00104 #include "thermal.h" 00105 #include "undo.h" 00106 00107 #ifdef HAVE_LIBDMALLOC 00108 #include <dmalloc.h> 00109 #endif 00110 00111 #define ROUND(x) ((long)(((x) >= 0 ? (x) + 0.5 : (x) - 0.5))) 00112 00113 #define UNSUBTRACT_BLOAT 10 00114 #define SUBTRACT_PIN_VIA_BATCH_SIZE 100 00115 #define SUBTRACT_LINE_BATCH_SIZE 20 00116 00117 static double rotate_circle_seg[4]; 00118 00119 void 00120 polygon_init (void) 00121 { 00122 double cos_ang = cos (2.0 * M_PI / POLY_CIRC_SEGS_F); 00123 double sin_ang = sin (2.0 * M_PI / POLY_CIRC_SEGS_F); 00124 00125 rotate_circle_seg[0] = cos_ang; rotate_circle_seg[1] = -sin_ang; 00126 rotate_circle_seg[2] = sin_ang; rotate_circle_seg[3] = cos_ang; 00127 } 00128 00129 Cardinal 00130 polygon_point_idx (PolygonType *polygon, PointType *point) 00131 { 00132 assert (point >= polygon->Points); 00133 assert (point <= polygon->Points + polygon->PointN); 00134 return ((char *)point - (char *)polygon->Points) / sizeof (PointType); 00135 } 00136 00144 Cardinal 00145 polygon_point_contour (PolygonType *polygon, Cardinal point) 00146 { 00147 Cardinal i; 00148 Cardinal contour = 0; 00149 00150 for (i = 0; i < polygon->HoleIndexN; i++) 00151 if (point >= polygon->HoleIndex[i]) 00152 contour = i + 1; 00153 return contour; 00154 } 00155 00156 Cardinal 00157 next_contour_point (PolygonType *polygon, Cardinal point) 00158 { 00159 Cardinal contour; 00160 Cardinal this_contour_start; 00161 Cardinal next_contour_start; 00162 00163 contour = polygon_point_contour (polygon, point); 00164 00165 this_contour_start = (contour == 0) ? 0 : 00166 polygon->HoleIndex[contour - 1]; 00167 next_contour_start = 00168 (contour == polygon->HoleIndexN) ? polygon->PointN : 00169 polygon->HoleIndex[contour]; 00170 00171 /* Wrap back to the start of the contour we're in if we pass the end */ 00172 if (++point == next_contour_start) 00173 point = this_contour_start; 00174 00175 return point; 00176 } 00177 00178 Cardinal 00179 prev_contour_point (PolygonType *polygon, Cardinal point) 00180 { 00181 Cardinal contour; 00182 Cardinal prev_contour_end; 00183 Cardinal this_contour_end; 00184 00185 contour = polygon_point_contour (polygon, point); 00186 00187 prev_contour_end = (contour == 0) ? 0 : 00188 polygon->HoleIndex[contour - 1]; 00189 this_contour_end = 00190 (contour == polygon->HoleIndexN) ? polygon->PointN - 1: 00191 polygon->HoleIndex[contour] - 1; 00192 00193 /* Wrap back to the start of the contour we're in if we pass the end */ 00194 if (point == prev_contour_end) 00195 point = this_contour_end; 00196 else 00197 point--; 00198 00199 return point; 00200 } 00201 00202 static void 00203 add_noholes_polyarea (PLINE *pline, void *user_data) 00204 { 00205 PolygonType *poly = (PolygonType *)user_data; 00206 00207 /* Prepend the pline into the NoHoles linked list */ 00208 pline->next = poly->NoHoles; 00209 poly->NoHoles = pline; 00210 } 00211 00212 void 00213 ComputeNoHoles (PolygonType *poly) 00214 { 00215 poly_FreeContours (&poly->NoHoles); 00216 if (poly->Clipped) 00217 NoHolesPolygonDicer (poly, NULL, add_noholes_polyarea, poly); 00218 else 00219 printf ("Compute_noholes caught poly->Clipped = NULL\n"); 00220 poly->NoHolesValid = 1; 00221 } 00222 00223 static POLYAREA * 00224 biggest (POLYAREA * p) 00225 { 00226 POLYAREA *n, *top = NULL; 00227 PLINE *pl; 00228 rtree_t *tree; 00229 double big = -1; 00230 if (!p) 00231 return NULL; 00232 n = p; 00233 do 00234 { 00235 #if 0 00236 if (n->contours->area < PCB->IsleArea) 00237 { 00238 n->b->f = n->f; 00239 n->f->b = n->b; 00240 poly_DelContour (&n->contours); 00241 if (n == p) 00242 p = n->f; 00243 n = n->f; 00244 if (!n->contours) 00245 { 00246 free (n); 00247 return NULL; 00248 } 00249 } 00250 #endif 00251 if (n->contours->area > big) 00252 { 00253 top = n; 00254 big = n->contours->area; 00255 } 00256 } 00257 while ((n = n->f) != p); 00258 assert (top); 00259 if (top == p) 00260 return p; 00261 pl = top->contours; 00262 tree = top->contour_tree; 00263 top->contours = p->contours; 00264 top->contour_tree = p->contour_tree; 00265 p->contours = pl; 00266 p->contour_tree = tree; 00267 assert (pl); 00268 assert (p->f); 00269 assert (p->b); 00270 return p; 00271 } 00272 00273 POLYAREA * 00274 ContourToPoly (PLINE * contour) 00275 { 00276 POLYAREA *p; 00277 poly_PreContour (contour, TRUE); 00278 assert (contour->Flags.orient == PLF_DIR); 00279 if (!(p = poly_Create ())) 00280 return NULL; 00281 poly_InclContour (p, contour); 00282 assert (poly_Valid (p)); 00283 return p; 00284 } 00285 00286 static POLYAREA * 00287 original_poly (PolygonType * p) 00288 { 00289 PLINE *contour = NULL; 00290 POLYAREA *np = NULL; 00291 Cardinal n; 00292 Vector v; 00293 int hole = 0; 00294 00295 if ((np = poly_Create ()) == NULL) 00296 return NULL; 00297 00298 /* first make initial polygon contour */ 00299 for (n = 0; n < p->PointN; n++) 00300 { 00301 /* No current contour? Make a new one starting at point */ 00302 /* (or) Add point to existing contour */ 00303 00304 v[0] = p->Points[n].X; 00305 v[1] = p->Points[n].Y; 00306 if (contour == NULL) 00307 { 00308 if ((contour = poly_NewContour (v)) == NULL) 00309 return NULL; 00310 } 00311 else 00312 { 00313 poly_InclVertex (contour->head.prev, poly_CreateNode (v)); 00314 } 00315 00316 /* Is current point last in contour? If so process it. */ 00317 if (n == p->PointN - 1 || 00318 (hole < p->HoleIndexN && n == p->HoleIndex[hole] - 1)) 00319 { 00320 poly_PreContour (contour, TRUE); 00321 00322 /* make sure it is a positive contour (outer) or negative (hole) */ 00323 if (contour->Flags.orient != (hole ? PLF_INV : PLF_DIR)) 00324 poly_InvContour (contour); 00325 assert (contour->Flags.orient == (hole ? PLF_INV : PLF_DIR)); 00326 00327 poly_InclContour (np, contour); 00328 contour = NULL; 00329 assert (poly_Valid (np)); 00330 00331 hole++; 00332 } 00333 } 00334 return biggest (np); 00335 } 00336 00337 POLYAREA * 00338 PolygonToPoly (PolygonType *p) 00339 { 00340 return original_poly (p); 00341 } 00342 00343 POLYAREA * 00344 RectPoly (Coord x1, Coord x2, Coord y1, Coord y2) 00345 { 00346 PLINE *contour = NULL; 00347 Vector v; 00348 00349 /* Return NULL for zero or negatively sized rectangles */ 00350 if (x2 <= x1 || y2 <= y1) 00351 return NULL; 00352 00353 v[0] = x1; 00354 v[1] = y1; 00355 if ((contour = poly_NewContour (v)) == NULL) 00356 return NULL; 00357 v[0] = x2; 00358 v[1] = y1; 00359 poly_InclVertex (contour->head.prev, poly_CreateNode (v)); 00360 v[0] = x2; 00361 v[1] = y2; 00362 poly_InclVertex (contour->head.prev, poly_CreateNode (v)); 00363 v[0] = x1; 00364 v[1] = y2; 00365 poly_InclVertex (contour->head.prev, poly_CreateNode (v)); 00366 return ContourToPoly (contour); 00367 } 00368 00369 POLYAREA * 00370 OctagonPoly (Coord x, Coord y, Coord radius) 00371 { 00372 PLINE *contour = NULL; 00373 Vector v; 00374 00375 v[0] = x + ROUND (radius * 0.5); 00376 v[1] = y + ROUND (radius * TAN_22_5_DEGREE_2); 00377 if ((contour = poly_NewContour (v)) == NULL) 00378 return NULL; 00379 v[0] = x + ROUND (radius * TAN_22_5_DEGREE_2); 00380 v[1] = y + ROUND (radius * 0.5); 00381 poly_InclVertex (contour->head.prev, poly_CreateNode (v)); 00382 v[0] = x - (v[0] - x); 00383 poly_InclVertex (contour->head.prev, poly_CreateNode (v)); 00384 v[0] = x - ROUND (radius * 0.5); 00385 v[1] = y + ROUND (radius * TAN_22_5_DEGREE_2); 00386 poly_InclVertex (contour->head.prev, poly_CreateNode (v)); 00387 v[1] = y - (v[1] - y); 00388 poly_InclVertex (contour->head.prev, poly_CreateNode (v)); 00389 v[0] = x - ROUND (radius * TAN_22_5_DEGREE_2); 00390 v[1] = y - ROUND (radius * 0.5); 00391 poly_InclVertex (contour->head.prev, poly_CreateNode (v)); 00392 v[0] = x - (v[0] - x); 00393 poly_InclVertex (contour->head.prev, poly_CreateNode (v)); 00394 v[0] = x + ROUND (radius * 0.5); 00395 v[1] = y - ROUND (radius * TAN_22_5_DEGREE_2); 00396 poly_InclVertex (contour->head.prev, poly_CreateNode (v)); 00397 return ContourToPoly (contour); 00398 } 00399 00409 void 00410 frac_circle (PLINE * c, Coord X, Coord Y, Vector v, int fraction) 00411 { 00412 double e1, e2, t1; 00413 int i, range; 00414 00415 poly_InclVertex (c->head.prev, poly_CreateNode (v)); 00416 /* move vector to origin */ 00417 e1 = (v[0] - X) * POLY_CIRC_RADIUS_ADJ; 00418 e2 = (v[1] - Y) * POLY_CIRC_RADIUS_ADJ; 00419 00420 /* NB: the caller adds the last vertex, hence the -1 */ 00421 range = POLY_CIRC_SEGS / fraction - 1; 00422 for (i = 0; i < range; i++) 00423 { 00424 /* rotate the vector */ 00425 t1 = rotate_circle_seg[0] * e1 + rotate_circle_seg[1] * e2; 00426 e2 = rotate_circle_seg[2] * e1 + rotate_circle_seg[3] * e2; 00427 e1 = t1; 00428 v[0] = X + ROUND (e1); 00429 v[1] = Y + ROUND (e2); 00430 poly_InclVertex (c->head.prev, poly_CreateNode (v)); 00431 } 00432 } 00433 00437 POLYAREA * 00438 CirclePoly (Coord x, Coord y, Coord radius) 00439 { 00440 PLINE *contour; 00441 Vector v; 00442 00443 if (radius <= 0) 00444 return NULL; 00445 v[0] = x + radius; 00446 v[1] = y; 00447 if ((contour = poly_NewContour (v)) == NULL) 00448 return NULL; 00449 frac_circle (contour, x, y, v, 1); 00450 contour->is_round = TRUE; 00451 contour->cx = x; 00452 contour->cy = y; 00453 contour->radius = radius; 00454 return ContourToPoly (contour); 00455 } 00456 00461 POLYAREA * 00462 RoundRect (Coord x1, Coord x2, Coord y1, Coord y2, Coord t) 00463 { 00464 PLINE *contour = NULL; 00465 Vector v; 00466 00467 assert (x2 > x1); 00468 assert (y2 > y1); 00469 v[0] = x1 - t; 00470 v[1] = y1; 00471 if ((contour = poly_NewContour (v)) == NULL) 00472 return NULL; 00473 frac_circle (contour, x1, y1, v, 4); 00474 v[0] = x2; 00475 v[1] = y1 - t; 00476 poly_InclVertex (contour->head.prev, poly_CreateNode (v)); 00477 frac_circle (contour, x2, y1, v, 4); 00478 v[0] = x2 + t; 00479 v[1] = y2; 00480 poly_InclVertex (contour->head.prev, poly_CreateNode (v)); 00481 frac_circle (contour, x2, y2, v, 4); 00482 v[0] = x1; 00483 v[1] = y2 + t; 00484 poly_InclVertex (contour->head.prev, poly_CreateNode (v)); 00485 frac_circle (contour, x1, y2, v, 4); 00486 return ContourToPoly (contour); 00487 } 00488 00489 #define ARC_ANGLE 5 00490 static POLYAREA * 00491 ArcPolyNoIntersect (ArcType * a, Coord thick) 00492 { 00493 PLINE *contour = NULL; 00494 POLYAREA *np = NULL; 00495 Vector v; 00496 BoxType *ends; 00497 int i, segs; 00498 double ang, da, rx, ry; 00499 long half; 00500 double radius_adj; 00501 00502 if (thick <= 0) 00503 return NULL; 00504 if (a->Delta < 0) 00505 { 00506 a->StartAngle += a->Delta; 00507 a->Delta = -a->Delta; 00508 } 00509 half = (thick + 1) / 2; 00510 ends = GetArcEnds (a); 00511 /* start with inner radius */ 00512 rx = MAX (a->Width - half, 0); 00513 ry = MAX (a->Height - half, 0); 00514 segs = 1; 00515 if(thick > 0) 00516 segs = MAX (segs, a->Delta * M_PI / 360 * 00517 sqrt (hypot (rx, ry) / 00518 POLY_ARC_MAX_DEVIATION / 2 / thick)); 00519 segs = MAX(segs, a->Delta / ARC_ANGLE); 00520 00521 ang = a->StartAngle; 00522 da = (1.0 * a->Delta) / segs; 00523 radius_adj = (M_PI*da/360)*(M_PI*da/360)/2; 00524 v[0] = a->X - rx * cos (ang * M180); 00525 v[1] = a->Y + ry * sin (ang * M180); 00526 if ((contour = poly_NewContour (v)) == NULL) 00527 return 0; 00528 for (i = 0; i < segs - 1; i++) 00529 { 00530 ang += da; 00531 v[0] = a->X - rx * cos (ang * M180); 00532 v[1] = a->Y + ry * sin (ang * M180); 00533 poly_InclVertex (contour->head.prev, poly_CreateNode (v)); 00534 } 00535 /* find last point */ 00536 ang = a->StartAngle + a->Delta; 00537 v[0] = a->X - rx * cos (ang * M180) * (1 - radius_adj); 00538 v[1] = a->Y + ry * sin (ang * M180) * (1 - radius_adj); 00539 /* add the round cap at the end */ 00540 frac_circle (contour, ends->X2, ends->Y2, v, 2); 00541 /* and now do the outer arc (going backwards) */ 00542 rx = (a->Width + half) * (1+radius_adj); 00543 ry = (a->Width + half) * (1+radius_adj); 00544 da = -da; 00545 for (i = 0; i < segs; i++) 00546 { 00547 v[0] = a->X - rx * cos (ang * M180); 00548 v[1] = a->Y + ry * sin (ang * M180); 00549 poly_InclVertex (contour->head.prev, poly_CreateNode (v)); 00550 ang += da; 00551 } 00552 /* now add other round cap */ 00553 ang = a->StartAngle; 00554 v[0] = a->X - rx * cos (ang * M180) * (1 - radius_adj); 00555 v[1] = a->Y + ry * sin (ang * M180) * (1 - radius_adj); 00556 frac_circle (contour, ends->X1, ends->Y1, v, 2); 00557 /* now we have the whole contour */ 00558 if (!(np = ContourToPoly (contour))) 00559 return NULL; 00560 return np; 00561 } 00562 00563 #define MIN_CLEARANCE_BEFORE_BISECT 10. 00564 POLYAREA * 00565 ArcPoly (ArcType * a, Coord thick) 00566 { 00567 double delta; 00568 ArcType seg1, seg2; 00569 POLYAREA *tmp1, *tmp2, *res; 00570 00571 delta = (a->Delta < 0) ? -a->Delta : a->Delta; 00572 00573 /* If the arc segment would self-intersect, we need to construct it as the union of 00574 two non-intersecting segments */ 00575 00576 if (2 * M_PI * a->Width * (1. - (double)delta / 360.) - thick < MIN_CLEARANCE_BEFORE_BISECT) 00577 { 00578 int half_delta = a->Delta / 2; 00579 00580 seg1 = seg2 = *a; 00581 seg1.Delta = half_delta; 00582 seg2.Delta -= half_delta; 00583 seg2.StartAngle += half_delta; 00584 00585 tmp1 = ArcPolyNoIntersect (&seg1, thick); 00586 tmp2 = ArcPolyNoIntersect (&seg2, thick); 00587 poly_Boolean_free (tmp1, tmp2, &res, PBO_UNITE); 00588 return res; 00589 } 00590 00591 return ArcPolyNoIntersect (a, thick); 00592 } 00593 00594 POLYAREA * 00595 LinePoly (LineType * L, Coord thick) 00596 { 00597 PLINE *contour = NULL; 00598 POLYAREA *np = NULL; 00599 Vector v; 00600 double d, dx, dy; 00601 long half;LineType _l=*L,*l=&_l; 00602 00603 if (thick <= 0) 00604 return NULL; 00605 half = (thick + 1) / 2; 00606 d = hypot (l->Point1.X - l->Point2.X, l->Point1.Y - l->Point2.Y); 00607 if (!TEST_FLAG (SQUAREFLAG,l)) 00608 if (d == 0) /* line is a point */ 00609 return CirclePoly (l->Point1.X, l->Point1.Y, half); 00610 if (d != 0) 00611 { 00612 d = half / d; 00613 dx = (l->Point1.Y - l->Point2.Y) * d; 00614 dy = (l->Point2.X - l->Point1.X) * d; 00615 } 00616 else 00617 { 00618 dx = half; 00619 dy = 0; 00620 } 00621 if (TEST_FLAG (SQUAREFLAG,l))/* take into account the ends */ 00622 { 00623 l->Point1.X -= dy; 00624 l->Point1.Y += dx; 00625 l->Point2.X += dy; 00626 l->Point2.Y -= dx; 00627 } 00628 v[0] = l->Point1.X - dx; 00629 v[1] = l->Point1.Y - dy; 00630 if ((contour = poly_NewContour (v)) == NULL) 00631 return 0; 00632 v[0] = l->Point2.X - dx; 00633 v[1] = l->Point2.Y - dy; 00634 if (TEST_FLAG (SQUAREFLAG,l)) 00635 poly_InclVertex (contour->head.prev, poly_CreateNode (v)); 00636 else 00637 frac_circle (contour, l->Point2.X, l->Point2.Y, v, 2); 00638 v[0] = l->Point2.X + dx; 00639 v[1] = l->Point2.Y + dy; 00640 poly_InclVertex (contour->head.prev, poly_CreateNode (v)); 00641 v[0] = l->Point1.X + dx; 00642 v[1] = l->Point1.Y + dy; 00643 if (TEST_FLAG (SQUAREFLAG,l)) 00644 poly_InclVertex (contour->head.prev, poly_CreateNode (v)); 00645 else 00646 frac_circle (contour, l->Point1.X, l->Point1.Y, v, 2); 00647 /* now we have the line contour */ 00648 if (!(np = ContourToPoly (contour))) 00649 return NULL; 00650 return np; 00651 } 00652 00656 POLYAREA * 00657 SquarePadPoly (PadType * pad, Coord clear) 00658 { 00659 PLINE *contour = NULL; 00660 POLYAREA *np = NULL; 00661 Vector v; 00662 double d; 00663 double tx, ty; 00664 double cx, cy; 00665 PadType _t=*pad,*t=&_t; 00666 PadType _c=*pad,*c=&_c; 00667 int halfthick = (pad->Thickness + 1) / 2; 00668 int halfclear = (clear + 1) / 2; 00669 00670 d = hypot (pad->Point1.X - pad->Point2.X, pad->Point1.Y - pad->Point2.Y); 00671 if (d != 0) 00672 { 00673 double a = halfthick / d; 00674 tx = (t->Point1.Y - t->Point2.Y) * a; 00675 ty = (t->Point2.X - t->Point1.X) * a; 00676 a = halfclear / d; 00677 cx = (c->Point1.Y - c->Point2.Y) * a; 00678 cy = (c->Point2.X - c->Point1.X) * a; 00679 00680 t->Point1.X -= ty; 00681 t->Point1.Y += tx; 00682 t->Point2.X += ty; 00683 t->Point2.Y -= tx; 00684 c->Point1.X -= cy; 00685 c->Point1.Y += cx; 00686 c->Point2.X += cy; 00687 c->Point2.Y -= cx; 00688 } 00689 else 00690 { 00691 tx = halfthick; 00692 ty = 0; 00693 cx = halfclear; 00694 cy = 0; 00695 00696 t->Point1.Y += tx; 00697 t->Point2.Y -= tx; 00698 c->Point1.Y += cx; 00699 c->Point2.Y -= cx; 00700 } 00701 00702 v[0] = c->Point1.X - tx; 00703 v[1] = c->Point1.Y - ty; 00704 if ((contour = poly_NewContour (v)) == NULL) 00705 return 0; 00706 frac_circle (contour, (t->Point1.X - tx), (t->Point1.Y - ty), v, 4); 00707 00708 v[0] = t->Point2.X - cx; 00709 v[1] = t->Point2.Y - cy; 00710 poly_InclVertex (contour->head.prev, poly_CreateNode (v)); 00711 frac_circle (contour, (t->Point2.X - tx), (t->Point2.Y - ty), v, 4); 00712 00713 v[0] = c->Point2.X + tx; 00714 v[1] = c->Point2.Y + ty; 00715 poly_InclVertex (contour->head.prev, poly_CreateNode (v)); 00716 frac_circle (contour, (t->Point2.X + tx), (t->Point2.Y + ty), v, 4); 00717 00718 v[0] = t->Point1.X + cx; 00719 v[1] = t->Point1.Y + cy; 00720 poly_InclVertex (contour->head.prev, poly_CreateNode (v)); 00721 frac_circle (contour, (t->Point1.X + tx), (t->Point1.Y + ty), v, 4); 00722 00723 /* now we have the line contour */ 00724 if (!(np = ContourToPoly (contour))) 00725 return NULL; 00726 return np; 00727 } 00728 00732 static int 00733 Subtract (POLYAREA * np1, PolygonType * p, bool fnp) 00734 { 00735 POLYAREA *merged = NULL, *np = np1; 00736 int x; 00737 assert (np); 00738 assert (p); 00739 if (!p->Clipped) 00740 { 00741 if (fnp) 00742 poly_Free (&np); 00743 return 1; 00744 } 00745 assert (poly_Valid (p->Clipped)); 00746 assert (poly_Valid (np)); 00747 if (fnp) 00748 x = poly_Boolean_free (p->Clipped, np, &merged, PBO_SUB); 00749 else 00750 { 00751 x = poly_Boolean (p->Clipped, np, &merged, PBO_SUB); 00752 poly_Free (&p->Clipped); 00753 } 00754 assert (!merged || poly_Valid (merged)); 00755 if (x != err_ok) 00756 { 00757 fprintf (stderr, "Error while clipping PBO_SUB: %d\n", x); 00758 poly_Free (&merged); 00759 p->Clipped = NULL; 00760 if (p->NoHoles) printf ("Just leaked in Subtract\n"); 00761 p->NoHoles = NULL; 00762 return -1; 00763 } 00764 p->Clipped = biggest (merged); 00765 assert (!p->Clipped || poly_Valid (p->Clipped)); 00766 if (!p->Clipped) 00767 Message ("Polygon cleared out of existence near (%d, %d)\n", 00768 (p->BoundingBox.X1 + p->BoundingBox.X2) / 2, 00769 (p->BoundingBox.Y1 + p->BoundingBox.Y2) / 2); 00770 return 1; 00771 } 00772 00776 POLYAREA * 00777 PinPoly (PinType * pin, Coord thick, Coord clear) 00778 { 00779 int size; 00780 00781 if (TEST_FLAG (SQUAREFLAG, pin)) 00782 { 00783 size = (thick + 1) / 2; 00784 return RoundRect (pin->X - size, pin->X + size, pin->Y - size, 00785 pin->Y + size, (clear + 1) / 2); 00786 } 00787 else 00788 { 00789 size = (thick + clear + 1) / 2; 00790 if (TEST_FLAG (OCTAGONFLAG, pin)) 00791 { 00792 return OctagonPoly (pin->X, pin->Y, size + size); 00793 } 00794 } 00795 return CirclePoly (pin->X, pin->Y, size); 00796 } 00797 00798 POLYAREA * 00799 BoxPolyBloated (BoxType *box, Coord bloat) 00800 { 00801 return RectPoly (box->X1 - bloat, box->X2 + bloat, 00802 box->Y1 - bloat, box->Y2 + bloat); 00803 } 00804 00808 static int 00809 SubtractPin (DataType * d, PinType * pin, LayerType * l, PolygonType * p) 00810 { 00811 POLYAREA *np; 00812 Cardinal i; 00813 00814 if (pin->Clearance == 0) 00815 return 0; 00816 i = GetLayerNumber (d, l); 00817 if (TEST_THERM (i, pin)) 00818 { 00819 np = ThermPoly ((PCBType *) (d->pcb), pin, i); 00820 if (!np) 00821 return 0; 00822 } 00823 else 00824 { 00825 np = PinPoly (pin, PIN_SIZE (pin), pin->Clearance); 00826 if (!np) 00827 return -1; 00828 } 00829 return Subtract (np, p, TRUE); 00830 } 00831 00832 static int 00833 SubtractLine (LineType * line, PolygonType * p) 00834 { 00835 POLYAREA *np; 00836 00837 if (!TEST_FLAG (CLEARLINEFLAG, line)) 00838 return 0; 00839 if (!(np = LinePoly (line, line->Thickness + line->Clearance))) 00840 return -1; 00841 return Subtract (np, p, true); 00842 } 00843 00844 static int 00845 SubtractArc (ArcType * arc, PolygonType * p) 00846 { 00847 POLYAREA *np; 00848 00849 if (!TEST_FLAG (CLEARLINEFLAG, arc)) 00850 return 0; 00851 if (!(np = ArcPoly (arc, arc->Thickness + arc->Clearance))) 00852 return -1; 00853 return Subtract (np, p, true); 00854 } 00855 00856 static int 00857 SubtractText (TextType * text, PolygonType * p) 00858 { 00859 POLYAREA *np; 00860 const BoxType *b = &text->BoundingBox; 00861 00862 if (!TEST_FLAG (CLEARLINEFLAG, text)) 00863 return 0; 00864 if (!(np = RoundRect (b->X1 + PCB->Bloat, b->X2 - PCB->Bloat, 00865 b->Y1 + PCB->Bloat, b->Y2 - PCB->Bloat, PCB->Bloat))) 00866 return -1; 00867 return Subtract (np, p, true); 00868 } 00869 00870 static int 00871 SubtractPad (PadType * pad, PolygonType * p) 00872 { 00873 POLYAREA *np = NULL; 00874 00875 if (pad->Clearance == 0) 00876 return 0; 00877 if (TEST_FLAG (SQUAREFLAG, pad)) 00878 { 00879 if (! 00880 (np = SquarePadPoly (pad, pad->Thickness + pad->Clearance))) 00881 return -1; 00882 } 00883 else 00884 { 00885 if (! 00886 (np = LinePoly ((LineType *) pad, pad->Thickness + pad->Clearance))) 00887 return -1; 00888 } 00889 return Subtract (np, p, true); 00890 } 00891 00892 struct cpInfo 00893 { 00894 const BoxType *other; 00895 DataType *data; 00896 LayerType *layer; 00897 PolygonType *polygon; 00898 bool bottom; 00899 POLYAREA *accumulate; 00900 int batch_size; 00901 jmp_buf env; 00902 }; 00903 00904 static void 00905 subtract_accumulated (struct cpInfo *info, PolygonType *polygon) 00906 { 00907 if (info->accumulate == NULL) 00908 return; 00909 Subtract (info->accumulate, polygon, true); 00910 info->accumulate = NULL; 00911 info->batch_size = 0; 00912 } 00913 00914 static int 00915 pin_sub_callback (const BoxType * b, void *cl) 00916 { 00917 PinType *pin = (PinType *) b; 00918 struct cpInfo *info = (struct cpInfo *) cl; 00919 PolygonType *polygon; 00920 POLYAREA *np; 00921 POLYAREA *merged; 00922 Cardinal i; 00923 00924 /* don't subtract the object that was put back! */ 00925 if (b == info->other) 00926 return 0; 00927 polygon = info->polygon; 00928 00929 i = GetLayerNumber (info->data, info->layer); 00930 00931 if (VIA_IS_BURIED (pin) && (!VIA_ON_LAYER (pin, i))) 00932 return 0; 00933 00934 if (pin->Clearance == 0) 00935 return 0; 00936 if (TEST_THERM (i, pin)) 00937 { 00938 np = ThermPoly ((PCBType *) (info->data->pcb), pin, i); 00939 if (!np) 00940 return 1; 00941 } 00942 else 00943 { 00944 np = PinPoly (pin, PIN_SIZE (pin), pin->Clearance); 00945 if (!np) 00946 longjmp (info->env, 1); 00947 } 00948 00949 poly_Boolean_free (info->accumulate, np, &merged, PBO_UNITE); 00950 info->accumulate = merged; 00951 00952 info->batch_size ++; 00953 00954 if (info->batch_size == SUBTRACT_PIN_VIA_BATCH_SIZE) 00955 subtract_accumulated (info, polygon); 00956 00957 return 1; 00958 } 00959 00960 static int 00961 arc_sub_callback (const BoxType * b, void *cl) 00962 { 00963 ArcType *arc = (ArcType *) b; 00964 struct cpInfo *info = (struct cpInfo *) cl; 00965 PolygonType *polygon; 00966 00967 /* don't subtract the object that was put back! */ 00968 if (b == info->other) 00969 return 0; 00970 if (!TEST_FLAG (CLEARLINEFLAG, arc)) 00971 return 0; 00972 polygon = info->polygon; 00973 if (SubtractArc (arc, polygon) < 0) 00974 longjmp (info->env, 1); 00975 return 1; 00976 } 00977 00978 static int 00979 pad_sub_callback (const BoxType * b, void *cl) 00980 { 00981 PadType *pad = (PadType *) b; 00982 struct cpInfo *info = (struct cpInfo *) cl; 00983 PolygonType *polygon; 00984 00985 /* don't subtract the object that was put back! */ 00986 if (b == info->other) 00987 return 0; 00988 if (pad->Clearance == 0) 00989 return 0; 00990 polygon = info->polygon; 00991 if (XOR (TEST_FLAG (ONSOLDERFLAG, pad), !info->bottom)) 00992 { 00993 if (SubtractPad (pad, polygon) < 0) 00994 longjmp (info->env, 1); 00995 return 1; 00996 } 00997 return 0; 00998 } 00999 01000 static int 01001 line_sub_callback (const BoxType * b, void *cl) 01002 { 01003 LineType *line = (LineType *) b; 01004 struct cpInfo *info = (struct cpInfo *) cl; 01005 PolygonType *polygon; 01006 POLYAREA *np; 01007 POLYAREA *merged; 01008 01009 /* don't subtract the object that was put back! */ 01010 if (b == info->other) 01011 return 0; 01012 if (!TEST_FLAG (CLEARLINEFLAG, line)) 01013 return 0; 01014 polygon = info->polygon; 01015 01016 if (!(np = LinePoly (line, line->Thickness + line->Clearance))) 01017 longjmp (info->env, 1); 01018 01019 poly_Boolean_free (info->accumulate, np, &merged, PBO_UNITE); 01020 info->accumulate = merged; 01021 info->batch_size ++; 01022 01023 if (info->batch_size == SUBTRACT_LINE_BATCH_SIZE) 01024 subtract_accumulated (info, polygon); 01025 01026 return 1; 01027 } 01028 01029 static int 01030 text_sub_callback (const BoxType * b, void *cl) 01031 { 01032 TextType *text = (TextType *) b; 01033 struct cpInfo *info = (struct cpInfo *) cl; 01034 PolygonType *polygon; 01035 01036 /* don't subtract the object that was put back! */ 01037 if (b == info->other) 01038 return 0; 01039 if (!TEST_FLAG (CLEARLINEFLAG, text)) 01040 return 0; 01041 polygon = info->polygon; 01042 if (SubtractText (text, polygon) < 0) 01043 longjmp (info->env, 1); 01044 return 1; 01045 } 01046 01047 static int 01048 Group (DataType *Data, Cardinal layer) 01049 { 01050 Cardinal i, j; 01051 for (i = 0; i < max_group; i++) 01052 for (j = 0; j < ((PCBType *) (Data->pcb))->LayerGroups.Number[i]; j++) 01053 if (layer == ((PCBType *) (Data->pcb))->LayerGroups.Entries[i][j]) 01054 return i; 01055 return i; 01056 } 01057 01058 static int 01059 clearPoly (DataType *Data, LayerType *Layer, PolygonType * polygon, 01060 const BoxType * here, Coord expand) 01061 { 01062 int r = 0; 01063 BoxType region; 01064 struct cpInfo info; 01065 Cardinal group; 01066 01067 if (!TEST_FLAG (CLEARPOLYFLAG, polygon) 01068 || GetLayerNumber (Data, Layer) >= max_copper_layer) 01069 return 0; 01070 group = Group (Data, GetLayerNumber (Data, Layer)); 01071 info.bottom = (group == Group (Data, bottom_silk_layer)); 01072 info.data = Data; 01073 info.other = here; 01074 info.layer = Layer; 01075 info.polygon = polygon; 01076 if (here) 01077 region = clip_box (here, &polygon->BoundingBox); 01078 else 01079 region = polygon->BoundingBox; 01080 region = bloat_box (®ion, expand); 01081 01082 if (setjmp (info.env) == 0) 01083 { 01084 r = 0; 01085 info.accumulate = NULL; 01086 info.batch_size = 0; 01087 if (info.bottom || group == Group (Data, top_silk_layer)) 01088 r += r_search (Data->pad_tree, ®ion, NULL, pad_sub_callback, &info); 01089 GROUP_LOOP (Data, group); 01090 { 01091 r += 01092 r_search (layer->line_tree, ®ion, NULL, line_sub_callback, 01093 &info); 01094 subtract_accumulated (&info, polygon); 01095 r += 01096 r_search (layer->arc_tree, ®ion, NULL, arc_sub_callback, &info); 01097 r += 01098 r_search (layer->text_tree, ®ion, NULL, text_sub_callback, &info); 01099 } 01100 END_LOOP; 01101 r += r_search (Data->via_tree, ®ion, NULL, pin_sub_callback, &info); 01102 r += r_search (Data->pin_tree, ®ion, NULL, pin_sub_callback, &info); 01103 subtract_accumulated (&info, polygon); 01104 } 01105 polygon->NoHolesValid = 0; 01106 return r; 01107 } 01108 01109 static int 01110 Unsubtract (POLYAREA * np1, PolygonType * p) 01111 { 01112 POLYAREA *merged = NULL, *np = np1; 01113 POLYAREA *orig_poly, *clipped_np; 01114 int x; 01115 assert (np); 01116 assert (p && p->Clipped); 01117 01118 orig_poly = original_poly (p); 01119 01120 x = poly_Boolean_free (np, orig_poly, &clipped_np, PBO_ISECT); 01121 if (x != err_ok) 01122 { 01123 fprintf (stderr, "Error while clipping PBO_ISECT: %d\n", x); 01124 poly_Free (&clipped_np); 01125 goto fail; 01126 } 01127 01128 x = poly_Boolean_free (p->Clipped, clipped_np, &merged, PBO_UNITE); 01129 if (x != err_ok) 01130 { 01131 fprintf (stderr, "Error while clipping PBO_UNITE: %d\n", x); 01132 poly_Free (&merged); 01133 goto fail; 01134 } 01135 p->Clipped = biggest (merged); 01136 assert (!p->Clipped || poly_Valid (p->Clipped)); 01137 return 1; 01138 01139 fail: 01140 p->Clipped = NULL; 01141 if (p->NoHoles) printf ("Just leaked in Unsubtract\n"); 01142 p->NoHoles = NULL; 01143 return 0; 01144 } 01145 01146 static int 01147 UnsubtractPin (PinType * pin, LayerType * l, PolygonType * p) 01148 { 01149 POLYAREA *np; 01150 01151 /* overlap a bit to prevent gaps from rounding errors */ 01152 np = BoxPolyBloated (&pin->BoundingBox, UNSUBTRACT_BLOAT); 01153 01154 if (!np) 01155 return 0; 01156 if (!Unsubtract (np, p)) 01157 return 0; 01158 clearPoly (PCB->Data, l, p, (const BoxType *) pin, 2 * UNSUBTRACT_BLOAT); 01159 return 1; 01160 } 01161 01162 static int 01163 UnsubtractArc (ArcType * arc, LayerType * l, PolygonType * p) 01164 { 01165 POLYAREA *np; 01166 01167 if (!TEST_FLAG (CLEARLINEFLAG, arc)) 01168 return 0; 01169 01170 /* overlap a bit to prevent gaps from rounding errors */ 01171 np = BoxPolyBloated (&arc->BoundingBox, UNSUBTRACT_BLOAT); 01172 01173 if (!np) 01174 return 0; 01175 if (!Unsubtract (np, p)) 01176 return 0; 01177 clearPoly (PCB->Data, l, p, (const BoxType *) arc, 2 * UNSUBTRACT_BLOAT); 01178 return 1; 01179 } 01180 01181 static int 01182 UnsubtractLine (LineType * line, LayerType * l, PolygonType * p) 01183 { 01184 POLYAREA *np; 01185 01186 if (!TEST_FLAG (CLEARLINEFLAG, line)) 01187 return 0; 01188 01189 /* overlap a bit to prevent notches from rounding errors */ 01190 np = BoxPolyBloated (&line->BoundingBox, UNSUBTRACT_BLOAT); 01191 01192 if (!np) 01193 return 0; 01194 if (!Unsubtract (np, p)) 01195 return 0; 01196 clearPoly (PCB->Data, l, p, (const BoxType *) line, 2 * UNSUBTRACT_BLOAT); 01197 return 1; 01198 } 01199 01200 static int 01201 UnsubtractText (TextType * text, LayerType * l, PolygonType * p) 01202 { 01203 POLYAREA *np; 01204 01205 if (!TEST_FLAG (CLEARLINEFLAG, text)) 01206 return 0; 01207 01208 /* overlap a bit to prevent notches from rounding errors */ 01209 np = BoxPolyBloated (&text->BoundingBox, UNSUBTRACT_BLOAT); 01210 01211 if (!np) 01212 return -1; 01213 if (!Unsubtract (np, p)) 01214 return 0; 01215 clearPoly (PCB->Data, l, p, (const BoxType *) text, 2 * UNSUBTRACT_BLOAT); 01216 return 1; 01217 } 01218 01219 static int 01220 UnsubtractPad (PadType * pad, LayerType * l, PolygonType * p) 01221 { 01222 POLYAREA *np; 01223 01224 /* overlap a bit to prevent notches from rounding errors */ 01225 np = BoxPolyBloated (&pad->BoundingBox, UNSUBTRACT_BLOAT); 01226 01227 if (!np) 01228 return 0; 01229 if (!Unsubtract (np, p)) 01230 return 0; 01231 clearPoly (PCB->Data, l, p, (const BoxType *) pad, 2 * UNSUBTRACT_BLOAT); 01232 return 1; 01233 } 01234 01235 static bool inhibit = false; 01236 01237 int 01238 InitClip (DataType *Data, LayerType *layer, PolygonType * p) 01239 { 01240 if (inhibit) 01241 return 0; 01242 if (p->Clipped) 01243 poly_Free (&p->Clipped); 01244 p->Clipped = original_poly (p); 01245 poly_FreeContours (&p->NoHoles); 01246 if (!p->Clipped) 01247 return 0; 01248 assert (poly_Valid (p->Clipped)); 01249 if (TEST_FLAG (CLEARPOLYFLAG, p)) 01250 clearPoly (Data, layer, p, NULL, 0); 01251 else 01252 p->NoHolesValid = 0; 01253 return 1; 01254 } 01255 01264 bool 01265 RemoveExcessPolygonPoints (LayerType *Layer, PolygonType *Polygon) 01266 { 01267 PointType *p; 01268 Cardinal n, prev, next; 01269 LineType line; 01270 bool changed = false; 01271 01272 if (Undoing ()) 01273 return (false); 01274 01275 for (n = 0; n < Polygon->PointN; n++) 01276 { 01277 prev = prev_contour_point (Polygon, n); 01278 next = next_contour_point (Polygon, n); 01279 p = &Polygon->Points[n]; 01280 01281 line.Point1 = Polygon->Points[prev]; 01282 line.Point2 = Polygon->Points[next]; 01283 line.Thickness = 0; 01284 if (IsPointOnLine (p->X, p->Y, 0.0, &line)) 01285 { 01286 RemoveObject (POLYGONPOINT_TYPE, Layer, Polygon, p); 01287 changed = true; 01288 } 01289 } 01290 return (changed); 01291 } 01292 01299 Cardinal 01300 GetLowestDistancePolygonPoint (PolygonType *Polygon, Coord X, Coord Y) 01301 { 01302 double mindistance = (double) MAX_COORD * MAX_COORD; 01303 PointType *ptr1, *ptr2; 01304 Cardinal n, result = 0; 01305 01306 /* we calculate the distance to each segment and choose the 01307 * shortest distance. If the closest approach between the 01308 * given point and the projected line (i.e. the segment extended) 01309 * is not on the segment, then the distance is the distance 01310 * to the segment end point. 01311 */ 01312 01313 for (n = 0; n < Polygon->PointN; n++) 01314 { 01315 double u, dx, dy; 01316 ptr1 = &Polygon->Points[prev_contour_point (Polygon, n)]; 01317 ptr2 = &Polygon->Points[n]; 01318 01319 dx = ptr2->X - ptr1->X; 01320 dy = ptr2->Y - ptr1->Y; 01321 if (dx != 0.0 || dy != 0.0) 01322 { 01323 /* projected intersection is at P1 + u(P2 - P1) */ 01324 u = ((X - ptr1->X) * dx + (Y - ptr1->Y) * dy) / (dx * dx + dy * dy); 01325 01326 if (u < 0.0) 01327 { /* ptr1 is closest point */ 01328 u = SQUARE (X - ptr1->X) + SQUARE (Y - ptr1->Y); 01329 } 01330 else if (u > 1.0) 01331 { /* ptr2 is closest point */ 01332 u = SQUARE (X - ptr2->X) + SQUARE (Y - ptr2->Y); 01333 } 01334 else 01335 { /* projected intersection is closest point */ 01336 u = SQUARE (X - ptr1->X * (1.0 - u) - u * ptr2->X) + 01337 SQUARE (Y - ptr1->Y * (1.0 - u) - u * ptr2->Y); 01338 } 01339 if (u < mindistance) 01340 { 01341 mindistance = u; 01342 result = n; 01343 } 01344 } 01345 } 01346 return (result); 01347 } 01348 01352 void 01353 GoToPreviousPoint (void) 01354 { 01355 switch (Crosshair.AttachedPolygon.PointN) 01356 { 01357 /* do nothing if mode has just been entered */ 01358 case 0: 01359 break; 01360 01361 /* reset number of points and 'LINE_MODE' state */ 01362 case 1: 01363 Crosshair.AttachedPolygon.PointN = 0; 01364 Crosshair.AttachedLine.State = STATE_FIRST; 01365 addedLines = 0; 01366 break; 01367 01368 /* back-up one point */ 01369 default: 01370 { 01371 PointType *points = Crosshair.AttachedPolygon.Points; 01372 Cardinal n = Crosshair.AttachedPolygon.PointN - 2; 01373 01374 Crosshair.AttachedPolygon.PointN--; 01375 Crosshair.AttachedLine.Point1.X = points[n].X; 01376 Crosshair.AttachedLine.Point1.Y = points[n].Y; 01377 break; 01378 } 01379 } 01380 } 01381 01385 void 01386 ClosePolygon (void) 01387 { 01388 Cardinal n = Crosshair.AttachedPolygon.PointN; 01389 01390 /* check number of points */ 01391 if (n >= 3) 01392 { 01393 /* if 45 degree lines are what we want do a quick check 01394 * if closing the polygon makes sense 01395 */ 01396 if (!TEST_FLAG (ALLDIRECTIONFLAG, PCB)) 01397 { 01398 Coord dx, dy; 01399 01400 dx = abs (Crosshair.AttachedPolygon.Points[n - 1].X - 01401 Crosshair.AttachedPolygon.Points[0].X); 01402 dy = abs (Crosshair.AttachedPolygon.Points[n - 1].Y - 01403 Crosshair.AttachedPolygon.Points[0].Y); 01404 if (!(dx == 0 || dy == 0 || dx == dy)) 01405 { 01406 Message 01407 (_ 01408 ("Cannot close polygon because 45 degree lines are requested.\n")); 01409 return; 01410 } 01411 } 01412 CopyAttachedPolygonToLayer (); 01413 Draw (); 01414 } 01415 else 01416 Message (_("A polygon has to have at least 3 points\n")); 01417 } 01418 01423 void 01424 CopyAttachedPolygonToLayer (void) 01425 { 01426 PolygonType *polygon; 01427 int saveID; 01428 01429 /* move data to layer and clear attached struct */ 01430 polygon = CreateNewPolygon (CURRENT, NoFlags ()); 01431 saveID = polygon->ID; 01432 *polygon = Crosshair.AttachedPolygon; 01433 polygon->ID = saveID; 01434 SET_FLAG (CLEARPOLYFLAG, polygon); 01435 if (TEST_FLAG (NEWFULLPOLYFLAG, PCB)) 01436 SET_FLAG (FULLPOLYFLAG, polygon); 01437 memset (&Crosshair.AttachedPolygon, 0, sizeof (PolygonType)); 01438 SetPolygonBoundingBox (polygon); 01439 if (!CURRENT->polygon_tree) 01440 CURRENT->polygon_tree = r_create_tree (NULL, 0, 0); 01441 r_insert_entry (CURRENT->polygon_tree, (BoxType *) polygon, 0); 01442 InitClip (PCB->Data, CURRENT, polygon); 01443 DrawPolygon (CURRENT, polygon); 01444 SetChangedFlag (true); 01445 01446 /* reset state of attached line */ 01447 Crosshair.AttachedLine.State = STATE_FIRST; 01448 addedLines = 0; 01449 01450 /* add to undo list */ 01451 AddObjectToCreateUndoList (POLYGON_TYPE, CURRENT, polygon, polygon); 01452 IncrementUndoSerialNumber (); 01453 } 01454 01461 int 01462 PolygonHoles (PolygonType *polygon, const BoxType *range, 01463 int (*callback) (PLINE *contour, void *user_data), 01464 void *user_data) 01465 { 01466 POLYAREA *pa = polygon->Clipped; 01467 PLINE *pl; 01468 /* If this hole is so big the polygon doesn't exist, then it's not 01469 * really a hole. 01470 */ 01471 if (!pa) 01472 return 0; 01473 for (pl = pa->contours->next; pl; pl = pl->next) 01474 { 01475 if (range != NULL && 01476 (pl->xmin > range->X2 || pl->xmax < range->X1 || 01477 pl->ymin > range->Y2 || pl->ymax < range->Y1)) 01478 continue; 01479 if (callback (pl, user_data)) 01480 { 01481 return 1; 01482 } 01483 } 01484 return 0; 01485 } 01486 01487 struct plow_info 01488 { 01489 int type; 01490 void *ptr1, *ptr2; 01491 LayerType *layer; 01492 DataType *data; 01493 int (*callback) (DataType *, LayerType *, PolygonType *, int, void *, 01494 void *, void *); 01495 void *userdata; 01496 }; 01497 01498 static int 01499 subtract_plow (DataType *Data, LayerType *Layer, PolygonType *Polygon, 01500 int type, void *ptr1, void *ptr2, void *userdata) 01501 { 01502 PinType *via; 01503 int layer_n = GetLayerNumber (Data, Layer); 01504 01505 if (!Polygon->Clipped) 01506 return 0; 01507 switch (type) 01508 { 01509 case PIN_TYPE: 01510 SubtractPin (Data, (PinType *) ptr2, Layer, Polygon); 01511 Polygon->NoHolesValid = 0; 01512 return 1; 01513 case VIA_TYPE: 01514 via = (PinType *) ptr2; 01515 if (!VIA_IS_BURIED (via) || VIA_ON_LAYER (via, layer_n)) 01516 { 01517 SubtractPin (Data, via, Layer, Polygon); 01518 Polygon->NoHolesValid = 0; 01519 return 1; 01520 } 01521 break; 01522 case LINE_TYPE: 01523 SubtractLine ((LineType *) ptr2, Polygon); 01524 Polygon->NoHolesValid = 0; 01525 return 1; 01526 case ARC_TYPE: 01527 SubtractArc ((ArcType *) ptr2, Polygon); 01528 Polygon->NoHolesValid = 0; 01529 return 1; 01530 case PAD_TYPE: 01531 SubtractPad ((PadType *) ptr2, Polygon); 01532 Polygon->NoHolesValid = 0; 01533 return 1; 01534 case TEXT_TYPE: 01535 SubtractText ((TextType *) ptr2, Polygon); 01536 Polygon->NoHolesValid = 0; 01537 return 1; 01538 } 01539 return 0; 01540 } 01541 01542 static int 01543 add_plow (DataType *Data, LayerType *Layer, PolygonType *Polygon, 01544 int type, void *ptr1, void *ptr2, void *userdata) 01545 { 01546 PinType *via; 01547 int layer_n = GetLayerNumber (Data, Layer); 01548 01549 switch (type) 01550 { 01551 case PIN_TYPE: 01552 UnsubtractPin ((PinType *) ptr2, Layer, Polygon); 01553 return 1; 01554 case VIA_TYPE: 01555 via = (PinType *) ptr2; 01556 if (!VIA_IS_BURIED (via) || VIA_ON_LAYER (via, layer_n)) 01557 { 01558 UnsubtractPin ((PinType *) ptr2, Layer, Polygon); 01559 return 1; 01560 } 01561 break; 01562 case LINE_TYPE: 01563 UnsubtractLine ((LineType *) ptr2, Layer, Polygon); 01564 return 1; 01565 case ARC_TYPE: 01566 UnsubtractArc ((ArcType *) ptr2, Layer, Polygon); 01567 return 1; 01568 case PAD_TYPE: 01569 UnsubtractPad ((PadType *) ptr2, Layer, Polygon); 01570 return 1; 01571 case TEXT_TYPE: 01572 UnsubtractText ((TextType *) ptr2, Layer, Polygon); 01573 return 1; 01574 } 01575 return 0; 01576 } 01577 01578 static int 01579 plow_callback (const BoxType * b, void *cl) 01580 { 01581 struct plow_info *plow = (struct plow_info *) cl; 01582 PolygonType *polygon = (PolygonType *) b; 01583 01584 if (TEST_FLAG (CLEARPOLYFLAG, polygon)) 01585 return plow->callback (plow->data, plow->layer, polygon, plow->type, 01586 plow->ptr1, plow->ptr2, plow->userdata); 01587 return 0; 01588 } 01589 01590 int 01591 PlowsPolygon (DataType * Data, int type, void *ptr1, void *ptr2, 01592 int (*call_back) (DataType *data, LayerType *lay, 01593 PolygonType *poly, int type, void *ptr1, 01594 void *ptr2, void *userdata), 01595 void *userdata) 01596 { 01597 BoxType sb = ((PinType *) ptr2)->BoundingBox; 01598 int r = 0; 01599 struct plow_info info; 01600 01601 info.type = type; 01602 info.ptr1 = ptr1; 01603 info.ptr2 = ptr2; 01604 info.data = Data; 01605 info.callback = call_back; 01606 info.userdata = userdata; 01607 switch (type) 01608 { 01609 case PIN_TYPE: 01610 case VIA_TYPE: 01611 if (type == PIN_TYPE || ptr1 == ptr2 || ptr1 == NULL) 01612 { 01613 LAYER_LOOP (Data, max_copper_layer); 01614 { 01615 info.layer = layer; 01616 r += 01617 r_search (layer->polygon_tree, &sb, NULL, plow_callback, &info); 01618 } 01619 END_LOOP; 01620 } 01621 else 01622 { 01623 GROUP_LOOP (Data, GetLayerGroupNumberByNumber (GetLayerNumber (Data, 01624 ((LayerType *) ptr1)))); 01625 { 01626 info.layer = layer; 01627 r += 01628 r_search (layer->polygon_tree, &sb, NULL, plow_callback, &info); 01629 } 01630 END_LOOP; 01631 } 01632 break; 01633 case LINE_TYPE: 01634 case ARC_TYPE: 01635 case TEXT_TYPE: 01636 /* the cast works equally well for lines and arcs */ 01637 if (!TEST_FLAG (CLEARLINEFLAG, (LineType *) ptr2)) 01638 return 0; 01639 /* silk doesn't plow */ 01640 if (GetLayerNumber (Data, (LayerType *)ptr1) >= max_copper_layer) 01641 return 0; 01642 GROUP_LOOP (Data, GetLayerGroupNumberByNumber (GetLayerNumber (Data, 01643 ((LayerType *) ptr1)))); 01644 { 01645 info.layer = layer; 01646 r += r_search (layer->polygon_tree, &sb, NULL, plow_callback, &info); 01647 } 01648 END_LOOP; 01649 break; 01650 case PAD_TYPE: 01651 { 01652 Cardinal group = GetLayerGroupNumberByNumber ( 01653 TEST_FLAG (ONSOLDERFLAG, (PadType *) ptr2) ? 01654 bottom_silk_layer : top_silk_layer); 01655 GROUP_LOOP (Data, group); 01656 { 01657 info.layer = layer; 01658 r += 01659 r_search (layer->polygon_tree, &sb, NULL, plow_callback, &info); 01660 } 01661 END_LOOP; 01662 } 01663 break; 01664 01665 case ELEMENT_TYPE: 01666 { 01667 PIN_LOOP ((ElementType *) ptr1); 01668 { 01669 PlowsPolygon (Data, PIN_TYPE, ptr1, pin, call_back, userdata); 01670 } 01671 END_LOOP; 01672 PAD_LOOP ((ElementType *) ptr1); 01673 { 01674 PlowsPolygon (Data, PAD_TYPE, ptr1, pad, call_back, userdata); 01675 } 01676 END_LOOP; 01677 } 01678 break; 01679 } 01680 return r; 01681 } 01682 01683 void 01684 RestoreToPolygon (DataType * Data, int type, void *ptr1, void *ptr2) 01685 { 01686 if (!Data->polyClip) 01687 return; 01688 01689 if (type == POLYGON_TYPE) 01690 InitClip (PCB->Data, (LayerType *) ptr1, (PolygonType *) ptr2); 01691 else 01692 PlowsPolygon (Data, type, ptr1, ptr2, add_plow, NULL); 01693 } 01694 01695 void 01696 ClearFromPolygon (DataType * Data, int type, void *ptr1, void *ptr2) 01697 { 01698 if (!Data->polyClip) 01699 return; 01700 01701 if (type == POLYGON_TYPE) 01702 InitClip (PCB->Data, (LayerType *) ptr1, (PolygonType *) ptr2); 01703 else 01704 PlowsPolygon (Data, type, ptr1, ptr2, subtract_plow, NULL); 01705 } 01706 01707 bool 01708 isects (POLYAREA * a, PolygonType *p, bool fr) 01709 { 01710 POLYAREA *x; 01711 bool ans; 01712 ans = Touching (a, p->Clipped); 01713 /* argument may be register, so we must copy it */ 01714 x = a; 01715 if (fr) 01716 poly_Free (&x); 01717 return ans; 01718 } 01719 01720 01721 bool 01722 IsPointInPolygon (Coord X, Coord Y, Coord r, PolygonType *p) 01723 { 01724 POLYAREA *c; 01725 Vector v; 01726 v[0] = X; 01727 v[1] = Y; 01728 if (poly_CheckInside (p->Clipped, v)) 01729 return true; 01730 if (r < 1) 01731 return false; 01732 if (!(c = CirclePoly (X, Y, r))) 01733 return false; 01734 return isects (c, p, true); 01735 } 01736 01737 01738 bool 01739 IsPointInPolygonIgnoreHoles (Coord X, Coord Y, PolygonType *p) 01740 { 01741 Vector v; 01742 v[0] = X; 01743 v[1] = Y; 01744 return poly_InsideContour (p->Clipped->contours, v); 01745 } 01746 01747 bool 01748 IsRectangleInPolygon (Coord X1, Coord Y1, Coord X2, Coord Y2, PolygonType *p) 01749 { 01750 POLYAREA *s; 01751 if (! 01752 (s = RectPoly (min (X1, X2), max (X1, X2), min (Y1, Y2), max (Y1, Y2)))) 01753 return false; 01754 return isects (s, p, true); 01755 } 01756 01763 static void 01764 r_NoHolesPolygonDicer (POLYAREA * pa, 01765 void (*emit) (PLINE *, void *), void *user_data) 01766 { 01767 PLINE *p = pa->contours; 01768 01769 if (!pa->contours->next) /* no holes */ 01770 { 01771 pa->contours = NULL; /* The callback now owns the contour */ 01772 /* Don't bother removing it from the POLYAREA's rtree 01773 since we're going to free the POLYAREA below anyway */ 01774 emit (p, user_data); 01775 poly_Free (&pa); 01776 return; 01777 } 01778 else 01779 { 01780 POLYAREA *poly2, *left, *right; 01781 01782 /* make a rectangle of the left region slicing through the middle of the first hole */ 01783 poly2 = RectPoly (p->xmin, (p->next->xmin + p->next->xmax) / 2, 01784 p->ymin, p->ymax); 01785 poly_AndSubtract_free (pa, poly2, &left, &right); 01786 if (left) 01787 { 01788 POLYAREA *cur, *next; 01789 cur = left; 01790 do 01791 { 01792 next = cur->f; 01793 cur->f = cur->b = cur; /* Detach this polygon piece */ 01794 r_NoHolesPolygonDicer (cur, emit, user_data); 01795 /* NB: The POLYAREA was freed by its use in the recursive dicer */ 01796 } 01797 while ((cur = next) != left); 01798 } 01799 if (right) 01800 { 01801 POLYAREA *cur, *next; 01802 cur = right; 01803 do 01804 { 01805 next = cur->f; 01806 cur->f = cur->b = cur; /* Detach this polygon piece */ 01807 r_NoHolesPolygonDicer (cur, emit, user_data); 01808 /* NB: The POLYAREA was freed by its use in the recursive dicer */ 01809 } 01810 while ((cur = next) != right); 01811 } 01812 } 01813 } 01814 01815 void 01816 NoHolesPolygonDicer (PolygonType *p, const BoxType * clip, 01817 void (*emit) (PLINE *, void *), void *user_data) 01818 { 01819 POLYAREA *main_contour, *cur, *next; 01820 01821 main_contour = poly_Create (); 01822 /* copy the main poly only */ 01823 poly_Copy1 (main_contour, p->Clipped); 01824 /* clip to the bounding box */ 01825 if (clip) 01826 { 01827 POLYAREA *cbox = RectPoly (clip->X1, clip->X2, clip->Y1, clip->Y2); 01828 poly_Boolean_free (main_contour, cbox, &main_contour, PBO_ISECT); 01829 } 01830 if (main_contour == NULL) 01831 return; 01832 /* Now dice it up. 01833 * NB: Could be more than one piece (because of the clip above) 01834 */ 01835 cur = main_contour; 01836 do 01837 { 01838 next = cur->f; 01839 cur->f = cur->b = cur; /* Detach this polygon piece */ 01840 r_NoHolesPolygonDicer (cur, emit, user_data); 01841 /* NB: The POLYAREA was freed by its use in the recursive dicer */ 01842 } 01843 while ((cur = next) != main_contour); 01844 } 01845 01850 bool 01851 MorphPolygon (LayerType *layer, PolygonType *poly) 01852 { 01853 POLYAREA *p, *start; 01854 bool many = false; 01855 FlagType flags; 01856 01857 if (!poly->Clipped || TEST_FLAG (LOCKFLAG, poly)) 01858 return false; 01859 if (poly->Clipped->f == poly->Clipped) 01860 return false; 01861 ErasePolygon (poly); 01862 start = p = poly->Clipped; 01863 /* This is ugly. The creation of the new polygons can cause 01864 * all of the polygon pointers (including the one we're called 01865 * with to change if there is a realloc in GetPolygonMemory(). 01866 * That will invalidate our original "poly" argument, potentially 01867 * inside the loop. We need to steal the Clipped pointer and 01868 * hide it from the Remove call so that it still exists while 01869 * we do this dirty work. 01870 */ 01871 poly->Clipped = NULL; 01872 if (poly->NoHoles) printf ("Just leaked in MorpyPolygon\n"); 01873 poly->NoHoles = NULL; 01874 flags = poly->Flags; 01875 RemovePolygon (layer, poly); 01876 inhibit = true; 01877 do 01878 { 01879 VNODE *v; 01880 PolygonType *newone; 01881 01882 if (p->contours->area > PCB->IsleArea) 01883 { 01884 newone = CreateNewPolygon (layer, flags); 01885 if (!newone) 01886 return false; 01887 many = true; 01888 v = &p->contours->head; 01889 CreateNewPointInPolygon (newone, v->point[0], v->point[1]); 01890 for (v = v->next; v != &p->contours->head; v = v->next) 01891 CreateNewPointInPolygon (newone, v->point[0], v->point[1]); 01892 newone->BoundingBox.X1 = p->contours->xmin; 01893 newone->BoundingBox.X2 = p->contours->xmax + 1; 01894 newone->BoundingBox.Y1 = p->contours->ymin; 01895 newone->BoundingBox.Y2 = p->contours->ymax + 1; 01896 AddObjectToCreateUndoList (POLYGON_TYPE, layer, newone, newone); 01897 newone->Clipped = p; 01898 p = p->f; /* go to next pline */ 01899 newone->Clipped->b = newone->Clipped->f = newone->Clipped; /* unlink from others */ 01900 r_insert_entry (layer->polygon_tree, (BoxType *) newone, 0); 01901 DrawPolygon (layer, newone); 01902 } 01903 else 01904 { 01905 POLYAREA *t = p; 01906 01907 p = p->f; 01908 poly_DelContour (&t->contours); 01909 free (t); 01910 } 01911 } 01912 while (p != start); 01913 inhibit = false; 01914 IncrementUndoSerialNumber (); 01915 return many; 01916 } 01917 01918 void debug_pline (PLINE *pl) 01919 { 01920 VNODE *v; 01921 pcb_fprintf (stderr, "\txmin %#mS xmax %#mS ymin %#mS ymax %#mS\n", 01922 pl->xmin, pl->xmax, pl->ymin, pl->ymax); 01923 v = &pl->head; 01924 while (v) 01925 { 01926 pcb_fprintf(stderr, "\t\tvnode: %#mD\n", v->point[0], v->point[1]); 01927 v = v->next; 01928 if (v == &pl->head) 01929 break; 01930 } 01931 } 01932 01933 void 01934 debug_polyarea (POLYAREA *p) 01935 { 01936 PLINE *pl; 01937 01938 fprintf (stderr, "POLYAREA %p\n", p); 01939 for (pl=p->contours; pl; pl=pl->next) 01940 debug_pline (pl); 01941 } 01942 01943 void 01944 debug_polygon (PolygonType *p) 01945 { 01946 Cardinal i; 01947 POLYAREA *pa; 01948 fprintf (stderr, "POLYGON %p %d pts\n", p, p->PointN); 01949 for (i=0; i<p->PointN; i++) 01950 pcb_fprintf(stderr, "\t%d: %#mD\n", i, p->Points[i].X, p->Points[i].Y); 01951 if (p->HoleIndexN) 01952 { 01953 fprintf (stderr, "%d holes, starting at indices\n", p->HoleIndexN); 01954 for (i=0; i<p->HoleIndexN; i++) 01955 fprintf(stderr, "\t%d: %d\n", i, p->HoleIndex[i]); 01956 } 01957 else 01958 fprintf (stderr, "it has no holes\n"); 01959 pa = p->Clipped; 01960 while (pa) 01961 { 01962 debug_polyarea (pa); 01963 pa = pa->f; 01964 if (pa == p->Clipped) 01965 break; 01966 } 01967 } 01968 01973 void 01974 PolyToPolygonsOnLayer (DataType *Destination, LayerType *Layer, 01975 POLYAREA *Input, FlagType Flags) 01976 { 01977 PolygonType *Polygon; 01978 POLYAREA *pa; 01979 PLINE *pline; 01980 VNODE *node; 01981 bool outer; 01982 01983 if (Input == NULL) 01984 return; 01985 01986 pa = Input; 01987 do 01988 { 01989 Polygon = CreateNewPolygon (Layer, Flags); 01990 01991 pline = pa->contours; 01992 outer = true; 01993 01994 do 01995 { 01996 if (!outer) 01997 CreateNewHoleInPolygon (Polygon); 01998 outer = false; 01999 02000 node = &pline->head; 02001 do 02002 { 02003 CreateNewPointInPolygon (Polygon, node->point[0], 02004 node->point[1]); 02005 } 02006 while ((node = node->next) != &pline->head); 02007 02008 } 02009 while ((pline = pline->next) != NULL); 02010 02011 InitClip (Destination, Layer, Polygon); 02012 SetPolygonBoundingBox (Polygon); 02013 if (!Layer->polygon_tree) 02014 Layer->polygon_tree = r_create_tree (NULL, 0, 0); 02015 r_insert_entry (Layer->polygon_tree, (BoxType *) Polygon, 0); 02016 02017 DrawPolygon (Layer, Polygon); 02018 /* add to undo list */ 02019 AddObjectToCreateUndoList (POLYGON_TYPE, Layer, Polygon, Polygon); 02020 } 02021 while ((pa = pa->f) != Input); 02022 02023 SetChangedFlag (true); 02024 }