TraceMaker
C++ API of the engine
Loading...
Searching...
No Matches
legality.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-3.0-or-later
2#pragma once
3// Placement legality (design doc 04 §3 D/E): exact integer tests of courtyards, through-hole obstacles, the
4// board outline, keepouts and pad-to-edge clearance, plus a bucket index of placed parts and a conservative
5// occupancy raster used as a fast path by the legaliser.
6#include <cstdint>
7#include <vector>
8
9#include "place/problem.hpp"
10
11namespace tmk::place {
12
13struct Placement {
14 std::vector<Point> pos; // footprint origin per part
15 std::vector<std::uint8_t> rot; // rotation index per part (angle0 + 90° * rot)
16
17 static Placement initial(const Problem& p); // every part where the board has it
18 Point pin(const Problem& p, int pin_index) const {
19 const Pin& q = p.pins[z(pin_index)];
20 return pos[z(q.part)] + q.off[rot[z(q.part)]];
21 }
22};
23
24// Exact test with translation (no copies): same semantics as geom::closer_than(a + da, b + db, clearance).
25bool closer(const Shape& a, Point da, const Shape& b, Point db, Coord clearance);
26// Copper clearance violation between two copper shapes (different nets, shared layer, max of the two needs).
27bool copper_conflict(const CopperShape& a, Point pa, const CopperShape& b, Point pb);
28
29inline constexpr Coord kThroughMargin = 100'000; // through obstacle vs courtyard on the other side
30inline constexpr Coord kThroughThrough = 250'000; // through obstacle vs through obstacle
31
32class Legality {
33 public:
34 explicit Legality(const Problem& p);
35
36 // Board test (outline, cut-outs, keepouts, pad-to-edge clearance); independent of other parts.
37 // `lenient`: pads only need to be inside the outline, without the copper-to-edge clearance.
38 bool inside_ok(int part, Point pos, int rot, bool lenient = false) const;
39 // Exact test of two parts.
40 bool pair_conflict(int a, Point pa, int ra, int b, Point pb, int rb) const;
41
42 // Index of placed parts (all parts present after reset).
43 void reset(const Placement& pl);
44 void clear();
45 void insert(int part, Point pos, int rot);
46 void remove(int part);
47 bool present(int part) const { return present_[z(part)] != 0; }
48 // First placed part that conflicts with `part` at (pos, rot), skipping `part` itself and skip1/skip2; -1 if none.
49 int find_conflict(int part, Point pos, int rot, int skip1 = -1, int skip2 = -1) const;
50 // Every placed part that conflicts (sorted).
51 void conflicts(int part, Point pos, int rot, std::vector<int>& out) const;
52 bool legal(int part, Point pos, int rot, int skip1 = -1, int skip2 = -1) const {
53 return inside_ok(part, pos, rot) && find_conflict(part, pos, rot, skip1, skip2) < 0;
54 }
55 // Placed parts whose bodies are within `margin` of the box.
56 void neighbours(const Box& box, std::vector<int>& out) const;
57
58 private:
59 void cells_of(const Box& b, int& cx0, int& cy0, int& cx1, int& cy1) const;
60 const Problem& p_;
61 Coord cell_ = 2'000'000;
62 Coord ox_ = 0, oy_ = 0;
63 int nx_ = 1, ny_ = 1;
64 std::vector<std::vector<int>> cells_;
65 std::vector<Point> pos_;
66 std::vector<std::uint8_t> rot_, present_;
67 mutable std::vector<std::uint32_t> stamp_;
68 mutable std::uint32_t epoch_ = 0;
69 // Board edge segments in a bucket grid.
70 std::vector<Shape> segs_;
71 std::vector<std::vector<int>> seg_cells_;
72 std::vector<std::vector<int>> fixed_cells_; // Problem::fixed_copper in the same grid
73 Coord reach_ = 0; // neighbour search inflation (largest clearance of any kind)
74};
75
76// Conservative occupancy raster per side (cell 0.05–0.1 mm). `free()` returning true proves that the part is
77// legal against the board and every part in the raster; false means "maybe illegal" (run the exact test).
78class Raster {
79 public:
81 void add(int part, Point pos, int rot, int delta); // delta = +1 insert, -1 remove
82 bool free(int part, Point pos, int rot) const; // summed-area tables: O(shapes) per call
83 bool free_reference(int part, Point pos, int rot) const; // cell scan (reference path for tests)
84 Coord cell() const { return h_; }
85 // Fraction of cells inside the board on side s (for diagnostics).
86 double inside_fraction(int side) const;
87
88 private:
89 bool range(const Box& b, int& x0, int& y0, int& x1, int& y1) const;
90 bool any(const std::vector<std::uint16_t>& g, const Box& b) const;
91 bool any_sat(const std::vector<std::int32_t>& sat, const Box& b) const;
92 void build_sat(const std::vector<std::uint16_t>& g, std::vector<std::int32_t>& sat) const;
93 bool free_impl(int part, Point pos, int rot, bool sat) const;
94 void bump(std::vector<std::uint16_t>& g, const Box& b, int delta);
95 const Problem& p_;
96 Coord h_;
97 Coord ox_ = 0, oy_ = 0;
98 int nx_ = 0, ny_ = 0;
99 std::vector<std::uint16_t> blocked_[2]; // static: not entirely inside the board
100 std::vector<std::uint16_t> keep_[2]; // static: touched by a footprint keepout on that side
101 std::vector<std::uint16_t> occ_[2]; // courtyard and through-obstacle boxes of placed parts
102 std::vector<std::uint16_t> fixed_[2]; // static: fixed board copper boxes
103 std::vector<std::int32_t> sat_blocked_[2], sat_keep_[2], sat_fixed_[2]; // summed-area tables (cell != 0)
104 mutable std::vector<std::int32_t> sat_occ_[2]; // rebuilt lazily after add()
105 mutable bool occ_dirty_ = true;
106};
107
108// Every conflict in a placement (for the final report and tests): movable-involved pairs and parts outside.
110 int overlaps = 0; // conflicting pairs with at least one movable part
111 int fixed_overlaps = 0; // pairs of fixed parts (pre-existing, not ours)
112 int outside = 0; // movable parts failing inside_ok
114 std::vector<std::pair<int, int>> pairs;
115 std::vector<int> outside_parts;
116};
118
119} // namespace tmk::place
void conflicts(int part, Point pos, int rot, std::vector< int > &out) const
Every placed part that conflicts (sorted).
void remove(int part)
Legality(const Problem &p)
int find_conflict(int part, Point pos, int rot, int skip1=-1, int skip2=-1) const
First placed part that conflicts with part at (pos, rot), skipping part itself and skip1/skip2; -1 if...
void insert(int part, Point pos, int rot)
bool inside_ok(int part, Point pos, int rot, bool lenient=false) const
Board test (outline, cut-outs, keepouts, pad-to-edge clearance); independent of other parts.
bool present(int part) const
Definition legality.hpp:47
void reset(const Placement &pl)
Index of placed parts (all parts present after reset).
void neighbours(const Box &box, std::vector< int > &out) const
Placed parts whose bodies are within margin of the box.
bool pair_conflict(int a, Point pa, int ra, int b, Point pb, int rb) const
Exact test of two parts.
bool legal(int part, Point pos, int rot, int skip1=-1, int skip2=-1) const
Definition legality.hpp:52
Coord cell() const
Definition legality.hpp:84
bool free_reference(int part, Point pos, int rot) const
cell scan (reference path for tests)
double inside_fraction(int side) const
Fraction of cells inside the board on side s (for diagnostics).
void add(int part, Point pos, int rot, int delta)
delta = +1 insert, -1 remove
bool free(int part, Point pos, int rot) const
summed-area tables: O(shapes) per call
Raster(const Problem &p, Coord cell)
std::size_t z(int i)
Definition problem.hpp:21
bool copper_conflict(const CopperShape &a, Point pa, const CopperShape &b, Point pb)
Copper clearance violation between two copper shapes (different nets, shared layer,...
Violations check_all(const Problem &p, const Placement &pl)
constexpr Coord kThroughMargin
through obstacle vs courtyard on the other side
Definition legality.hpp:29
constexpr Coord kThroughThrough
through obstacle vs through obstacle
Definition legality.hpp:30
bool closer(const Shape &a, Point da, const Shape &b, Point db, Coord clearance)
Exact test with translation (no copies): same semantics as geom::closer_than(a + da,...
std::int64_t Coord
Engine coordinate: signed 64-bit nanometres.
Definition units.hpp:12
Placement problem extracted from a board (design doc 04 §2): parts with courtyards,...
A piece of copper with what KiCad's clearance check needs: layers, net and the clearance it asks for ...
Definition problem.hpp:30
std::array< Point, kStates > off
offset from the part origin per state
Definition problem.hpp:89
static Placement initial(const Problem &p)
every part where the board has it
std::vector< std::uint8_t > rot
rotation index per part (angle0 + 90° * rot)
Definition legality.hpp:15
Point pin(const Problem &p, int pin_index) const
Definition legality.hpp:18
std::vector< Point > pos
footprint origin per part
Definition legality.hpp:14
std::vector< Pin > pins
Definition problem.hpp:114
Every conflict in a placement (for the final report and tests): movable-involved pairs and parts outs...
Definition legality.hpp:109
std::vector< std::pair< int, int > > pairs
Definition legality.hpp:114
std::vector< int > outside_parts
Definition legality.hpp:115
int outside
movable parts failing inside_ok
Definition legality.hpp:112
int fixed_overlaps
pairs of fixed parts (pre-existing, not ours)
Definition legality.hpp:111
int overlaps
conflicting pairs with at least one movable part
Definition legality.hpp:110