/* * COPYRIGHT * * pcb-rnd, interactive printed circuit board design * (this file is based on PCB, interactive printed circuit board design) * Copyright (C) 1994,1995,1996, 2003, 2004 Thomas Nau * Copyright (C) 2017,2018 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") * */ /* Local functions for special layer draw logics. This code is not generic; instead it collects all the hardwired heuristics for the special layers. Included from draw.c. */ /******** paste ********/ static void pcb_draw_paste_auto_(comp_ctx_t *ctx, void *side) { if (PCB->pstk_on) pcb_draw_pstks(ctx->info, ctx->gid, 0, PCB_LYC_AUTO); } static void pcb_draw_paste(pcb_draw_info_t *info, int side) { unsigned long side_lyt = side ? PCB_LYT_TOP : PCB_LYT_BOTTOM; rnd_layergrp_id_t gid = -1; comp_ctx_t cctx; pcb_layer_t *ly = NULL; rnd_xform_t tmp; xform_setup(info, &tmp, NULL); pcb_layergrp_list(info->pcb, PCB_LYT_PASTE | side_lyt, &gid, 1); cctx.grp = pcb_get_layergrp((pcb_board_t *)info->pcb, gid); if (cctx.grp->len > 0) ly = pcb_get_layer(info->pcb->Data, cctx.grp->lid[0]); cctx.info = info; cctx.gid = gid; cctx.color = ly != NULL ? &ly->meta.real.color : &conf_core.appearance.color.paste; cctx.thin = (info->xform != NULL) && (info->xform->thin_draw || info->xform->thin_draw_poly || info->xform->wireframe); cctx.invert = 0; if ((cctx.grp == NULL) || (cctx.grp->len == 0)) { /* fallback: no layers -> original code: draw a single auto-add */ rnd_render->set_drawing_mode(rnd_render, RND_HID_COMP_RESET, pcb_draw_out.direct, info->drawn_area); rnd_render->set_drawing_mode(rnd_render, RND_HID_COMP_POSITIVE, pcb_draw_out.direct, info->drawn_area); rnd_render->set_drawing_mode(rnd_render, RND_HID_COMP_FLUSH, pcb_draw_out.direct, info->drawn_area); } else { comp_draw_layer(&cctx, pcb_draw_paste_auto_, &side); comp_finish(&cctx); } info->xform = NULL; info->layer = NULL; } /******** mask ********/ static void pcb_draw_mask_auto(comp_ctx_t *ctx, void *side) { if (PCB->pstk_on) pcb_draw_pstks(ctx->info, ctx->gid, 0, PCB_LYC_SUB | PCB_LYC_AUTO); } static void pcb_draw_mask(pcb_draw_info_t *info, int side) { unsigned long side_lyt = side ? PCB_LYT_TOP : PCB_LYT_BOTTOM; rnd_layergrp_id_t gid = -1; comp_ctx_t cctx; pcb_layer_t *ly = NULL; rnd_xform_t tmp; xform_setup(info, &tmp, NULL); pcb_layergrp_list(PCB, PCB_LYT_MASK | side_lyt, &gid, 1); cctx.grp = pcb_get_layergrp(PCB, gid); if (cctx.grp->len > 0) ly = pcb_get_layer(PCB->Data, cctx.grp->lid[0]); cctx.info = info; cctx.gid = gid; cctx.color = ly != NULL ? &ly->meta.real.color : &conf_core.appearance.color.mask; cctx.thin = (info->xform != NULL) && (info->xform->thin_draw || info->xform->thin_draw_poly || info->xform->wireframe); cctx.invert = rnd_render->mask_invert; if (!cctx.invert) pcb_draw_out.direct = 0; if ((cctx.grp == NULL) || (cctx.grp->len == 0)) { /* fallback: no layers -> original code: draw a single auto-sub */ comp_init(&cctx, 1); comp_start_sub(&cctx); pcb_draw_mask_auto(&cctx, &side); comp_start_add(&cctx); } else comp_draw_layer(&cctx, pcb_draw_mask_auto, &side); comp_finish(&cctx); info->xform = NULL; info->layer = NULL; } /******** silk ********/ static void pcb_draw_silk_auto(comp_ctx_t *ctx, void *lyt_side) { if (PCB->pstk_on) pcb_draw_pstks(ctx->info, ctx->gid, 0, PCB_LYC_AUTO); } static int pcb_is_silk_old_style(comp_ctx_t *cctx, rnd_layer_id_t lid) { if (cctx->grp == NULL) return 1; /* no group means no silk -> fall back to implicit */ if ((cctx->grp->len == 1) && ((PCB->Data->Layer[lid].comb & (PCB_LYC_AUTO | PCB_LYC_SUB)) == PCB_LYC_AUTO)) return 1; /* A single auto-positive layer -> original code: draw auto+manual */ return 0; } static void pcb_draw_silk_doc(pcb_draw_info_t *info, pcb_layer_type_t lyt_side, pcb_layer_type_t lyt_type, int setgrp, int invis) { rnd_layer_id_t lid; rnd_layergrp_id_t gid[PCB_MAX_LAYERGRP]; comp_ctx_t cctx; int len, n; len = pcb_layergrp_list(info->pcb, lyt_type | lyt_side, gid, PCB_MAX_LAYERGRP); if (len < 1) return; for(n = 0; n < len; n++) { pcb_layergrp_t *grp = &info->pcb->LayerGroups.grp[gid[n]]; pcb_layer_t *ly = NULL; /* Special case: 'global' location is not a specific location bit but lack of location bits; for that case listing will return every group and we need to filter by hand */ if ((lyt_side == 0) && ((grp->ltype & PCB_LYT_ANYWHERE) != 0)) continue; /* workaround: in direct export group visibility is not really set but layer visibility is set; if they are contradicting, it's enough if either is set. Assume all layers are visible or invisible within a group, so depend only on the first layer */ if (grp->len > 0) ly = pcb_get_layer(info->pcb->Data, grp->lid[0]); if ((!grp->vis) && ((ly == NULL) || (!ly->meta.real.vis))) continue; if (setgrp) if (!pcb_layer_gui_set_glayer(info->pcb, gid[n], 0, &info->xform_exporter)) continue; cctx.info = info; cctx.gid = gid[n]; cctx.grp = pcb_get_layergrp((pcb_board_t *)info->pcb, gid[n]); if ((lyt_side == 0) && (cctx.grp->ltype & PCB_LYT_ANYWHERE) != 0) /* special case for global */ continue; if (cctx.grp->len == 0) continue; lid = cctx.grp->lid[0]; cctx.color = invis ? &conf_core.appearance.color.invisible_objects : &info->pcb->Data->Layer[lid].meta.real.color; cctx.thin = (info->xform != NULL) && (info->xform->thin_draw || info->xform->thin_draw_poly || info->xform->wireframe); cctx.invert = 0; if ((lyt_type & PCB_LYT_SILK) && (pcb_is_silk_old_style(&cctx, lid))) { /* fallback: implicit layer -> original code: draw auto+manual */ rnd_render->set_drawing_mode(rnd_render, RND_HID_COMP_RESET, pcb_draw_out.direct, info->drawn_area); rnd_render->set_drawing_mode(rnd_render, RND_HID_COMP_POSITIVE, pcb_draw_out.direct, info->drawn_area); pcb_draw_layer(info, pcb_get_layer(info->pcb->Data, lid)); pcb_draw_silk_auto(&cctx, &lyt_side); rnd_render->set_drawing_mode(rnd_render, RND_HID_COMP_FLUSH, pcb_draw_out.direct, info->drawn_area); } else { comp_draw_layer(&cctx, pcb_draw_silk_auto, &lyt_side); comp_finish(&cctx); } if (setgrp) rnd_render->end_layer(rnd_render); } } static void remember_slot(pcb_layer_t **uslot, pcb_layer_t **pslot, int *uscore, int *pscore, const pcb_layergrp_t *g, pcb_layer_t *ly) { int score; pcb_layer_t **dslot; int *dscore; if (!(ly->comb & PCB_LYC_AUTO)) return; if (g->purpi == F_uroute) { dslot = uslot; dscore = uscore; } else if (g->purpi == F_proute) { dslot = pslot; dscore = pscore; } else return; if (g->ltype & PCB_LYT_BOUNDARY) score = 1; if (g->ltype & PCB_LYT_MECH) score = 2; if (score > *dscore) { *dscore = score; *dslot = ly; } } static void pcb_draw_boundary_mech(pcb_draw_info_t *info) { int count = 0; rnd_layergrp_id_t gid, goutid; const pcb_layergrp_t *g, *goutl = NULL; pcb_layer_t *uslot = NULL, *pslot = NULL; int uscore = 0, pscore = 0; int plated, unplated; for(gid = 0, g = info->pcb->LayerGroups.grp; gid < info->pcb->LayerGroups.len; gid++,g++) { int n, numobj; if ((g->ltype & PCB_LYT_BOUNDARY) && (g->purpi == F_uroute)) { goutl = g; goutid = gid; } if (!(g->ltype & (PCB_LYT_BOUNDARY | PCB_LYT_MECH)) || (g->len < 1)) continue; /* Count whether there are objects on any boundary layer: don't count the objects drawn, but the objects the layer has; zooming in the middle doesn't mean we need to have the implicit outline */ numobj = 0; for(n = 0; n < g->len; n++) { pcb_layer_t *ly = pcb_get_layer(info->pcb->Data, g->lid[n]); if (ly->line_tree != NULL) numobj += ly->line_tree->size; if (ly->arc_tree != NULL) numobj += ly->arc_tree->size; if (ly->text_tree != NULL) numobj += ly->text_tree->size; if (ly->polygon_tree != NULL) numobj += ly->polygon_tree->size; remember_slot(&uslot, &pslot, &uscore, &pscore, g, ly); } count += numobj; if (pcb_layer_gui_set_layer(gid, g, (numobj == 0), &info->xform_exporter)) { /* boundary does NOT support compisiting, everything is drawn in positive */ rnd_render->set_drawing_mode(rnd_render, RND_HID_COMP_RESET, pcb_draw_out.direct, info->drawn_area); rnd_render->set_drawing_mode(rnd_render, RND_HID_COMP_POSITIVE, pcb_draw_out.direct, info->drawn_area); for(n = 0; n < g->len; n++) { pcb_layer_t *ly = pcb_get_layer(info->pcb->Data, g->lid[n]); pcb_draw_layer(info, ly); } rnd_render->set_drawing_mode(rnd_render, RND_HID_COMP_FLUSH, pcb_draw_out.direct, info->drawn_area); rnd_render->end_layer(rnd_render); } } if ((count == 0) && (goutl != NULL) && (pcb_layer_gui_set_layer(goutid, goutl, 0, &info->xform))) { /* The implicit outline rectangle (or automatic outline rectanlge). We should check for rnd_render->gui here, but it's kinda cool seeing the auto-outline magically disappear when you first add something to the outline layer. */ rnd_render->set_drawing_mode(rnd_render, RND_HID_COMP_RESET, pcb_draw_out.direct, info->drawn_area); rnd_render->set_drawing_mode(rnd_render, RND_HID_COMP_POSITIVE, pcb_draw_out.direct, info->drawn_area); rnd_render->set_color(pcb_draw_out.fgGC, &PCB->Data->Layer[goutl->lid[0]].meta.real.color); rnd_hid_set_line_cap(pcb_draw_out.fgGC, rnd_cap_round); rnd_hid_set_line_width(pcb_draw_out.fgGC, conf_core.design.min_wid); rnd_render->draw_rect(pcb_draw_out.fgGC, PCB->hidlib.dwg.X1, PCB->hidlib.dwg.Y1, PCB->hidlib.dwg.X2, PCB->hidlib.dwg.Y2); rnd_render->set_drawing_mode(rnd_render, RND_HID_COMP_FLUSH, pcb_draw_out.direct, info->drawn_area); rnd_render->end_layer(rnd_render); } /* draw slots */ if (((uslot == NULL) || (!uslot->meta.real.vis)) && ((pslot == NULL) || (!pslot->meta.real.vis))) return; pcb_board_count_slots(PCB, &plated, &unplated, info->drawn_area); if ((uslot != NULL) && (uslot->meta.real.vis)) { if (pcb_layer_gui_set_glayer(PCB, uslot->meta.real.grp, unplated <= 0, &info->xform)) { rnd_render->set_drawing_mode(rnd_render, RND_HID_COMP_RESET, pcb_draw_out.direct, info->drawn_area); rnd_render->set_drawing_mode(rnd_render, RND_HID_COMP_POSITIVE, pcb_draw_out.direct, info->drawn_area); pcb_draw_pstk_slots(info, uslot->meta.real.grp, PCB_PHOLE_UNPLATED | PCB_PHOLE_BB); rnd_render->set_drawing_mode(rnd_render, RND_HID_COMP_FLUSH, pcb_draw_out.direct, info->drawn_area); rnd_render->end_layer(rnd_render); } } if ((pslot != NULL) && (pslot->meta.real.vis)) { if (pcb_layer_gui_set_glayer(PCB, pslot->meta.real.grp, plated <= 0, &info->xform)) { rnd_render->set_drawing_mode(rnd_render, RND_HID_COMP_RESET, pcb_draw_out.direct, info->drawn_area); rnd_render->set_drawing_mode(rnd_render, RND_HID_COMP_POSITIVE, pcb_draw_out.direct, info->drawn_area); pcb_draw_pstk_slots(info, pslot->meta.real.grp, PCB_PHOLE_PLATED | PCB_PHOLE_BB); rnd_render->set_drawing_mode(rnd_render, RND_HID_COMP_FLUSH, pcb_draw_out.direct, info->drawn_area); rnd_render->end_layer(rnd_render); } } } /******** misc ********/ static void pcb_draw_rats(pcb_draw_info_t *info, const rnd_box_t *drawn_area) { rnd_render->set_drawing_mode(rnd_render, RND_HID_COMP_RESET, pcb_draw_out.direct, drawn_area); rnd_render->set_drawing_mode(rnd_render, RND_HID_COMP_POSITIVE, pcb_draw_out.direct, drawn_area); rnd_rtree_search_any(PCB->Data->rat_tree, (rnd_rtree_box_t *)drawn_area, NULL, pcb_rat_draw_callback, info, NULL); rnd_render->set_drawing_mode(rnd_render, RND_HID_COMP_FLUSH, pcb_draw_out.direct, drawn_area); } extern int rnd_ps_faded; static void pcb_draw_assembly(pcb_draw_info_t *info, pcb_layer_type_t lyt_side) { rnd_layergrp_id_t side_group; if (pcb_layergrp_list(PCB, PCB_LYT_COPPER | lyt_side, &side_group, 1) != 1) return; pcb_draw_doing_assy = rnd_true; rnd_ps_faded = 1; pcb_draw_layer_grp(info, side_group, 0); rnd_ps_faded = 0; /* draw package */ pcb_draw_silk_doc(info, lyt_side, PCB_LYT_SILK, 0, 0); pcb_draw_doing_assy = rnd_false; }