/* * COPYRIGHT * * pcb-rnd, interactive printed circuit board design * (this file is based on PCB, interactive printed circuit board design) * Copyright (C) 1994,1995,1996 Thomas Nau * Copyright (C) 2020 Tibor 'Igor2' Palinkas * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact: * Project page: http://repo.hu/projects/pcb-rnd * lead developer: http://repo.hu/projects/pcb-rnd/contact.html * mailing list: pcb-rnd (at) list.repo.hu (send "subscribe") * */ /* Drawing primitive: (elliptical) arc */ #include "config.h" #include "board.h" #include "data.h" #include "polygon.h" #include "undo.h" #include "rotate.h" #include "move.h" #include "conf_core.h" #include "thermal.h" #include #include "draw_wireframe.h" #include #include "obj_arc.h" #include "obj_arc_op.h" #include "obj_subc_parent.h" #include "obj_hash.h" #include "obj_arc_draw.h" TODO("ui_layer parent fix: remove this") #include "layer_ui.h" static int pcb_arc_end_addr = 1; int *pcb_arc_start_ptr = NULL, *pcb_arc_end_ptr = &pcb_arc_end_addr; void pcb_arc_reg(pcb_layer_t *layer, pcb_arc_t *arc) { arclist_append(&layer->Arc, arc); PCB_SET_PARENT(arc, layer, layer); if (pcb_is_uilayer(layer)) pcb_obj_id_reg(layer->parent.data, arc); else if (layer->parent_type == PCB_PARENT_DATA) pcb_obj_id_reg(layer->parent.data, arc); } void pcb_arc_unreg(pcb_arc_t *arc) { pcb_layer_t *layer = arc->parent.layer; assert(arc->parent_type == PCB_PARENT_LAYER); arclist_remove(arc); if (pcb_is_uilayer(layer)) { pcb_obj_id_del(layer->parent.data, arc); } else { assert(layer->parent_type == PCB_PARENT_DATA); pcb_obj_id_del(layer->parent.data, arc); } PCB_CLEAR_PARENT(arc); } pcb_arc_t *pcb_arc_alloc_id(pcb_layer_t *layer, long int id) { pcb_arc_t *new_obj; new_obj = calloc(sizeof(pcb_arc_t), 1); new_obj->ID = id; new_obj->type = PCB_OBJ_ARC; new_obj->Attributes.post_change = pcb_obj_attrib_post_change; pcb_arc_reg(layer, new_obj); return new_obj; } pcb_arc_t *pcb_arc_alloc(pcb_layer_t *layer) { return pcb_arc_alloc_id(layer, pcb_create_ID_get()); } /* computes the centerline bounding box of an arc */ rnd_box_t pcb_arc_bbox_cline(const pcb_arc_t *Arc) { double ca1, ca2, sa1, sa2; double minx, maxx, miny, maxy, delta; rnd_angle_t ang1, ang2; rnd_box_t res; /* first normalize angles: ang1 < ang2, both angles between 0 and 720 */ delta = RND_CLAMP(Arc->Delta, -360, 360); if (delta > 0) { ang1 = rnd_normalize_angle(Arc->StartAngle); ang2 = rnd_normalize_angle(Arc->StartAngle + delta); } else { ang1 = rnd_normalize_angle(Arc->StartAngle + delta); ang2 = rnd_normalize_angle(Arc->StartAngle); } if (ang1 > ang2) ang2 += 360; /* Make sure full circles aren't treated as zero-length arcs */ if (delta == 360 || delta == -360) ang2 = ang1 + 360; /* calculate sines, cosines */ sa1 = sin(RND_M180 * ang1); ca1 = cos(RND_M180 * ang1); sa2 = sin(RND_M180 * ang2); ca2 = cos(RND_M180 * ang2); minx = MIN(ca1, ca2); maxx = MAX(ca1, ca2); miny = MIN(sa1, sa2); maxy = MAX(sa1, sa2); /* Check for extreme angles */ if ((ang1 <= 0 && ang2 >= 0) || (ang1 <= 360 && ang2 >= 360)) maxx = 1; if ((ang1 <= 90 && ang2 >= 90) || (ang1 <= 450 && ang2 >= 450)) maxy = 1; if ((ang1 <= 180 && ang2 >= 180) || (ang1 <= 540 && ang2 >= 540)) minx = -1; if ((ang1 <= 270 && ang2 >= 270) || (ang1 <= 630 && ang2 >= 630)) miny = -1; /* Finally, calculate bounds, converting sane geometry into pcb geometry */ res.X1 = Arc->X - Arc->Width * maxx; res.X2 = Arc->X - Arc->Width * minx; res.Y1 = Arc->Y + Arc->Height * miny; res.Y2 = Arc->Y + Arc->Height * maxy; return res; } /* computes the bounding box of an arc */ static rnd_box_t pcb_arc_bbox_(const pcb_arc_t *Arc, int mini) { rnd_box_t res; rnd_coord_t width; res = pcb_arc_bbox_cline(Arc); if (!mini) { width = (Arc->Thickness + Arc->Clearance) / 2; /* Adjust for our discrete polygon approximation */ width = (double) width *MAX(RND_POLY_CIRC_RADIUS_ADJ, (1.0 + RND_POLY_ARC_MAX_DEVIATION)) + 0.5; } else width = Arc->Thickness / 2; res.X1 -= width; res.X2 += width; res.Y1 -= width; res.Y2 += width; rnd_close_box(&res); return res; } void pcb_arc_bbox(pcb_arc_t *Arc) { Arc->BoundingBox = pcb_arc_bbox_(Arc, 0); Arc->bbox_naked = pcb_arc_bbox_(Arc, 1); } void pcb_arc_get_end(pcb_arc_t *arc, int which, rnd_coord_t *x, rnd_coord_t *y) { rnd_arc_get_endpt(arc->X, arc->Y, arc->Width, arc->Height, arc->StartAngle, arc->Delta, which, x, y); } int pcb_angle_in_arc_(double arc_sa, double arc_da, double ang, int inclusive) { double arc_ea; /* make sure angle is always positive */ if (ang < 0) ang += 360.0; if (arc_da < 0) { /* swap endpoints so da is always positive */ arc_sa = arc_sa + arc_da; arc_da = -arc_da; } if (arc_sa < 0) arc_sa += 360.0; arc_ea = arc_sa + arc_da; /* if arc spans from some high value through zero, the end angle has to be larger than 360; if ang is under both start and end, that may be the case so add a full circle to ang, last chance to get it in range */ if ((arc_sa > ang) && (arc_ea > ang)) ang += 360.0; if (inclusive) { if ((ang >= arc_sa) && (ang <= arc_ea)) return 1; } else { if ((ang > arc_sa) && (ang < arc_ea)) return 1; } if (arc_ea > 360.0) { ang += 360.0; if (inclusive) { if ((ang >= arc_sa) && (ang <= arc_ea)) return 1; } else { if ((ang > arc_sa) && (ang < arc_ea)) return 1; } } return 0; } void pcb_arc_set_angles(pcb_layer_t *Layer, pcb_arc_t *a, rnd_angle_t new_sa, rnd_angle_t new_da) { if (new_da >= 360) { new_da = 360; new_sa = 0; } pcb_poly_restore_to_poly(PCB->Data, PCB_OBJ_ARC, Layer, a); rnd_rtree_delete(Layer->arc_tree, a, (rnd_rtree_box_t *)a); pcb_undo_add_obj_to_change_angles(PCB_OBJ_ARC, a, a, a); a->StartAngle = new_sa; a->Delta = new_da; pcb_arc_bbox(a); rnd_rtree_insert(Layer->arc_tree, a, (rnd_rtree_box_t *)a); pcb_poly_clear_from_poly(PCB->Data, PCB_OBJ_ARC, Layer, a); } void pcb_arc_set_radii(pcb_layer_t *Layer, pcb_arc_t *a, rnd_coord_t new_width, rnd_coord_t new_height) { pcb_poly_restore_to_poly(PCB->Data, PCB_OBJ_ARC, Layer, a); rnd_rtree_delete(Layer->arc_tree, a, (rnd_rtree_box_t *)a); pcb_undo_add_obj_to_change_radii(PCB_OBJ_ARC, a, a, a); a->Width = new_width; a->Height = new_height; pcb_arc_bbox(a); rnd_rtree_insert(Layer->arc_tree, a, (rnd_rtree_box_t *)a); pcb_poly_clear_from_poly(PCB->Data, PCB_OBJ_ARC, Layer, a); } /* creates a new arc on a layer */ pcb_arc_t *pcb_arc_new(pcb_layer_t *Layer, rnd_coord_t X1, rnd_coord_t Y1, rnd_coord_t width, rnd_coord_t height, rnd_angle_t sa, rnd_angle_t dir, rnd_coord_t Thickness, rnd_coord_t Clearance, pcb_flag_t Flags, rnd_bool prevent_dups) { pcb_arc_t *Arc; if ((prevent_dups) && (Layer->arc_tree != NULL)) { rnd_rtree_it_t it; pcb_any_obj_t *o; rnd_box_t b; b.X1 = X1 - width; b.Y1 = Y1 - height; b.X2 = X1 + width; b.Y2 = Y1 + height; for(o = rnd_rtree_first(&it, Layer->arc_tree, (rnd_rtree_box_t *)&b); o != NULL; o = rnd_rtree_next(&it)) { pcb_arc_t *arc = (pcb_arc_t *)o; if ((arc->X == X1) && (arc->Y == Y1) && (arc->Width == width)) { double s1, s2, d1 = arc->Delta, d2 = dir; /* there are two ways normalized arcs can be the same: with + and with - delta */ if (d1 < 0) { s1 = rnd_normalize_angle(arc->StartAngle + d1); d1 = -d1; } else s1 = rnd_normalize_angle(arc->StartAngle); if (d2 < 0) { s2 = rnd_normalize_angle(sa + d2); d2 = -d2; } else s2 = rnd_normalize_angle(sa); if ((s1 == s2) && (d1 == d2)) return NULL; /* prevent stacked arcs */ } } } Arc = pcb_arc_alloc(Layer); if (!Arc) return Arc; Arc->Flags = Flags; Arc->Thickness = Thickness; Arc->Clearance = Clearance; Arc->X = X1; Arc->Y = Y1; Arc->Width = width; Arc->Height = height; Arc->StartAngle = sa; Arc->Delta = dir; pcb_add_arc_on_layer(Layer, Arc); return Arc; } static pcb_arc_t *pcb_arc_copy_meta(pcb_arc_t *dst, pcb_arc_t *src) { if (dst == NULL) return NULL; pcb_attribute_copy_all(&dst->Attributes, &src->Attributes); return dst; } pcb_arc_t *pcb_arc_dup(pcb_layer_t *dst, pcb_arc_t *src) { pcb_arc_t *a = pcb_arc_new(dst, src->X, src->Y, src->Width, src->Height, src->StartAngle, src->Delta, src->Thickness, src->Clearance, src->Flags, rnd_false); pcb_arc_copy_meta(a, src); return a; } pcb_arc_t *pcb_arc_dup_at(pcb_layer_t *dst, pcb_arc_t *src, rnd_coord_t dx, rnd_coord_t dy) { pcb_arc_t *a = pcb_arc_new(dst, src->X+dx, src->Y+dy, src->Width, src->Height, src->StartAngle, src->Delta, src->Thickness, src->Clearance, src->Flags, rnd_false); pcb_arc_copy_meta(a, src); return a; } void pcb_add_arc_on_layer(pcb_layer_t *Layer, pcb_arc_t *Arc) { pcb_arc_bbox(Arc); if (!Layer->arc_tree) rnd_rtree_init(Layer->arc_tree = malloc(sizeof(rnd_rtree_t))); rnd_rtree_insert(Layer->arc_tree, Arc, (rnd_rtree_box_t *)Arc); Arc->type = PCB_OBJ_ARC; PCB_SET_PARENT(Arc, layer, Layer); } void pcb_arc_free(pcb_arc_t *arc) { if ((arc->parent.layer != NULL) && (arc->parent.layer->arc_tree != NULL)) rnd_rtree_delete(arc->parent.layer->arc_tree, arc, (rnd_rtree_box_t *)arc); pcb_attribute_free(&arc->Attributes); pcb_arc_unreg(arc); pcb_obj_common_free((pcb_any_obj_t *)arc); free(arc); } int pcb_arc_eq(const pcb_host_trans_t *tr1, const pcb_arc_t *a1, const pcb_host_trans_t *tr2, const pcb_arc_t *a2) { double sgn1 = tr1->on_bottom ? -1 : +1; double sgn2 = tr2->on_bottom ? -1 : +1; if (pcb_field_neq(a1, a2, Thickness) || pcb_field_neq(a1, a2, Clearance)) return 0; if (pcb_field_neq(a1, a2, Width) || pcb_field_neq(a1, a2, Height)) return 0; if (!PCB_FLAG_TEST(PCB_FLAG_FLOATER, a1) && !PCB_FLAG_TEST(PCB_FLAG_FLOATER, a2)) { if (pcb_neq_tr_coords(tr1, a1->X, a1->Y, tr2, a2->X, a2->Y)) return 0; if (rnd_normalize_angle(rnd_round(a1->StartAngle * sgn1 + tr1->rot * sgn1)) != rnd_normalize_angle(rnd_round(a2->StartAngle * sgn2 + tr2->rot * sgn2))) return 0; if (rnd_round(a1->Delta * sgn1) != rnd_round(a2->Delta * sgn2)) return 0; } return 1; } unsigned int pcb_arc_hash(const pcb_host_trans_t *tr, const pcb_arc_t *a) { unsigned int crd = 0; double sgn = tr->on_bottom ? -1 : +1; if (!PCB_FLAG_TEST(PCB_FLAG_FLOATER, a)) { rnd_coord_t x, y; pcb_hash_tr_coords(tr, &x, &y, a->X, a->Y); crd = pcb_hash_coord(x) ^ pcb_hash_coord(y) ^ pcb_hash_coord(rnd_normalize_angle(rnd_round(a->StartAngle*sgn + tr->rot*sgn))) ^ pcb_hash_coord(rnd_round(a->Delta * sgn)); } return pcb_hash_coord(a->Thickness) ^ pcb_hash_coord(a->Clearance) ^ pcb_hash_coord(a->Width) ^ pcb_hash_coord(a->Height) ^ crd; } rnd_coord_t pcb_arc_length(const pcb_arc_t *arc) { double da = arc->Delta; double r = ((double)arc->Width + (double)arc->Height) / 2.0; /* TODO: lame approximation */ if (da < 0) da = -da; while(da > 360.0) da = 360.0; return rnd_round(2.0*r*M_PI*da/360.0); } double pcb_arc_area(const pcb_arc_t *arc) { return (pcb_arc_length(arc) * (double)arc->Thickness /* body */ + (double)arc->Thickness * (double)arc->Thickness * (double)M_PI); /* cap circles */ } rnd_box_t pcb_arc_mini_bbox(const pcb_arc_t *arc) { return pcb_arc_bbox_(arc, 1); } void pcb_arc_pre(pcb_arc_t *arc) { pcb_layer_t *ly = pcb_layer_get_real(arc->parent.layer); if (ly == NULL) return; if (ly->arc_tree != NULL) rnd_rtree_delete(ly->arc_tree, arc, (rnd_rtree_box_t *)arc); pcb_poly_restore_to_poly(ly->parent.data, PCB_OBJ_ARC, ly, arc); } void pcb_arc_post(pcb_arc_t *arc) { pcb_layer_t *ly = pcb_layer_get_real(arc->parent.layer); if (ly == NULL) return; if (ly->arc_tree != NULL) rnd_rtree_insert(ly->arc_tree, arc, (rnd_rtree_box_t *)arc); pcb_poly_clear_from_poly(ly->parent.data, PCB_OBJ_ARC, ly, arc); } /***** operations *****/ static const char core_arc_cookie[] = "core-arc"; typedef struct { pcb_arc_t *arc; /* it is safe to save the object pointer because it is persistent (through the removed object list) */ rnd_coord_t Thickness, Clearance; rnd_coord_t Width, Height; rnd_coord_t X, Y; rnd_angle_t StartAngle, Delta; } undo_arc_geo_t; static int undo_arc_geo_swap(void *udata) { undo_arc_geo_t *g = udata; pcb_layer_t *layer = g->arc->parent.layer; if (layer->arc_tree != NULL) rnd_rtree_delete(layer->arc_tree, g->arc, (rnd_rtree_box_t *)g->arc); pcb_poly_restore_to_poly(layer->parent.data, PCB_OBJ_ARC, layer, g->arc); rnd_swap(rnd_coord_t, g->Thickness, g->arc->Thickness); rnd_swap(rnd_coord_t, g->Clearance, g->arc->Clearance); rnd_swap(rnd_coord_t, g->Width, g->arc->Width); rnd_swap(rnd_coord_t, g->Height, g->arc->Height); rnd_swap(rnd_coord_t, g->X, g->arc->X); rnd_swap(rnd_coord_t, g->Y, g->arc->Y); rnd_swap(rnd_angle_t, g->StartAngle, g->arc->StartAngle); rnd_swap(rnd_angle_t, g->Delta, g->arc->Delta); pcb_arc_bbox(g->arc); if (layer->arc_tree != NULL) rnd_rtree_insert(layer->arc_tree, g->arc, (rnd_rtree_box_t *)g->arc); pcb_poly_clear_from_poly(layer->parent.data, PCB_OBJ_ARC, layer, g->arc); return 0; } static void undo_arc_geo_print(void *udata, char *dst, size_t dst_len) { rnd_snprintf(dst, dst_len, "arc geo"); } static const uundo_oper_t undo_arc_geo = { core_arc_cookie, NULL, undo_arc_geo_swap, undo_arc_geo_swap, undo_arc_geo_print }; /* copies an arc to buffer */ void *pcb_arcop_add_to_buffer(pcb_opctx_t *ctx, pcb_layer_t *Layer, pcb_arc_t *Arc) { pcb_arc_t *a; rnd_layer_id_t lid = pcb_layer_id(ctx->buffer.src, Layer); pcb_layer_t *layer; /* the buffer may not have the specified layer, e.g. on loose subc subc-aux layer */ if (lid == -1) return NULL; layer = &ctx->buffer.dst->Layer[lid]; a = pcb_arc_new(layer, Arc->X, Arc->Y, Arc->Width, Arc->Height, Arc->StartAngle, Arc->Delta, Arc->Thickness, Arc->Clearance, pcb_flag_mask(Arc->Flags, PCB_FLAG_FOUND | ctx->buffer.extraflg), rnd_false); pcb_arc_copy_meta(a, Arc); if (ctx->buffer.keep_id) pcb_obj_change_id((pcb_any_obj_t *)a, Arc->ID); return a; } /* moves an arc between board and buffer */ void *pcb_arcop_move_buffer(pcb_opctx_t *ctx, pcb_layer_t *dstly, pcb_arc_t *arc) { pcb_layer_t *srcly = arc->parent.layer; assert(arc->parent_type == PCB_PARENT_LAYER); if ((dstly == NULL) || (dstly == srcly)) { /* auto layer in dst */ rnd_layer_id_t lid = pcb_layer_id(ctx->buffer.src, srcly); if (lid < 0) { rnd_message(RND_MSG_ERROR, "Internal error: can't resolve source layer ID in pcb_arcop_move_buffer\n"); return NULL; } dstly = &ctx->buffer.dst->Layer[lid]; } pcb_poly_restore_to_poly(ctx->buffer.src, PCB_OBJ_ARC, srcly, arc); rnd_rtree_delete(srcly->arc_tree, arc, (rnd_rtree_box_t *)arc); pcb_arc_unreg(arc); pcb_arc_reg(dstly, arc); PCB_FLAG_CLEAR(PCB_FLAG_FOUND, arc); if (!dstly->arc_tree) rnd_rtree_init(dstly->arc_tree = malloc(sizeof(rnd_rtree_t))); rnd_rtree_insert(dstly->arc_tree, arc, (rnd_rtree_box_t *)arc); pcb_poly_clear_from_poly(ctx->buffer.dst, PCB_OBJ_ARC, dstly, arc); return arc; } void *pcb_arcop_change_thermal(pcb_opctx_t *ctx, pcb_layer_t *ly, pcb_arc_t *arc) { return pcb_anyop_change_thermal(ctx, (pcb_any_obj_t *)arc); } /* changes the size of an arc */ void *pcb_arcop_change_size(pcb_opctx_t *ctx, pcb_layer_t *Layer, pcb_arc_t *Arc) { rnd_coord_t value = (ctx->chgsize.is_absolute) ? ctx->chgsize.value : Arc->Thickness + ctx->chgsize.value; if (PCB_FLAG_TEST(PCB_FLAG_LOCK, Arc)) return NULL; if (value <= PCB_MAX_THICKNESS && value >= PCB_MIN_THICKNESS && value != Arc->Thickness) { pcb_undo_add_obj_to_size(PCB_OBJ_ARC, Layer, Arc, Arc); pcb_arc_invalidate_erase(Arc); rnd_rtree_delete(Layer->arc_tree, Arc, (rnd_rtree_box_t *)Arc); pcb_poly_restore_to_poly(PCB->Data, PCB_OBJ_ARC, Layer, Arc); Arc->Thickness = value; pcb_arc_bbox(Arc); rnd_rtree_insert(Layer->arc_tree, Arc, (rnd_rtree_box_t *)Arc); pcb_poly_clear_from_poly(PCB->Data, PCB_OBJ_ARC, Layer, Arc); pcb_arc_invalidate_draw(Layer, Arc); return Arc; } return NULL; } /* changes the clearance size of an arc */ void *pcb_arcop_change_clear_size(pcb_opctx_t *ctx, pcb_layer_t *Layer, pcb_arc_t *Arc) { rnd_coord_t value = (ctx->chgsize.is_absolute) ? ctx->chgsize.value : Arc->Clearance + ctx->chgsize.value; if (PCB_FLAG_TEST(PCB_FLAG_LOCK, Arc) || !PCB_FLAG_TEST(PCB_FLAG_CLEARLINE, Arc)) return NULL; if (value < 0) value = 0; value = MIN(PCB_MAX_THICKNESS, value); if (!ctx->chgsize.is_absolute && ctx->chgsize.value < 0) value = 0; if (value != Arc->Clearance) { pcb_undo_add_obj_to_clear_size(PCB_OBJ_ARC, Layer, Arc, Arc); pcb_arc_invalidate_erase(Arc); rnd_rtree_delete(Layer->arc_tree, Arc, (rnd_rtree_box_t *)Arc); pcb_poly_restore_to_poly(PCB->Data, PCB_OBJ_ARC, Layer, Arc); Arc->Clearance = value; pcb_arc_bbox(Arc); rnd_rtree_insert(Layer->arc_tree, Arc, (rnd_rtree_box_t *)Arc); pcb_poly_clear_from_poly(PCB->Data, PCB_OBJ_ARC, Layer, Arc); pcb_arc_invalidate_draw(Layer, Arc); return Arc; } return NULL; } /* changes the radius of an arc (is_primary 0=width or 1=height or 2=both) */ void *pcb_arcop_change_radius(pcb_opctx_t *ctx, pcb_layer_t *Layer, pcb_arc_t *Arc) { rnd_coord_t value, *dst; void *a0, *a1; if (PCB_FLAG_TEST(PCB_FLAG_LOCK, Arc)) return NULL; switch(ctx->chgsize.is_primary) { case 0: dst = &Arc->Width; break; case 1: dst = &Arc->Height; break; case 2: ctx->chgsize.is_primary = 0; a0 = pcb_arcop_change_radius(ctx, Layer, Arc); ctx->chgsize.is_primary = 1; a1 = pcb_arcop_change_radius(ctx, Layer, Arc); if ((a0 != NULL) || (a1 != NULL)) return Arc; return NULL; } value = (ctx->chgsize.is_absolute) ? ctx->chgsize.value : (*dst) + ctx->chgsize.value; value = MIN(PCB_MAX_ARCRADIUS, MAX(value, PCB_MIN_ARCRADIUS)); if (value != *dst) { pcb_undo_add_obj_to_change_radii(PCB_OBJ_ARC, Layer, Arc, Arc); pcb_arc_invalidate_erase(Arc); rnd_rtree_delete(Layer->arc_tree, Arc, (rnd_rtree_box_t *)Arc); pcb_poly_restore_to_poly(PCB->Data, PCB_OBJ_ARC, Layer, Arc); *dst = value; pcb_arc_bbox(Arc); rnd_rtree_insert(Layer->arc_tree, Arc, (rnd_rtree_box_t *)Arc); pcb_poly_clear_from_poly(PCB->Data, PCB_OBJ_ARC, Layer, Arc); pcb_arc_invalidate_draw(Layer, Arc); return Arc; } return NULL; } /* changes the angle of an arc (is_primary 0=start or 1=end) */ void *pcb_arcop_change_angle(pcb_opctx_t *ctx, pcb_layer_t *Layer, pcb_arc_t *Arc) { rnd_angle_t value, *dst; void *a0, *a1; if (PCB_FLAG_TEST(PCB_FLAG_LOCK, Arc)) return NULL; switch(ctx->chgangle.is_primary) { case 0: dst = &Arc->StartAngle; break; case 1: dst = &Arc->Delta; break; case 2: ctx->chgangle.is_primary = 0; a0 = pcb_arcop_change_angle(ctx, Layer, Arc); ctx->chgangle.is_primary = 1; a1 = pcb_arcop_change_angle(ctx, Layer, Arc); if ((a0 != NULL) || (a1 != NULL)) return Arc; return NULL; } value = (ctx->chgangle.is_absolute) ? ctx->chgangle.value : (*dst) + ctx->chgangle.value; if ((value > 360.0) || (value < -360.0)) value = fmod(value, 360.0); if (value != *dst) { pcb_undo_add_obj_to_change_angles(PCB_OBJ_ARC, Layer, Arc, Arc); pcb_arc_invalidate_erase(Arc); rnd_rtree_delete(Layer->arc_tree, Arc, (rnd_rtree_box_t *)Arc); pcb_poly_restore_to_poly(PCB->Data, PCB_OBJ_ARC, Layer, Arc); *dst = value; pcb_arc_bbox(Arc); rnd_rtree_insert(Layer->arc_tree, Arc, (rnd_rtree_box_t *)Arc); pcb_poly_clear_from_poly(PCB->Data, PCB_OBJ_ARC, Layer, Arc); pcb_arc_invalidate_draw(Layer, Arc); return Arc; } return NULL; } /* changes the clearance flag of an arc */ void *pcb_arcop_change_join(pcb_opctx_t *ctx, pcb_layer_t *Layer, pcb_arc_t *Arc) { if (PCB_FLAG_TEST(PCB_FLAG_LOCK, Arc)) return NULL; pcb_arc_invalidate_erase(Arc); if (PCB_FLAG_TEST(PCB_FLAG_CLEARLINE, Arc)) { pcb_poly_restore_to_poly(PCB->Data, PCB_OBJ_ARC, Layer, Arc); pcb_undo_add_obj_to_clear_poly(PCB_OBJ_ARC, Layer, Arc, Arc, rnd_false); } pcb_undo_add_obj_to_flag(Arc); PCB_FLAG_TOGGLE(PCB_FLAG_CLEARLINE, Arc); if (PCB_FLAG_TEST(PCB_FLAG_CLEARLINE, Arc)) { pcb_poly_clear_from_poly(PCB->Data, PCB_OBJ_ARC, Layer, Arc); pcb_undo_add_obj_to_clear_poly(PCB_OBJ_ARC, Layer, Arc, Arc, rnd_true); } pcb_arc_invalidate_draw(Layer, Arc); return Arc; } /* sets the clearance flag of an arc */ void *pcb_arcop_set_join(pcb_opctx_t *ctx, pcb_layer_t *Layer, pcb_arc_t *Arc) { if (PCB_FLAG_TEST(PCB_FLAG_LOCK, Arc) || PCB_FLAG_TEST(PCB_FLAG_CLEARLINE, Arc)) return NULL; return pcb_arcop_change_join(ctx, Layer, Arc); } /* clears the clearance flag of an arc */ void *pcb_arcop_clear_join(pcb_opctx_t *ctx, pcb_layer_t *Layer, pcb_arc_t *Arc) { if (PCB_FLAG_TEST(PCB_FLAG_LOCK, Arc) || !PCB_FLAG_TEST(PCB_FLAG_CLEARLINE, Arc)) return NULL; return pcb_arcop_change_join(ctx, Layer, Arc); } /* copies an arc */ void *pcb_arcop_copy(pcb_opctx_t *ctx, pcb_layer_t *Layer, pcb_arc_t *Arc) { pcb_arc_t *arc; arc = pcb_arc_new(Layer, Arc->X + ctx->copy.DeltaX, Arc->Y + ctx->copy.DeltaY, Arc->Width, Arc->Height, Arc->StartAngle, Arc->Delta, Arc->Thickness, Arc->Clearance, pcb_flag_mask(Arc->Flags, PCB_FLAG_FOUND), rnd_true); if (!arc) return arc; if (ctx->copy.keep_id) arc->ID = Arc->ID; pcb_arc_copy_meta(arc, Arc); pcb_arc_invalidate_draw(Layer, arc); pcb_undo_add_obj_to_create(PCB_OBJ_ARC, Layer, arc, arc); return arc; } /* moves an arc */ void *pcb_arcop_move_noclip(pcb_opctx_t *ctx, pcb_layer_t *Layer, pcb_arc_t *Arc) { if (Layer->meta.real.vis) { pcb_arc_invalidate_erase(Arc); pcb_arc_move(Arc, ctx->move.dx, ctx->move.dy); pcb_arc_invalidate_draw(Layer, Arc); } else { pcb_arc_move(Arc, ctx->move.dx, ctx->move.dy); } return Arc; } void *pcb_arcop_move(pcb_opctx_t *ctx, pcb_layer_t *Layer, pcb_arc_t *Arc) { rnd_rtree_delete(Layer->arc_tree, Arc, (rnd_rtree_box_t *)Arc); pcb_poly_restore_to_poly(PCB->Data, PCB_OBJ_ARC, Layer, Arc); pcb_arcop_move_noclip(ctx, Layer, Arc); rnd_rtree_insert(Layer->arc_tree, Arc, (rnd_rtree_box_t *)Arc); pcb_poly_clear_from_poly(PCB->Data, PCB_OBJ_ARC, Layer, Arc); return Arc; } void *pcb_arcop_clip(pcb_opctx_t *ctx, pcb_layer_t *Layer, pcb_arc_t *Arc) { if (ctx->clip.restore) { rnd_rtree_delete(Layer->arc_tree, Arc, (rnd_rtree_box_t *)Arc); pcb_poly_restore_to_poly(PCB->Data, PCB_OBJ_ARC, Layer, Arc); } if (ctx->clip.clear) { rnd_rtree_insert(Layer->arc_tree, Arc, (rnd_rtree_box_t *)Arc); pcb_poly_clear_from_poly(PCB->Data, PCB_OBJ_ARC, Layer, Arc); } return Arc; } /* moves an arc between layers; lowlevel routines */ void *pcb_arcop_move_to_layer_low(pcb_opctx_t *ctx, pcb_layer_t * Source, pcb_arc_t * arc, pcb_layer_t * Destination) { rnd_rtree_delete(Source->arc_tree, arc, (rnd_rtree_box_t *)arc); pcb_arc_unreg(arc); pcb_arc_reg(Destination, arc); if (!Destination->arc_tree) rnd_rtree_init(Destination->arc_tree = malloc(sizeof(rnd_rtree_t))); rnd_rtree_insert(Destination->arc_tree, arc, (rnd_rtree_box_t *)arc); return arc; } /* moves an arc between layers */ void *pcb_arcop_move_to_layer(pcb_opctx_t *ctx, pcb_layer_t * Layer, pcb_arc_t * Arc) { pcb_arc_t *newone; if (PCB_FLAG_TEST(PCB_FLAG_LOCK, Arc)) { rnd_message(RND_MSG_WARNING, "Sorry, arc object is locked\n"); return NULL; } if (ctx->move.dst_layer == Layer && Layer->meta.real.vis) pcb_arc_invalidate_draw(Layer, Arc); if (ctx->move.dst_layer == Layer) return Arc; pcb_undo_add_obj_to_move_to_layer(PCB_OBJ_ARC, Layer, Arc, Arc); pcb_poly_restore_to_poly(PCB->Data, PCB_OBJ_ARC, Layer, Arc); if (Layer->meta.real.vis) pcb_arc_invalidate_erase(Arc); newone = (pcb_arc_t *) pcb_arcop_move_to_layer_low(ctx, Layer, Arc, ctx->move.dst_layer); pcb_poly_clear_from_poly(PCB->Data, PCB_OBJ_ARC, ctx->move.dst_layer, Arc); if (ctx->move.dst_layer->meta.real.vis) pcb_arc_invalidate_draw(ctx->move.dst_layer, newone); return newone; } /* destroys an arc from a layer */ void *pcb_arcop_destroy(pcb_opctx_t *ctx, pcb_layer_t *Layer, pcb_arc_t *Arc) { rnd_rtree_delete(Layer->arc_tree, Arc, (rnd_rtree_box_t *)Arc); pcb_arc_free(Arc); return NULL; } /* removes an arc from a layer */ void *pcb_arcop_remove(pcb_opctx_t *ctx, pcb_layer_t *Layer, pcb_arc_t *Arc) { /* erase from screen */ if (Layer->meta.real.vis) pcb_arc_invalidate_erase(Arc); pcb_undo_move_obj_to_remove(PCB_OBJ_ARC, Layer, Arc, Arc); return NULL; } void *pcb_arcop_remove_point(pcb_opctx_t *ctx, pcb_layer_t *l, pcb_arc_t *a, int *end_id) { return pcb_arcop_remove(ctx, l, a); } void *pcb_arc_destroy(pcb_layer_t *Layer, pcb_arc_t *Arc) { void *res; pcb_opctx_t ctx; ctx.remove.pcb = PCB; ctx.remove.destroy_target = NULL; res = pcb_arcop_remove(&ctx, Layer, Arc); pcb_draw(); return res; } /* rotates an arc */ void pcb_arc_rotate90(pcb_arc_t *Arc, rnd_coord_t X, rnd_coord_t Y, unsigned Number) { rnd_coord_t save; /* add Number*90 degrees (i.e., Number quarter-turns) */ Arc->StartAngle = rnd_normalize_angle(Arc->StartAngle + Number * 90); RND_COORD_ROTATE90(Arc->X, Arc->Y, X, Y, Number); /* now change width and height */ if (Number == 1 || Number == 3) { save = Arc->Width; Arc->Width = Arc->Height; Arc->Height = save; } /* can't optimize with box rotation due to closed boxes */ pcb_arc_bbox(Arc); } void pcb_arc_rotate(pcb_layer_t *layer, pcb_arc_t *arc, rnd_coord_t X, rnd_coord_t Y, double cosa, double sina, rnd_angle_t angle) { if (layer->arc_tree != NULL) rnd_rtree_delete(layer->arc_tree, arc, (rnd_rtree_box_t *)arc); rnd_rotate(&arc->X, &arc->Y, X, Y, cosa, sina); arc->StartAngle = rnd_normalize_angle(arc->StartAngle + angle); if (layer->arc_tree != NULL) rnd_rtree_insert(layer->arc_tree, arc, (rnd_rtree_box_t *)arc); } void pcb_arc_mirror(pcb_arc_t *arc, rnd_coord_t y_offs, rnd_bool undoable) { undo_arc_geo_t gtmp, *g = >mp; if (undoable) g = pcb_undo_alloc(pcb_data_get_top(arc->parent.layer->parent.data), &undo_arc_geo, sizeof(undo_arc_geo_t)); g->arc = arc; g->Thickness = arc->Thickness; g->Clearance = arc->Clearance; g->Width = arc->Width; g->Height = arc->Height; g->X = PCB_SWAP_X(arc->X); g->Y = PCB_SWAP_Y(arc->Y) + y_offs; g->StartAngle = RND_SWAP_ANGLE(arc->StartAngle); g->Delta = RND_SWAP_DELTA(arc->Delta); undo_arc_geo_swap(g); if (undoable) pcb_undo_inc_serial(); } void pcb_arc_flip_side(pcb_layer_t *layer, pcb_arc_t *arc) { rnd_rtree_delete(layer->arc_tree, arc, (rnd_rtree_box_t *)arc); arc->X = PCB_SWAP_X(arc->X); arc->Y = PCB_SWAP_Y(arc->Y); arc->StartAngle = RND_SWAP_ANGLE(arc->StartAngle); arc->Delta = RND_SWAP_DELTA(arc->Delta); pcb_arc_bbox(arc); rnd_rtree_insert(layer->arc_tree, arc, (rnd_rtree_box_t *)arc); } void pcb_arc_scale(pcb_arc_t *arc, double sx, double sy, double sth) { int onbrd = (arc->parent.layer != NULL) && (!arc->parent.layer->is_bound); if (onbrd) pcb_arc_pre(arc); if (sx != 1.0) { arc->X = rnd_round((double)arc->X * sx); arc->Width = rnd_round((double)arc->Width * sx); } if (sy != 1.0) { arc->Y = rnd_round((double)arc->Y * sy); arc->Height = rnd_round((double)arc->Height * sy); } if (sth != 1.0) arc->Thickness = rnd_round((double)arc->Thickness * sth); pcb_arc_bbox(arc); if (onbrd) pcb_arc_post(arc); } /* rotates an arc */ void *pcb_arcop_rotate90(pcb_opctx_t *ctx, pcb_layer_t *Layer, pcb_arc_t *Arc) { pcb_arc_invalidate_erase(Arc); pcb_poly_restore_to_poly(PCB->Data, PCB_OBJ_ARC, Layer, Arc); if (Layer->arc_tree != NULL) rnd_rtree_delete(Layer->arc_tree, Arc, (rnd_rtree_box_t *)Arc); pcb_arc_rotate90(Arc, ctx->rotate.center_x, ctx->rotate.center_y, ctx->rotate.number); if (Layer->arc_tree != NULL) rnd_rtree_insert(Layer->arc_tree, Arc, (rnd_rtree_box_t *)Arc); pcb_poly_clear_from_poly(PCB->Data, PCB_OBJ_ARC, Layer, Arc); pcb_arc_invalidate_draw(Layer, Arc); return Arc; } void *pcb_arcop_rotate(pcb_opctx_t *ctx, pcb_layer_t *Layer, pcb_arc_t *Arc) { pcb_arc_invalidate_erase(Arc); pcb_poly_restore_to_poly(PCB->Data, PCB_OBJ_ARC, Layer, Arc); pcb_arc_rotate(Layer, Arc, ctx->rotate.center_x, ctx->rotate.center_y, ctx->rotate.cosa, ctx->rotate.sina, ctx->rotate.angle); pcb_poly_clear_from_poly(PCB->Data, PCB_OBJ_ARC, Layer, Arc); pcb_arc_invalidate_draw(Layer, Arc); return Arc; } rnd_angle_t pcb_arc_get_angle(pcb_arc_t *arc, rnd_coord_t x, rnd_coord_t y) { return atan2(-(y - arc->Y), (x - arc->X)) * 180.0 / M_PI + 180.0; } int pcb_arc_get_xy(pcb_arc_t *arc, rnd_angle_t ang, rnd_coord_t *x, rnd_coord_t *y) { if (!pcb_angle_in_arc(arc, ang, 1)) return -1; *x = rnd_round((double)arc->X - (double)arc->Width * cos(ang * RND_M180)); *y = rnd_round((double)arc->Y + (double)arc->Height * sin(ang * RND_M180)); return 0; } void *pcb_arc_insert_point(pcb_opctx_t *ctx, pcb_layer_t *Layer, pcb_arc_t *arc) { rnd_angle_t end_ang = arc->StartAngle + arc->Delta; rnd_coord_t x = pcb_crosshair.X, y = pcb_crosshair.Y; rnd_angle_t angle = pcb_arc_get_angle(arc, x, y); pcb_arc_t *new_arc; if (end_ang > 360.0) end_ang -= 360.0; if (end_ang < -360.0) end_ang += 360.0; if ((arc->Delta < 0) || (arc->Delta > 180)) new_arc = pcb_arc_new(Layer, arc->X, arc->Y, arc->Width, arc->Height, angle, end_ang - angle + 360.0, arc->Thickness, arc->Clearance, arc->Flags, rnd_true); else new_arc = pcb_arc_new(Layer, arc->X, arc->Y, arc->Width, arc->Height, angle, end_ang - angle, arc->Thickness, arc->Clearance, arc->Flags, rnd_true); if (new_arc != NULL) { pcb_arc_copy_meta(new_arc, arc); PCB_FLAG_CHANGE(PCB_CHGFLG_SET, PCB_FLAG_FOUND, new_arc); if (arc->Delta < 0) pcb_arc_set_angles(Layer, arc, arc->StartAngle, angle - arc->StartAngle - 360.0); else pcb_arc_set_angles(Layer, arc, arc->StartAngle, angle - arc->StartAngle); pcb_undo_add_obj_to_create(PCB_OBJ_ARC, Layer, new_arc, new_arc); } return new_arc; } void *pcb_arcop_change_flag(pcb_opctx_t *ctx, pcb_layer_t *Layer, pcb_arc_t *Arc) { static pcb_flag_values_t pcb_arc_flags = 0; if (pcb_arc_flags == 0) pcb_arc_flags = pcb_obj_valid_flags(PCB_OBJ_ARC); if ((ctx->chgflag.flag & pcb_arc_flags) != ctx->chgflag.flag) return NULL; if ((ctx->chgflag.flag & PCB_FLAG_TERMNAME) && (Arc->term == NULL)) return NULL; pcb_undo_add_obj_to_flag(Arc); if (ctx->chgflag.flag & PCB_FLAG_CLEARLINE) pcb_poly_restore_to_poly(ctx->chgflag.pcb->Data, PCB_OBJ_ARC, Arc->parent.layer, Arc); PCB_FLAG_CHANGE(ctx->chgflag.how, ctx->chgflag.flag, Arc); if (ctx->chgflag.flag & PCB_FLAG_CLEARLINE) pcb_poly_clear_from_poly(ctx->chgflag.pcb->Data, PCB_OBJ_ARC, Arc->parent.layer, Arc); return Arc; } void *pcb_arcop_invalidate_label(pcb_opctx_t *ctx, pcb_layer_t *layer, pcb_arc_t *arc) { pcb_arc_name_invalidate_draw(arc); return arc; } /*** draw ***/ static void arc_label_pos(const pcb_arc_t *arc, rnd_coord_t *x0, rnd_coord_t *y0, rnd_bool_t *vert) { double da, ea, la; da = RND_CLAMP(arc->Delta, -360, 360); ea = arc->StartAngle + da; while(ea < -360) ea += 360; while(ea > +360) ea -= 360; la = (arc->StartAngle+ea)/2.0; *x0 = rnd_round((double)arc->X - (double)arc->Width * cos(la * RND_M180)); *y0 = rnd_round((double)arc->Y + (double)arc->Height * sin(la * RND_M180)); *vert = (((la < 45) && (la > -45)) || ((la > 135) && (la < 225))); } void pcb_arc_middle(const pcb_arc_t *arc, rnd_coord_t *x, rnd_coord_t *y) { rnd_bool_t waste; arc_label_pos(arc, x, y, &waste); } void pcb_arc_approx(const pcb_arc_t *arc, double res, int reverse, void *uctx, int (*cb)(void *uctx, rnd_coord_t x, rnd_coord_t y)) { double a, da = arc->Delta, sa, ea, ea2, step; while(da < -360.0) da = -360.0; while(da > +360.0) da = +360.0; if (!reverse) { sa = arc->StartAngle; ea = sa + da; } else { sa = arc->StartAngle + da; ea = arc->StartAngle; da = -da; } if (res == 0) res = RND_MM_TO_COORD(-1); if (res < 0) { double arclen, delta; delta = arc->Delta; if (delta < 0) delta = -delta; arclen = M_PI * ((double)arc->Width + (double)arc->Height) / 360.0 * delta; step = delta / (arclen / -res); } else step = res; if (ea > sa) { if (step < 0) step = -step; ea2 = ea - step/3; for(a = sa; a < ea2; a += step) if (cb(uctx, rnd_round((double)arc->X - (double)arc->Width * cos(a * RND_M180)), rnd_round((double)arc->Y + (double)arc->Height * sin(a * RND_M180))) != 0) return; } else { if (step > 0) step = +step; ea2 = ea + step/3; for(a = sa; a > ea2; a -= step) if (cb(uctx, rnd_round((double)arc->X - (double)arc->Width * cos(a * RND_M180)), rnd_round((double)arc->Y + (double)arc->Height * sin(a * RND_M180))) != 0) return; } cb(uctx, rnd_round((double)arc->X - (double)arc->Width * cos(ea * RND_M180)), rnd_round((double)arc->Y + (double)arc->Height * sin(ea * RND_M180))); } void pcb_arc_name_invalidate_draw(pcb_arc_t *arc) { if (arc->term != NULL) { rnd_coord_t x0, y0; rnd_bool_t vert; arc_label_pos(arc, &x0, &y0, &vert); pcb_term_label_invalidate(x0, y0, 100.0, vert, rnd_true, (pcb_any_obj_t *)arc); } } void pcb_arc_draw_label(pcb_draw_info_t *info, pcb_arc_t *arc, rnd_bool vis_side) { if ((arc->term != NULL) && vis_side) { rnd_coord_t x0, y0; rnd_bool_t vert; arc_label_pos(arc, &x0, &y0, &vert); pcb_term_label_draw(info, x0, y0, conf_core.appearance.term_label_size, vert, rnd_true, (pcb_any_obj_t *)arc); } if (arc->noexport && vis_side) { rnd_coord_t cx, cy; pcb_arc_middle(arc, &cx, &cy); pcb_obj_noexport_mark(arc, cx, cy); } if (arc->ind_editpoint) { rnd_coord_t x1, y1, x2, y2; pcb_obj_editpont_setup(); pcb_arc_get_end(arc, 0, &x1, &y1); pcb_arc_get_end(arc, 1, &x2, &y2); pcb_obj_editpont_cross(arc->X, arc->Y); if ((arc->X != x1) || (arc->Y != y1)) pcb_obj_editpont_cross(x1, y1); if ((x2 != x1) || (y2 != y1)) pcb_obj_editpont_cross(x2, y2); } } void pcb_arc_draw_(pcb_draw_info_t *info, pcb_arc_t *arc, int allow_term_gfx) { rnd_coord_t thickness = arc->Thickness; int draw_lab; if (arc->Thickness < 0) return; if (delayed_terms_enabled && (arc->term != NULL)) { pcb_draw_delay_obj_add((pcb_any_obj_t *)arc); return; } if ((info != NULL) && (info->xform != NULL) && (info->xform->bloat != 0)) { thickness += info->xform->bloat; if (thickness < 1) thickness = 1; } PCB_DRAW_BBOX(arc); if (!info->xform->thin_draw && !info->xform->wireframe) { if ((allow_term_gfx) && pcb_draw_term_need_gfx(arc) && pcb_draw_term_hid_permission()) { rnd_hid_set_line_cap(pcb_draw_out.active_padGC, rnd_cap_round); rnd_hid_set_line_width(pcb_draw_out.active_padGC, thickness); rnd_render->draw_arc(pcb_draw_out.active_padGC, arc->X, arc->Y, arc->Width, arc->Height, arc->StartAngle, arc->Delta); rnd_hid_set_line_width(pcb_draw_out.fgGC, PCB_DRAW_TERM_GFX_WIDTH); } else rnd_hid_set_line_width(pcb_draw_out.fgGC, thickness); rnd_hid_set_line_cap(pcb_draw_out.fgGC, rnd_cap_round); rnd_render->draw_arc(pcb_draw_out.fgGC, arc->X, arc->Y, arc->Width, arc->Height, arc->StartAngle, arc->Delta); } else { rnd_hid_set_line_width(pcb_draw_out.fgGC, 0); rnd_hid_set_line_cap(pcb_draw_out.fgGC, rnd_cap_round); if(info->xform->thin_draw) rnd_render->draw_arc(pcb_draw_out.fgGC, arc->X, arc->Y, arc->Width, arc->Height, arc->StartAngle, arc->Delta); if(info->xform->wireframe) pcb_draw_wireframe_arc(pcb_draw_out.fgGC, arc, thickness); } draw_lab = (arc->term != NULL) && ((pcb_draw_force_termlab) || PCB_FLAG_TEST(PCB_FLAG_TERMNAME, arc)); draw_lab |= arc->ind_editpoint; if (draw_lab) pcb_draw_delay_label_add((pcb_any_obj_t *)arc); } static void pcb_arc_draw(pcb_draw_info_t *info, pcb_arc_t *arc, int allow_term_gfx) { const rnd_color_t *color; rnd_color_t buf; const pcb_layer_t *layer = info->layer != NULL ? info->layer : pcb_layer_get_real(arc->parent.layer); pcb_obj_noexport(info, arc, return); if (layer == NULL) /* if the layer is inbound, e.g. in preview, fall back using the layer recipe */ layer = arc->parent.layer; if (info->xform->flag_color && PCB_FLAG_TEST(PCB_FLAG_WARN, arc)) color = &conf_core.appearance.color.warn; else if (info->xform->flag_color && PCB_FLAG_TEST(PCB_FLAG_SELECTED | PCB_FLAG_FOUND, arc)) { if (PCB_FLAG_TEST(PCB_FLAG_SELECTED, arc)) { if (layer->is_bound) PCB_OBJ_COLOR_ON_BOUND_LAYER(color, layer, 1); else color = &conf_core.appearance.color.selected; } else color = &conf_core.appearance.color.connected; } else if (PCB_HAS_COLOROVERRIDE(arc)) { color = arc->override_color; } else if (layer->is_bound) PCB_OBJ_COLOR_ON_BOUND_LAYER(color, layer, 0); else color = &layer->meta.real.color; if (info->xform->flag_color && arc->ind_onpoint) { pcb_lighten_color(color, &buf, 1.75); color = &buf; } rnd_render->set_color(pcb_draw_out.fgGC, color); pcb_arc_draw_(info, arc, allow_term_gfx); } rnd_rtree_dir_t pcb_arc_draw_callback(void *cl, void *obj, const rnd_rtree_box_t *box) { pcb_arc_t *arc = (pcb_arc_t *)obj; pcb_draw_info_t *info = cl; if (pcb_hidden_floater((pcb_any_obj_t*)obj, info) || pcb_partial_export((pcb_any_obj_t*)obj, info)) return rnd_RTREE_DIR_FOUND_CONT; if (!PCB->SubcPartsOn && pcb_lobj_parent_subc(arc->parent_type, &arc->parent)) return rnd_RTREE_DIR_NOT_FOUND_CONT; pcb_arc_draw(info, arc, 0); return rnd_RTREE_DIR_FOUND_CONT; } rnd_rtree_dir_t pcb_arc_draw_term_callback(void *cl, void *obj, const rnd_rtree_box_t *box) { pcb_arc_t *arc = (pcb_arc_t *)obj; pcb_draw_info_t *info = cl; if (pcb_hidden_floater((pcb_any_obj_t*)obj, info) || pcb_partial_export((pcb_any_obj_t*)obj, info)) return rnd_RTREE_DIR_FOUND_CONT; if (!PCB->SubcPartsOn && pcb_lobj_parent_subc(arc->parent_type, &arc->parent)) return rnd_RTREE_DIR_NOT_FOUND_CONT; pcb_arc_draw(info, arc, 1); return rnd_RTREE_DIR_FOUND_CONT; } /* erases an arc on a layer */ void pcb_arc_invalidate_erase(pcb_arc_t *Arc) { if (!Arc->Thickness) return; pcb_draw_invalidate(Arc); } void pcb_arc_invalidate_draw(pcb_layer_t *Layer, pcb_arc_t *Arc) { pcb_draw_invalidate(Arc); }