/* * COPYRIGHT * * pcb-rnd, interactive printed circuit board design * (this file is based on PCB, interactive printed circuit board design) * Copyright (C) 1994,1995,1996,2006 Thomas Nau * Copyright (C) 2016,2019 Tibor 'Igor2' Palinkas (pcb-rnd extensions) * * 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") * */ #ifndef PCB_LAYER_H #define PCB_LAYER_H /* Layer type bitfield */ typedef enum { /* Stack-up (vertical position): */ PCB_LYT_TOP = 0x00000001, /* layer is on the top side of the board */ PCB_LYT_BOTTOM = 0x00000002, /* layer is on the bottom side of the board */ PCB_LYT_INTERN = 0x00000004, /* layer is internal */ PCB_LYT_LOGICAL = 0x00000008, /* does not depend on the layer stackup (typically aux drawing layer) */ PCB_LYT_ANYWHERE = 0x000000FF, /* MASK: layer is anywhere on the stack */ /* What the layer consists of (main type) */ PCB_LYT_COPPER = 0x00000100, /* copper objects */ PCB_LYT_SILK = 0x00000200, /* silk objects */ PCB_LYT_MASK = 0x00000400, /* solder mask */ PCB_LYT_PASTE = 0x00000800, /* paste */ PCB_LYT_RAT = 0x00002000, /* (virtual) rats nest (one, not in the stackup) */ PCB_LYT_INVIS = 0x00004000, /* (virtual) layer is invisible (one, not in the stackup) */ PCB_LYT_BOUNDARY = 0x00008000, /* physical boundaries of the board (inner and outer): route, cuts, slots, drills */ PCB_LYT_UI = 0x00080000, /* (virtual) user interface drawings (feature plugins use this for displaying states or debug info) */ PCB_LYT_SUBSTRATE= 0x00200000, /* substrate / insulator */ PCB_LYT_MISC = 0x00400000, /* misc (for internal use) */ PCB_LYT_DIALOG = 0x00800000, /* (virtual) dialog box drawings (e.g. font selector) - not to be interpreted in the board space */ PCB_LYT_DOC = 0x01000000, /* misc documentation layers - user allocated, largely ignored by the code */ PCB_LYT_MECH = 0x02000000, /* misc mechanical/physical layers (e.g. adhesive, keepouts) */ PCB_LYT_ANYTHING = 0x0FFFFF00, /* MASK: layers consist anything */ /* misc properties */ PCB_LYT_VIRTUAL = 0x10000000, /* the layer is not in the layer array (generated layer) */ PCB_LYT_NOEXPORT = 0x20000000, /* should not show up in any of the exports */ PCB_LYT_ANYPROP = 0x70000000 /* MASK: misc layer properties */ } pcb_layer_type_t; typedef enum { PCB_VLY_INVISIBLE, PCB_VLY_RATS, PCB_VLY_TOP_ASSY, PCB_VLY_BOTTOM_ASSY, PCB_VLY_FAB, PCB_VLY_PLATED_DRILL, PCB_VLY_UNPLATED_DRILL, PCB_VLY_CSECT, /* for determining the range, do not use */ PCB_VLY_end, PCB_VLY_first = PCB_VLY_INVISIBLE } pcb_virtual_layer_t; typedef enum { /* bitfield */ PCB_LYC_SUB = 1, /* bit 0 is 0 for add or 1 for sub */ PCB_LYC_AUTO = 2 /* bit 1 is 0 for manual drawn layer or 1 for side-effect objects from padstacks; this is how the user controls on which composite mask/paste layer padstack side effects should appear */ } pcb_layer_combining_t; #define PCB_LAYER_IN_STACK(lyt) (((lyt) & PCB_LYT_COPPER) || ((lyt) & PCB_LYT_SILK) || ((lyt) & PCB_LYT_MASK) || ((lyt) & PCB_LYT_PASTE) || ((lyt) & PCB_LYT_SUBSTRATE)) #define PCB_LAYER_SIDED(lyt) (((lyt) & PCB_LYT_COPPER) || ((lyt) & PCB_LYT_SILK) || ((lyt) & PCB_LYT_MASK) || ((lyt) & PCB_LYT_PASTE) || ((lyt) & PCB_LYT_DOC)) #define PCB_LAYER_IS_VASSY(lyt, purpi) (((lyt) & PCB_LYT_VIRTUAL) && ((purpi) == F_assy)) #define PCB_LAYER_IS_RASSY(lyt, purpi) (((lyt) & PCB_LYT_DOC) && ((purpi) == F_assy)) #define PCB_LAYER_IS_ASSY(lyt, purpi) (PCB_LAYER_IS_VASSY(lyt, purpi)||PCB_LAYER_IS_RASSY(lyt, purpi)) #define PCB_LAYER_IS_VFAB(lyt, purpi) (((lyt) & PCB_LYT_VIRTUAL) && ((purpi) == F_fab)) #define PCB_LAYER_IS_RFAB(lyt, purpi) (((lyt) & PCB_LYT_DOC) && ((purpi) == F_fab)) #define PCB_LAYER_IS_FAB(lyt, purpi) (PCB_LAYER_IS_VFAB(lyt, purpi) || PCB_LAYER_IS_RFAB(lyt, purpi)) #define PCB_LAYER_IS_CSECT(lyt, purpi) (((lyt) & PCB_LYT_VIRTUAL) && ((purpi) == F_csect)) #define PCB_LAYER_IS_PDRILL(lyt, purpi) (((lyt) & PCB_LYT_VIRTUAL) && ((purpi) == F_pdrill)) #define PCB_LAYER_IS_UDRILL(lyt, purpi) (((lyt) & PCB_LYT_VIRTUAL) && ((purpi) == F_udrill)) #define PCB_LAYER_IS_DRILL(lyt, purpi) (((lyt) & PCB_LYT_VIRTUAL) && (((purpi) == F_pdrill) || ((purpi) == F_udrill))) /* Route must be on a mech or boundary layer */ #define PCB_LAYER_IS_UROUTE(lyt, purpi) (((lyt) & (PCB_LYT_BOUNDARY | PCB_LYT_MECH)) && ((((purpi) == F_uroute)))) #define PCB_LAYER_IS_PROUTE(lyt, purpi) (((lyt) & (PCB_LYT_BOUNDARY | PCB_LYT_MECH)) && (((purpi) == F_proute))) #define PCB_LAYER_IS_ROUTE(lyt, purpi) (((lyt) & (PCB_LYT_BOUNDARY | PCB_LYT_MECH)) && (((purpi) == F_proute) || ((purpi) == F_uroute))) /* Outline is a route in a boundary group; outline in this sense means the "perimeter of the board", but could include largish internal cutout - the user needs to be explicit about this. Mech layers are NOT included, that's the difference compared to routed layers */ #define PCB_LAYER_IS_OUTLINE(lyt, purpi) (((lyt) & PCB_LYT_BOUNDARY) && (((purpi) == F_proute) || ((purpi) == F_uroute) || ((purpi) == F_ucut) || ((purpi) == F_uvcut))) #include "globalconst.h" #include #include #include "attrib.h" #include "obj_common.h" #include "obj_arc_list.h" #include "obj_line_list.h" #include "obj_poly_list.h" #include "obj_text_list.h" #include "obj_gfx_list.h" #include "global_typedefs.h" struct pcb_layer_s { /* holds information about one layer */ PCB_ANY_OBJ_FIELDS; linelist_t Line; textlist_t Text; polylist_t Polygon; arclist_t Arc; gfxlist_t Gfx; const char *name; /* layer name */ pcb_layer_combining_t comb; /* how to combine this layer with other layers in the group */ /* for bound layers these point to the board layer's*/ rnd_rtree_t *line_tree, *text_tree, *polygon_tree, *arc_tree, *gfx_tree; union { struct { /* A real board layer */ rnd_layergrp_id_t grp; /* the group this layer is in (cross-reference) */ rnd_bool vis; /* visible flag */ rnd_color_t color; /* copied */ int no_drc; /* whether to ignore the layer when checking the design rules */ const char *cookie; /* for UI layers: registration cookie; NULL for unused UI layers */ rnd_xform_t xform; /* layer specified rendering transformation */ rnd_xform_t gui_xform; /* GUI-render only layer specified rendering transformation */ } real; struct { /* A subcircuit layer binding; list data are local but everything else is coming from board layers */ pcb_layer_t *real; /* NULL if unbound */ /* matching rules */ pcb_layer_type_t type; /* for comb, use the ->comb from the common part */ int stack_offs; /* offset in the stack for PCB_LYT_INNER: positive is counted from primary side, negative from the opposite side */ char *purpose; /* what the target doc/mech layer is used for */ } bound; } meta; unsigned is_bound:1; /* Optional: if not NULL, call this instead of rendering objects from layer data, after setting up info an info->xform; lets plugins implement their own custom draw functions */ void (*plugin_draw)(pcb_draw_info_t *info, const pcb_layer_t *Layer); void *plugin_draw_data; }; /* returns the layer number for the passed copper or silk layer pointer */ rnd_layer_id_t pcb_layer_id(const pcb_data_t *Data, const pcb_layer_t *Layer); /* Sddress side of the board without referencing to groups or layers. (Historical use: in io_pcb the index offsets of the two additional special layers (e.g. silk) for 'component' and 'solder'. The offset of PCB_MAX_LAYER is not added here.) */ typedef enum { PCB_SOLDER_SIDE = 0, PCB_COMPONENT_SIDE = 1 } pcb_side_t; /* Return the board the layer is under */ #define pcb_layer_get_top(layer) pcb_data_get_top((layer)->parent.data) typedef struct { const char *name, *abbrev; rnd_color_t const *force_color; const char *select_name; int vis_offs, sel_offs; } pcb_menu_layers_t; extern const pcb_menu_layers_t pcb_menu_layers[]; const pcb_menu_layers_t *pcb_menu_layer_find(const char *name_or_abbrev); /************ OLD API - new code should not use these **************/ #define LAYER_LOOP(data, ml) \ do { \ rnd_cardinal_t n; \ for (n = 0; n < ml; n++) { \ pcb_layer_t *layer = (&data->Layer[(n)]); /************ NEW API - new code should use these **************/ #define PCB_STACKLAYER(pcb, n) (&((pcb)->Data->Layer[pcb_layer_stack[(n)]])) #define PCB_CURRLAYER(pcb) (PCB_STACKLAYER((pcb), 0)) #define PCB_CURRLID(pcb) (pcb_layer_stack[0]) /* Free all metadata and objects of a layer; does not free(layer) */ void pcb_layer_free_fields(pcb_layer_t *layer, rnd_bool undoable); /* Return the layer pointer (or NULL on invalid or virtual layers) for an id */ pcb_layer_t *pcb_get_layer(pcb_data_t *data, rnd_layer_id_t id); /* Return the layer ID within data, or -1 if ly is not in data */ rnd_layer_id_t pcb_layer2id(pcb_data_t *data, pcb_layer_t *ly); /* Return the name of a layer (real or virtual) or NULL on error NOTE: layer names may not be unique; returns the first case sensitive hit; slow linear search */ rnd_layer_id_t pcb_layer_by_name(pcb_data_t *data, const char *name); /* Returns rnd_true if the given layer is empty (there are no objects on the layer) */ rnd_bool pcb_layer_is_empty_(pcb_board_t *pcb, pcb_layer_t *ly); rnd_bool pcb_layer_is_empty(pcb_board_t *pcb, rnd_layer_id_t ly); /* Returns rnd_true if the given layer is empty - non-recursive variant (doesn't deal with side effects) */ rnd_bool pcb_layer_is_pure_empty(pcb_layer_t *layer); /* call the gui to set a virtual layer or the UI layer group */ int pcb_layer_gui_set_vlayer(pcb_board_t *pcb, pcb_virtual_layer_t vid, int is_empty, rnd_xform_t **xform); int pcb_layer_gui_set_g_ui(pcb_layer_t *first, int is_empty, rnd_xform_t **xform); /* returns a bitfield of pcb_layer_type_t; returns 0 if layer_idx or layer is invalid. */ unsigned int pcb_layer_flags(const pcb_board_t *pcb, rnd_layer_id_t layer_idx); unsigned int pcb_layer_flags_(const pcb_layer_t *layer); /* Return the purpi of the group of a layer; if out is not NULL, also copy a pointer to the purpose string there (valid until a layer change) */ int pcb_layer_purpose(const pcb_board_t *pcb, rnd_layer_id_t layer_idx, const char **out); int pcb_layer_purpose_(const pcb_layer_t *layer, const char **out); /* map bits of a layer type (call cb for each bit set); return number of bits found. */ int pcb_layer_type_map(pcb_layer_type_t type, void *ctx, void (*cb)(void *ctx, pcb_layer_type_t bit, const char *name, int class, const char *class_name)); int pcb_layer_comb_map(pcb_layer_combining_t type, void *ctx, void (*cb)(void *ctx, pcb_layer_combining_t bit, const char *name)); /* return 0 or the flag value correspoding to name (linear search) */ pcb_layer_type_t pcb_layer_type_str2bit(const char *name); pcb_layer_type_t pcb_layer_type_strn2bit(const char *name, size_t len); pcb_layer_combining_t pcb_layer_comb_str2bit(const char *name); /* Convert a list of types/combs from string to bits. Returns 0 on success. The string is separated by any non-alpha character and is case insensitive. If allow_implicit_lyc is true, improvise the value of *lyc using *lyt if no comb flag was explicitly specified in the string. */ int pcb_layer_typecomb_str2bits(const char *str, pcb_layer_type_t *lyt, pcb_layer_combining_t *lyc, rnd_bool allow_implicit_lyc); /* return the name of a type bit; type should have only one bit set */ const char *pcb_layer_type_bit2str(pcb_layer_type_t type); /* Various fixes for old/plain/flat layer stack imports vs. composite layers */ void pcb_layer_auto_fixup(pcb_board_t *pcb); /* List layer IDs that matches mask - write the first res_len items in res, if res is not NULL. Returns: - the total number of layers matching the query, if res is NULL - the number of layers copied into res if res is not NULL The plain version require exact match (look for a specific layer), the _any version allows partial match so work with PCB_LYT_ANY*. The version that ends in 'p' also matches purpose if purpi is not -1 and/or purpose is not NULL. */ int pcb_layer_list(const pcb_board_t *pcb, pcb_layer_type_t mask, rnd_layer_id_t *res, int res_len); int pcb_layer_list_any(const pcb_board_t *pcb, pcb_layer_type_t mask, rnd_layer_id_t *res, int res_len); int pcb_layer_listp(const pcb_board_t *pcb, pcb_layer_type_t mask, rnd_layer_id_t *res, int res_len, int purpi, const char *purpose); /**** layer creation (for load/import code) ****/ /* Set parent and attribute change callback */ void pcb_layer_setup(pcb_layer_t *ly, pcb_data_t *parent_data); /* Reset layers and layer groups to empty */ void pcb_layers_reset(pcb_board_t *pcb); /* Create a new layer and put it in an existing group (if grp is not -1). */ rnd_layer_id_t pcb_layer_create(pcb_board_t *pcb, rnd_layergrp_id_t grp, const char *lname, rnd_bool undoable); /* Return the name of a layer (resolving the true name of virtual layers too) */ const char *pcb_layer_name(pcb_data_t *data, rnd_layer_id_t id); /* Return the default color for a new layer from the config */ const rnd_color_t *pcb_layer_default_color(int idx, pcb_layer_type_t lyt); /* Rename/recolor an existing layer by idx */ int pcb_layer_rename(pcb_data_t *data, rnd_layer_id_t layer, const char *lname, rnd_bool undoable); int pcb_layer_recolor(pcb_data_t *data, rnd_layer_id_t layer, const char *lcolor, rnd_bool undoable); /* Change the combination flags of a layer */ int pcb_layer_recomb(pcb_layer_t *Layer, pcb_layer_combining_t comb, rnd_bool undoable); /* changes the color of a layer; string has to be allocated by the caller (pcb_strdup) */ int pcb_layer_rename_(pcb_layer_t *Layer, char *Name, rnd_bool undoable); /* Low level layer color change, parsed color must be available */ int pcb_layer_recolor_(pcb_layer_t *Layer, const rnd_color_t *color, rnd_bool undoable); /* index is 0..PCB_MAX_LAYER-1. If old_index is -1, a new layer is inserted at that index. If new_index is -1, the specified layer is deleted. Returns non-zero on error, zero if OK. */ int pcb_layer_move(pcb_board_t *pcb, rnd_layer_id_t old_index, rnd_layer_id_t new_index, rnd_layergrp_id_t new_in_grp, rnd_bool undoable); /* set up dst to be a bound layer with the right offset in the stack; src_pcb is used for the layer stack of src. Assumes other fields of dst, e.g. name, are all set up. */ void pcb_layer_real2bound_offs(pcb_layer_t *dst, pcb_board_t *src_pcb, pcb_layer_t *src); /* Set up dst so that it's a non-real layer bound to src */ void pcb_layer_real2bound(pcb_layer_t *dst, pcb_layer_t *src, int share_rtrees); /* Assume src is a bound layer; find the closest match in pcb's layer stack */ pcb_layer_t *pcb_layer_resolve_binding(pcb_board_t *pcb, pcb_layer_t *src); /* Allocate a new bound layer within data, set it up, but do not do the binding */ pcb_layer_t *pcb_layer_new_bound(pcb_data_t *data, pcb_layer_type_t type, const char *name, const char *purpose); /* Calculate a hash of a bound layer (ingoring its name) */ unsigned int pcb_layer_hash_bound(pcb_layer_t *ly, rnd_bool smirror); /* Calculate mirrored version of some (bound) layer properties */ pcb_layer_type_t pcb_layer_mirror_type(pcb_layer_type_t lyt); /* Modify tree pointers in dst to point to src's; allocates trees for src if they are not yet allocated */ void pcb_layer_link_trees(pcb_layer_t *dst, pcb_layer_t *src); /* How deep subcs can be nested */ #define PCB_MAX_BOUND_LAYER_RECURSION 128 /* Return the real layer, resolving layer bindings. Returns NULL on error (e.g. binding loop) */ RND_INLINE pcb_layer_t *pcb_layer_get_real(const pcb_layer_t *layer) { int rec = 0; while(layer->is_bound) { layer = layer->meta.bound.real; rec++; if ((rec > PCB_MAX_BOUND_LAYER_RECURSION) || (layer == NULL)) return NULL; } return (pcb_layer_t *)layer; } /* list of virtual layers: these are generated by the draw code but do not have a real layer in the array */ typedef struct pcb_virt_layer_s { char *name; rnd_layer_id_t new_id; pcb_layer_type_t type; const char *purpose; int purpi; } pcb_virt_layer_t; extern pcb_virt_layer_t pcb_virt_layers[]; /* Return the first virtual layer that fully matches mask */ const pcb_virt_layer_t *pcb_vlayer_get_first(pcb_layer_type_t mask, const char *purpose, int purpi); /* Returns whether the given unsigned int layer flags corresponds to a layer that's on the visible side of the board at the moment. */ #define PCB_LAYERFLG_ON_VISIBLE_SIDE(uint_flags) \ (!!(conf_core.editor.show_solder_side ? ((uint_flags) & PCB_LYT_BOTTOM) : ((uint_flags) & PCB_LYT_TOP))) #define PCB_LYT_VISIBLE_SIDE() \ ((conf_core.editor.show_solder_side ? PCB_LYT_BOTTOM : PCB_LYT_TOP)) #define PCB_LYT_INVISIBLE_SIDE() \ ((conf_core.editor.show_solder_side ? PCB_LYT_TOP : PCB_LYT_BOTTOM)) /*** For internal use ***/ void pcb_layer_move_(pcb_layer_t *dst, pcb_layer_t *src); #endif