TraceMaker
C++ API of the engine
Loading...
Searching...
No Matches
obstacles.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-3.0-or-later
2#pragma once
3// Obstacle model for routing: every copper item, hole, board edge and keepout, with exact legality tests that
4// use the DRC's rule engine, so the router and the DRC can never disagree about what is legal.
5#include <functional>
6#include <memory>
7#include <vector>
8
10#include "drc/copper.hpp"
11#include "drc/rule_engine.hpp"
13#include "model/board.hpp"
14#include "model/rules.hpp"
15
16namespace tmk::route {
17
18class Obstacles {
19 public:
20 // `board` is the router's working copy; items added later must also be appended to it.
22
23 // Legality of a probe shape. Result: 0 = free, 1 = only conflicts with rippable routed copper (owners are
24 // appended to `owners` when given), 2 = blocked by fixed copper, holes, edges or keepouts.
25 // With `ignore_routed` = false, routed copper counts as blocking (result 0 or 2 only).
26 int disk_state(geom::Point p, int layer, Coord hw, model::NetId net, Coord margin, bool ignore_routed,
27 std::vector<int>* owners = nullptr) const;
28 int segment_state(geom::Point a, geom::Point b, int layer, Coord width, model::NetId net, bool ignore_routed,
29 std::vector<int>* owners = nullptr) const;
30 // A via on copper layers [l0, l1] only (blind or buried via, or a micro via with `type`); via_state covers all layers.
31 int via_state_span(geom::Point p, Coord d, Coord drill, model::NetId net, Coord margin, bool ignore_routed, std::vector<int>* owners, int l0,
32 int l1, model::ViaType type = model::ViaType::Blind) const;
33 int via_state(geom::Point p, Coord d, Coord drill, model::NetId net, Coord margin, bool ignore_routed,
34 std::vector<int>* owners = nullptr) const;
35 bool disk_ok(geom::Point p, int layer, Coord hw, model::NetId net, Coord margin) const {
36 return disk_state(p, layer, hw, net, margin, false) == 0;
37 }
38 bool segment_ok(geom::Point a, geom::Point b, int layer, Coord width, model::NetId net) const {
39 return segment_state(a, b, layer, width, net, false) == 0;
40 }
41 bool via_ok(geom::Point p, Coord d, Coord drill, model::NetId net, Coord margin) const {
42 return via_state(p, d, drill, net, margin, false) == 0;
43 }
44 // Custom disallow rules that depend on position, size or footprint (doc 05 §34), for new copper of `net`: a
45 // track whose copper is `s` with `width` on `layer`, or a via of diameter `d` spanning [l0, l1]. The state
46 // checks above include them (blocked, 2); a disk's rules are judged on its copper, without the margin.
47 bool positional_rules() const { return re_->positional_disallow(); }
48 bool track_disallowed(const geom::Shape& s, int layer, Coord width, model::NetId net) const;
49 bool via_disallowed(geom::Point p, Coord d, model::NetId net, int l0, int l1, model::ViaType type) const;
50
51 // Registers committed copper (the board copy must already contain the track/via at `index`). Returns the
52 // copper item index.
53 int add_track(int index, int owner);
54 int add_via(int index, int owner);
55 // Rips up a routed item (by copper item index).
56 void remove_item(int item);
57
58 // Fixed-obstacle code of a disk (fixed copper, fixed holes, edges, keepouts, outline), independent of the
59 // probe's own net: kFree, kBlocked, or the single net id whose own copper is the only conflict (so the disk
60 // is legal for that net only). Clearances use `probe_net`'s class; diff-pair relief is not applied (safe).
61 static constexpr std::int32_t kFree = -1, kBlocked = -2;
62 std::int32_t fixed_code(geom::Point p, int layer, Coord hw, Coord margin, model::NetId probe_net, bool via_probe = false) const;
63 std::int32_t fixed_via_code(geom::Point p, Coord d, Coord drill, Coord margin, model::NetId probe_net) const;
64 // Per-layer reference for fixed_via_code.
65 std::int32_t fixed_via_code_reference(geom::Point p, Coord d, Coord drill, Coord margin, model::NetId probe_net) const;
66 // Routed (rippable) copper only: 0 free, 1 conflicts (owners appended), 2 blocked when !soft.
67 int routed_state(const geom::Shape& s, int layer, model::NetId net, drc::ItemKind kind, bool soft, std::vector<int>* owners,
68 bool via_hole = false, Coord hole_r = 0) const;
69 // Maximum routed_state over `layers` for a via and its hole; layer-independent hole checks run once.
70 int routed_via_state(const geom::Shape& s, model::LayerMask layers, model::NetId net, bool soft, Coord hole_r) const;
71 // Rules outside the per-class cache require exact per-point checks.
72 bool needs_exact_routing() const { return re_->needs_exact_routing(); }
73 // Ids of live routed items whose box meets `box`.
74 void routed_items_in(const geom::Box& box, std::vector<int>& out) const;
75
76 const drc::CopperModel& copper() const { return cm_; }
77 // Copper text as the model holds it: one estimated rectangle per line (copper index, rectangle).
78 const std::vector<std::pair<int, geom::Shape>>& copper_texts() const { return texts_; }
79 const drc::RuleEngine& rules() const { return *re_; }
80 index::UniformGrid& grid() { return *grid_; }
81 geom::Box bounds() const { return bounds_; }
82 // Board outline polygon (largest Edge.Cuts loop) when it could be assembled; empty otherwise.
83 const std::vector<geom::Point>& outline() const { return outline_; }
84 bool inside_board(geom::Point p, Coord margin) const;
85 // Solder-mask expansion the checks give untented vias (0 when the board tents them). Escape analysis sets it
86 // to 0 to ask "would a via fit here if vias were tented?"; routing never changes it.
87 Coord via_mask() const { return via_mask_; }
88 void set_via_mask(Coord m) { via_mask_ = m; }
89 // Zone fills are ignored as obstacles (they are refilled after routing); they remain connection targets.
90 void set_soft_zones(bool on) { soft_zones_ = on; }
91 // Net-less solder-mask openings drawn as footprint graphics (a solder-jumper's bridge, a MEMS microphone's pad group) no longer keep copper out; KiCad's
92 // mask checks flag what then lies in them (judgement, not a short). Off by default.
93 void set_soft_mask_graphics(bool on) { soft_mask_graphics_ = on; }
94 // Net-less copper drawn as BOARD graphics (an EasyEDA import's pours as polygons on a copper layer) is fixed copper that no track may touch, and pins inside it are
95 // enclosed; soft, it is ignored like a zone fill (KiCad then flags what touches it). Off by default.
96 void set_soft_copper_graphics(bool on) { soft_copper_graphics_ = on; } // (unused since the net inference of board copper graphics: Board::infer_graphic_nets)
97 bool soft_zones() const { return soft_zones_; }
98 // Vias keep clear of SMD pads narrower than `max_pad` (any net, net-class clearance), as if they were another
99 // net's copper; larger pads (exposed thermal pads) still take vias. set_pad_via_exempt(true) lifts this around the
100 // checks of one deliberate via in pad (the router's --via-in-pad).
101 void set_vias_off_pads(bool on, Coord max_pad) { vias_off_pads_ = on; vias_off_pads_max_ = max_pad; }
102 void set_pad_via_exempt(bool on) const { pad_via_exempt_ = on; }
103 // Reference path: test probes against every edge of a zone fill instead of the fill's edge index (the answers
104 // are the same; tests/test_design_rules.cpp).
105 void set_linear_zone_tests(bool on) { linear_zone_tests_ = on; }
106 // Rejection counters (diagnostics): outside board, copper, holes/edges/keepouts.
107 mutable long rej_outside = 0, rej_copper = 0, rej_other = 0, checks = 0;
108
109 private:
110 int copper_state(const geom::Shape& s, const drc::CopperItem& probe, int layer, bool ignore_routed, std::vector<int>* owners) const;
111 // True if `s` is closer than `req` to the copper of `it`. A zone fill answers from its edge index
112 // (geom::PolygonIndex, exact), so a probe costs the fill's nearby edges instead of all of them.
113 bool item_closer(const geom::Shape& s, const drc::CopperItem& it, Coord req) const;
114 int holes_edges_state(const geom::Shape& s, model::NetId net, int layer, bool is_via_hole, Coord hole_r, bool ignore_routed,
115 std::vector<int>* owners) const;
116 // Custom physical_hole_clearance rules, any net: new copper against existing holes, and a new via's hole
117 // against existing copper, on `layer`. 0 free, 1 conflict with routed copper (when soft), 2 blocked.
118 int physical_copper_state(const geom::Shape& s, drc::ItemKind kind, model::NetId net, int layer, bool fixed, bool routed, bool soft,
119 std::vector<int>* owners) const;
120 int physical_hole_state(const geom::Shape& hole, model::NetId net, int layer, bool fixed, bool routed, bool soft, std::vector<int>* owners) const;
121 int routed_copper_part(const geom::Shape& s, int layer, model::NetId net, drc::ItemKind kind, bool soft, std::vector<int>* owners) const;
122 int routed_via_holes_part(const geom::Shape& s, model::NetId net, Coord hc, bool soft, std::vector<int>* owners) const;
123 int routed_hole_copper_part(const geom::Shape& h, int layer, model::NetId net, Coord hc, bool soft, std::vector<int>* owners) const;
124 int routed_hole_to_hole_part(const geom::Shape& hole, bool soft, std::vector<int>* owners) const;
125 std::int32_t via_hole_code(geom::Point p, Coord drill, Coord margin, model::NetId probe_net, std::int32_t code) const;
126
127 model::Board& b_;
128 const model::DesignRules& r_;
130 std::unique_ptr<drc::RuleEngine> re_;
131 std::unique_ptr<drc::ZoneFills> fills_; // edge index of every zone fill present at construction
132 bool linear_zone_tests_ = false;
133 std::unique_ptr<index::UniformGrid> grid_; // copper items (fixed and routed)
134 std::unique_ptr<index::UniformGrid> rgrid_; // routed copper items only
135 std::unique_ptr<index::UniformGrid> hgrid_; // holes
136 std::unique_ptr<index::UniformGrid> egrid_; // board-edge segments
137 std::vector<geom::Shape> edge_segs_;
138 geom::Box bounds_;
139 Coord reach_ = 0;
140 std::vector<geom::Point> outline_;
141 std::vector<std::vector<geom::Point>> cutouts_;
142 // Inside-board raster: 0 outside, 1 inside, 2 boundary cell (exact test needed).
143 std::vector<std::uint8_t> inside_raster_;
144 int ir_w_ = 0, ir_h_ = 0;
145 Coord ir_cell_ = 250'000;
146 bool inside_exact(geom::Point p) const;
147 bool soft_zones_ = false;
148 bool soft_mask_graphics_ = false;
149 bool soft_copper_graphics_ = false;
150 bool soft_item(const drc::CopperItem& it) const {
151 return soft_zones_ && it.kind == drc::ItemKind::Zone;
152 }
153 bool vias_off_pads_ = false;
154 Coord vias_off_pads_max_ = 2'000'000;
155 mutable bool pad_via_exempt_ = false;
156 bool via_keeps_off(const drc::CopperItem& it) const;
157 std::vector<std::pair<geom::Shape, const model::Zone*>> keepouts_;
158 std::vector<geom::Shape> mask_open_[2]; // solder-mask openings drawn as graphics (front, back)
159 struct Aperture {
160 std::vector<geom::Shape> shapes; // pad copper shape; the opening is this inflated by `margin`
161 Coord margin = 0;
162 model::NetId net = 0;
163 geom::Box box;
164 };
165 std::vector<Aperture> apertures_[2]; // pad solder-mask openings per side
166 std::unique_ptr<index::UniformGrid> agrid_[2];
167 std::vector<std::pair<int, geom::Shape>> texts_; // copper text boxes (copper index, rectangle)
168 Coord via_mask_ = 0;
169 Coord max_hole_local_ = 0; // largest local (pad/footprint) clearance on a hole // mask expansion of untented vias (0 when tented)
170 // Mask-opening and copper-text conflicts for new copper on `layer` (fixed obstacles only).
171 void aperture_codes(const geom::Shape& s, int layer, bool via_probe, const std::function<void(model::NetId)>& hit) const;
172};
173
174// Filled area of zone fill items (nm^2), shoelace over each item's outline.
175long double zone_fill_area(const drc::CopperModel& cm, const std::vector<int>& items);
176// With soft zones a fill of at least this area that no pad touches is its net's plane: a connection target of its
177// own (doc 05 §26). Smaller ones are slivers of a stale fill, which a refill may drop or reshape.
178inline constexpr long double kPlaneTargetArea = 1e12L; // 1 mm^2
179
180} // namespace tmk::route
The board model (design doc 02 §3): every object TraceMaker reads from a .kicad_pcb,...
compiled custom-rule condition
void set_soft_zones(bool on)
Zone fills are ignored as obstacles (they are refilled after routing); they remain connection targets...
Definition obstacles.hpp:90
bool via_disallowed(geom::Point p, Coord d, model::NetId net, int l0, int l1, model::ViaType type) const
void set_soft_copper_graphics(bool on)
Net-less copper drawn as BOARD graphics (an EasyEDA import's pours as polygons on a copper layer) is ...
Definition obstacles.hpp:96
bool positional_rules() const
Custom disallow rules that depend on position, size or footprint (doc 05 §34), for new copper of net:...
Definition obstacles.hpp:47
int add_via(int index, int owner)
bool needs_exact_routing() const
Rules outside the per-class cache require exact per-point checks.
Definition obstacles.hpp:72
geom::Box bounds() const
Definition obstacles.hpp:81
std::int32_t fixed_via_code(geom::Point p, Coord d, Coord drill, Coord margin, model::NetId probe_net) const
static constexpr std::int32_t kFree
Fixed-obstacle code of a disk (fixed copper, fixed holes, edges, keepouts, outline),...
Definition obstacles.hpp:61
int add_track(int index, int owner)
Registers committed copper (the board copy must already contain the track/via at index).
void set_vias_off_pads(bool on, Coord max_pad)
Vias keep clear of SMD pads narrower than max_pad (any net, net-class clearance), as if they were ano...
std::int32_t fixed_via_code_reference(geom::Point p, Coord d, Coord drill, Coord margin, model::NetId probe_net) const
Per-layer reference for fixed_via_code.
int routed_state(const geom::Shape &s, int layer, model::NetId net, drc::ItemKind kind, bool soft, std::vector< int > *owners, bool via_hole=false, Coord hole_r=0) const
Routed (rippable) copper only: 0 free, 1 conflicts (owners appended), 2 blocked when !...
void set_linear_zone_tests(bool on)
Reference path: test probes against every edge of a zone fill instead of the fill's edge index (the a...
const std::vector< std::pair< int, geom::Shape > > & copper_texts() const
Copper text as the model holds it: one estimated rectangle per line (copper index,...
Definition obstacles.hpp:78
const std::vector< geom::Point > & outline() const
Board outline polygon (largest Edge.Cuts loop) when it could be assembled; empty otherwise.
Definition obstacles.hpp:83
static constexpr std::int32_t kBlocked
Definition obstacles.hpp:61
Obstacles(model::Board &board, const model::DesignRules &rules)
board is the router's working copy; items added later must also be appended to it.
void set_pad_via_exempt(bool on) const
bool track_disallowed(const geom::Shape &s, int layer, Coord width, model::NetId net) const
bool disk_ok(geom::Point p, int layer, Coord hw, model::NetId net, Coord margin) const
Definition obstacles.hpp:35
bool via_ok(geom::Point p, Coord d, Coord drill, model::NetId net, Coord margin) const
Definition obstacles.hpp:41
void routed_items_in(const geom::Box &box, std::vector< int > &out) const
Ids of live routed items whose box meets box.
int disk_state(geom::Point p, int layer, Coord hw, model::NetId net, Coord margin, bool ignore_routed, std::vector< int > *owners=nullptr) const
Legality of a probe shape.
int segment_state(geom::Point a, geom::Point b, int layer, Coord width, model::NetId net, bool ignore_routed, std::vector< int > *owners=nullptr) const
Coord via_mask() const
Solder-mask expansion the checks give untented vias (0 when the board tents them).
Definition obstacles.hpp:87
bool soft_zones() const
Definition obstacles.hpp:97
void set_soft_mask_graphics(bool on)
Net-less solder-mask openings drawn as footprint graphics (a solder-jumper's bridge,...
Definition obstacles.hpp:93
bool segment_ok(geom::Point a, geom::Point b, int layer, Coord width, model::NetId net) const
Definition obstacles.hpp:38
index::UniformGrid & grid()
Definition obstacles.hpp:80
void set_via_mask(Coord m)
Definition obstacles.hpp:88
const drc::RuleEngine & rules() const
Definition obstacles.hpp:79
int via_state(geom::Point p, Coord d, Coord drill, model::NetId net, Coord margin, bool ignore_routed, std::vector< int > *owners=nullptr) const
int routed_via_state(const geom::Shape &s, model::LayerMask layers, model::NetId net, bool soft, Coord hole_r) const
Maximum routed_state over layers for a via and its hole; layer-independent hole checks run once.
void remove_item(int item)
Rips up a routed item (by copper item index).
bool inside_board(geom::Point p, Coord margin) const
std::int32_t fixed_code(geom::Point p, int layer, Coord hw, Coord margin, model::NetId probe_net, bool via_probe=false) const
long rej_outside
Rejection counters (diagnostics): outside board, copper, holes/edges/keepouts.
int via_state_span(geom::Point p, Coord d, Coord drill, model::NetId net, Coord margin, bool ignore_routed, std::vector< int > *owners, int l0, int l1, model::ViaType type=model::ViaType::Blind) const
A via on copper layers [l0, l1] only (blind or buried via, or a micro via with type); via_state cover...
const drc::CopperModel & copper() const
Definition obstacles.hpp:76
Copper connectivity with KiCad's semantics, shared by the DRC (unconnected/dangling checks) and the r...
Copper items with exact shapes, built from the board model, for DRC and routing obstacles.
std::int32_t NetId
0 = no net
Definition board.hpp:21
std::uint64_t LayerMask
bit i = copper layer i in stack order (0 = F.Cu, last = B.Cu)
Definition board.hpp:22
constexpr long double kPlaneTargetArea
With soft zones a fill of at least this area that no pad touches is its net's plane: a connection tar...
long double zone_fill_area(const drc::CopperModel &cm, const std::vector< int > &items)
Filled area of zone fill items (nm^2), shoelace over each item's outline.
std::int64_t Coord
Engine coordinate: signed 64-bit nanometres.
Definition units.hpp:12
Resolves KiCad constraints for pairs of copper items (design doc 03 §6): net-class clearances,...
Design rules as KiCad defines them (design doc 08 §3–4): board minimums and net classes from the ....
Uniform spatial hash grid over a bounding box (design doc 03 §2): O(1) insert, box queries return eac...