/* * COPYRIGHT * * pcb-rnd, interactive printed circuit board design * (this file is based on PCB, interactive printed circuit board design) * Copyright (C) 1994,1995,1996, 2005 Thomas Nau * * 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") * */ #include "config.h" #include #include #include "conf_core.h" #include "flag_str.h" #include #include #include "obj_common.h" #include "obj_arc_ui.h" #include "obj_pstk.h" #include "obj_subc.h" #include "obj_subc_parent.h" #include "obj_term.h" #include "extobj.h" const char *pcb_obj_type_name(pcb_objtype_t type) { switch(type) { case PCB_OBJ_VOID: return "void"; case PCB_OBJ_LINE: return "line"; case PCB_OBJ_TEXT: return "text"; case PCB_OBJ_POLY: return "polygon"; case PCB_OBJ_ARC: return "arc"; case PCB_OBJ_RAT: return "ratline"; case PCB_OBJ_GFX: return "gfx"; case PCB_OBJ_PSTK: return "padstack"; case PCB_OBJ_SUBC: return "subcircuit"; case PCB_OBJ_NET: return "net"; case PCB_OBJ_NET_TERM: return "net_term"; case PCB_OBJ_LAYER: return "layer"; case PCB_OBJ_LAYERGRP: return "layer_group"; } switch((pcb_vobjtype_t)type) { case PCB_OBJ_LINE_POINT: return "line_point"; case PCB_OBJ_POLY_POINT: return "poly_point"; case PCB_OBJ_ARC_POINT: return "arc_point"; case PCB_OBJ_SUBC_PART: return "subc_part"; case PCB_OBJ_LOCKED: return "locked"; case PCB_OBJ_FLOATER: return "floater"; case PCB_OBJ_GFX_POINT: return "gfx_point"; } return ""; } /* returns a pointer to an objects bounding box; * data is valid until the routine is called again */ int pcb_obj_get_bbox_naked(int Type, void *Ptr1, void *Ptr2, void *Ptr3, rnd_box_t *res) { switch (Type) { case PCB_OBJ_LINE: case PCB_OBJ_ARC: case PCB_OBJ_TEXT: case PCB_OBJ_POLY: case PCB_OBJ_PSTK: case PCB_OBJ_GFX: *res = ((pcb_any_obj_t *)Ptr2)->bbox_naked; return 0; case PCB_OBJ_SUBC: *res = ((pcb_any_obj_t *)Ptr1)->bbox_naked; return 0; case PCB_OBJ_POLY_POINT: case PCB_OBJ_LINE_POINT: case PCB_OBJ_GFX_POINT: *res = *(rnd_box_t *)Ptr3; return 0; case PCB_OBJ_ARC_POINT: return pcb_obj_ui_arc_point_bbox(Type, Ptr1, Ptr2, Ptr3, res); default: rnd_message(RND_MSG_ERROR, "Request for bounding box of unsupported type %d\n", Type); *res = *(rnd_box_t *)Ptr2; return -1; } } /* current object ID; incremented after each creation of an object */ long int ID = 1; rnd_bool pcb_create_being_lenient = rnd_false; void pcb_create_be_lenient(rnd_bool v) { pcb_create_being_lenient = v; } void pcb_create_ID_bump(int min_id) { if (ID < min_id) ID = min_id; } void pcb_create_ID_reset(void) { ID = 1; } long int pcb_create_ID_get(void) { return ID++; } static void pcb_attribute_copy_all_smart(pcb_attribute_list_t *dest, const pcb_attribute_list_t *src, pcb_any_obj_t *dstobj, pcb_any_obj_t *copy_from_any) { int i; for (i = 0; i < src->Number; i++) pcb_attribute_put(dest, src->List[i].name, src->List[i].value); } void pcb_obj_add_attribs(pcb_any_obj_t *o, const pcb_attribute_list_t *src, pcb_any_obj_t *copy_from) { if (src == NULL) return; if (copy_from) pcb_attribute_copy_all_smart(&o->Attributes, src, o, copy_from); else pcb_attribute_copy_all(&o->Attributes, src); } void pcb_obj_center(const pcb_any_obj_t *obj, rnd_coord_t *x, rnd_coord_t *y) { switch (obj->type) { case PCB_OBJ_PSTK: *x = ((const pcb_pstk_t *)(obj))->x; *y = ((const pcb_pstk_t *)(obj))->y; break; case PCB_OBJ_ARC: pcb_arc_middle((const pcb_arc_t *)obj, x, y); break; default: *x = (obj->BoundingBox.X1 + obj->BoundingBox.X2) / 2; *y = (obj->BoundingBox.Y1 + obj->BoundingBox.Y2) / 2; } } void pcb_obj_attrib_post_change(pcb_attribute_list_t *list, const char *name, const char *value) { pcb_any_obj_t *obj = (pcb_any_obj_t *)(((char *)list) - offsetof(pcb_any_obj_t, Attributes)); if (strcmp(name, "term") == 0) { const char *inv; pcb_subc_t *subc = pcb_obj_parent_subc(obj); if ((subc != NULL) && (obj->term != NULL)) /* remove the old term */ pcb_term_del(&subc->terminals, obj->term, obj); obj->term = value; if ((subc != NULL) && (obj->term != NULL)) /* add the new term */ pcb_term_add(&subc->terminals, obj); inv = pcb_obj_id_invalid(obj->term); if (inv != NULL) rnd_message(RND_MSG_ERROR, "Invalid character '%c' in terminal name (term attribute) '%s'\n", *inv, obj->term); } else if (strcmp(name, "intconn") == 0) { long cid = 0; if (value != NULL) { char *end; cid = strtol(value, &end, 10); if (*end != '\0') cid = 0; } obj->intconn = cid; } else if (strcmp(name, "intnoconn") == 0) { long cid = 0; if (value != NULL) { char *end; cid = strtol(value, &end, 10); if (*end != '\0') cid = 0; } obj->intnoconn = cid; } else if (strncmp(name, "noexport", 8) == 0) { obj->noexport = 1; obj->noexport_named = (name[8] == ':'); } else if (strncmp(name, "extobj::", 8) == 0) { const char *arg = name+8; if (strcmp(arg, "role") == 0) obj->extobj_role = value; } else if ((obj->type == PCB_OBJ_TEXT) && (strcmp(name, "tight_clearance") == 0)) { pcb_text_t *t = (pcb_text_t *)obj; t->tight_clearance = rnd_istrue(value); } else if ((obj->type == PCB_OBJ_TEXT) && (strcmp(name, "mirror_x") == 0)) { pcb_text_t *t = (pcb_text_t *)obj; t->mirror_x = rnd_istrue(value); } else if ((obj->type == PCB_OBJ_GFX) && (strcmp(name, "render_level") == 0)) { pcb_gfx_t *g = (pcb_gfx_t *)obj; if ((value != NULL) && ((*value == 'u') || (*value == 'U'))) g->render_under = 1; else g->render_under = 0; } } const char *pcb_obj_id_invalid(const char *id) { const char *s; if (id != NULL) for(s = id; *s != '\0'; s++) { if (isalnum(*s)) continue; switch(*s) { case '_': case '.': case '$': case '*': case ':': continue; } return s; } return NULL; } char *pcb_obj_id_fix(char *id) { char *s; if (id == NULL) return NULL; for(s = id; *s != '\0'; s++) { if (isalnum(*s)) continue; switch(*s) { case '_': case '.': case '$': case '*': case ':': continue; default: *s = '_'; } } return id; } pcb_flag_values_t pcb_obj_valid_flags(unsigned long int objtype) { pcb_flag_values_t res = 0; int n; for(n = 0; n < pcb_object_flagbits_len; n++) if (pcb_object_flagbits[n].object_types & objtype) res |= pcb_object_flagbits[n].mask; return res; } rnd_coord_t pcb_obj_clearance_at(pcb_board_t *pcb, const pcb_any_obj_t *o, pcb_layer_t *at) { switch(o->type) { case PCB_OBJ_POLY: if (!(PCB_POLY_HAS_CLEARANCE((pcb_poly_t *)o))) return 0; return ((pcb_poly_t *)o)->Clearance; case PCB_OBJ_LINE: if (!(PCB_NONPOLY_HAS_CLEARANCE((pcb_line_t *)o))) return 0; return ((pcb_line_t *)o)->Clearance; case PCB_OBJ_TEXT: return 0; case PCB_OBJ_ARC: if (!(PCB_NONPOLY_HAS_CLEARANCE((pcb_arc_t *)o))) return 0; return ((pcb_arc_t *)o)->Clearance; case PCB_OBJ_PSTK: return obj_pstk_get_clearance(pcb, (pcb_pstk_t *)o, at); default: return 0; } } static void mmult(pcb_xform_mx_t dst, const pcb_xform_mx_t src) { pcb_xform_mx_t tmp; tmp[0] = dst[0] * src[0] + dst[1] * src[3] + dst[2] * src[6]; tmp[1] = dst[0] * src[1] + dst[1] * src[4] + dst[2] * src[7]; tmp[2] = dst[0] * src[2] + dst[1] * src[5] + dst[2] * src[8]; tmp[3] = dst[3] * src[0] + dst[4] * src[3] + dst[5] * src[6]; tmp[4] = dst[3] * src[1] + dst[4] * src[4] + dst[5] * src[7]; tmp[5] = dst[3] * src[2] + dst[4] * src[5] + dst[5] * src[8]; tmp[6] = dst[6] * src[0] + dst[7] * src[3] + dst[8] * src[6]; tmp[7] = dst[6] * src[1] + dst[7] * src[4] + dst[8] * src[7]; tmp[8] = dst[6] * src[2] + dst[7] * src[5] + dst[8] * src[8]; memcpy(dst, tmp, sizeof(tmp)); } void pcb_xform_mx_rotate(pcb_xform_mx_t mx, double deg) { pcb_xform_mx_t tr; deg /= RND_RAD_TO_DEG; tr[0] = cos(deg); tr[1] = sin(deg); tr[2] = 0; tr[3] = -sin(deg); tr[4] = cos(deg); tr[5] = 0; tr[6] = 0; tr[7] = 0; tr[8] = 1; mmult(mx, tr); } void pcb_xform_mx_translate(pcb_xform_mx_t mx, double xt, double yt) { pcb_xform_mx_t tr; tr[0] = 1; tr[1] = 0; tr[2] = xt; tr[3] = 0; tr[4] = 1; tr[5] = yt; tr[6] = 0; tr[7] = 0; tr[8] = 1; mmult(mx, tr); } void pcb_xform_mx_scale(pcb_xform_mx_t mx, double sx, double sy) { pcb_xform_mx_t tr; tr[0] = sx; tr[1] = 0; tr[2] = 0; tr[3] = 0; tr[4] = sy; tr[5] = 0; tr[6] = 0; tr[7] = 0; tr[8] = 1; mmult(mx, tr); } void pcb_xform_mx_shear(pcb_xform_mx_t mx, double sx, double sy) { pcb_xform_mx_t tr; tr[0] = 1; tr[1] = sx; tr[2] = 0; tr[3] = sy; tr[4] = 1; tr[5] = 0; tr[6] = 0; tr[7] = 0; tr[8] = 1; mmult(mx, tr); } void pcb_xform_mx_mirrorx(pcb_xform_mx_t mx) { pcb_xform_mx_scale(mx, 0, -1); } void pcb_obj_pre(pcb_any_obj_t *o) { switch(o->type) { case PCB_OBJ_LINE: pcb_line_pre((pcb_line_t *)o); break; case PCB_OBJ_TEXT: pcb_text_pre((pcb_text_t *)o); break; case PCB_OBJ_POLY: pcb_poly_pre((pcb_poly_t *)o); break; case PCB_OBJ_ARC: pcb_arc_pre((pcb_arc_t *)o); break; case PCB_OBJ_GFX: pcb_gfx_pre((pcb_gfx_t *)o); break; case PCB_OBJ_PSTK: pcb_pstk_pre((pcb_pstk_t *)o); break; default: break; } } void pcb_obj_post(pcb_any_obj_t *o) { switch(o->type) { case PCB_OBJ_LINE: pcb_line_post((pcb_line_t *)o); break; case PCB_OBJ_TEXT: pcb_text_post((pcb_text_t *)o); break; case PCB_OBJ_POLY: pcb_poly_post((pcb_poly_t *)o); break; case PCB_OBJ_ARC: pcb_arc_post((pcb_arc_t *)o); break; case PCB_OBJ_GFX: pcb_gfx_post((pcb_gfx_t *)o); break; case PCB_OBJ_PSTK: pcb_pstk_post((pcb_pstk_t *)o); break; default: break; } } void pcb_obj_change_id(pcb_any_obj_t *obj, long int new_id) { pcb_data_t *data; if (obj->parent_type == PCB_PARENT_DATA) data = obj->parent.data; else if (obj->parent_type == PCB_PARENT_LAYER) data = obj->parent.layer->parent.data; else return; pcb_obj_id_del(data, obj); obj->ID = new_id; pcb_obj_id_reg(data, obj); } void pcb_set_point_bounding_box(rnd_point_t *Pnt) { Pnt->X2 = Pnt->X + 1; Pnt->Y2 = Pnt->Y + 1; } void pcb_obj_common_free(pcb_any_obj_t *o) { if (o->override_color != NULL) { free(o->override_color); o->override_color = NULL; } pcb_flag_uninit(&o->Flags); } unsigned char *pcb_obj_common_get_thermal(pcb_any_obj_t *obj, unsigned long lid, rnd_bool_t alloc) { if (obj->type == PCB_OBJ_PSTK) return pcb_pstk_get_thermal((pcb_pstk_t *)obj, lid, alloc); return &obj->thermal; } void pcb_obj_update_bbox(pcb_board_t *pcb, pcb_any_obj_t *obj) { switch(obj->type) { case PCB_OBJ_ARC: pcb_arc_bbox((pcb_arc_t *)obj); break; case PCB_OBJ_LINE: pcb_line_bbox((pcb_line_t *)obj); break; case PCB_OBJ_POLY: pcb_poly_bbox((pcb_poly_t *)obj); break; case PCB_OBJ_TEXT: pcb_text_bbox(pcb_font(pcb, ((pcb_text_t *)obj)->fid, 1), (pcb_text_t *)obj); break; case PCB_OBJ_SUBC: pcb_subc_bbox((pcb_subc_t *)obj); break; case PCB_OBJ_PSTK: pcb_pstk_bbox((pcb_pstk_t *)obj); break; case PCB_OBJ_GFX: pcb_gfx_bbox((pcb_gfx_t *)obj); break; case PCB_OBJ_RAT: case PCB_OBJ_VOID: case PCB_OBJ_NET: case PCB_OBJ_NET_TERM: case PCB_OBJ_LAYER: case PCB_OBJ_LAYERGRP: /* these don't have bbox */ break; } }