TraceMaker
C++ API of the engine
Loading...
Searching...
No Matches
board_editor.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-3.0-or-later
2#pragma once
3// Edits a loaded .kicad_pcb document in place, KiCad style (design doc 08 §3). Only the nodes TraceMaker
4// owns change: new segment/via nodes, removed tracks, and footprint placement. Everything else is kept
5// byte for byte. Re-read the document after editing to get an updated board model.
6#include <cstdint>
7#include <string>
8#include <string_view>
9
11
12namespace tmk::io {
13
15 public:
16 // `seed` makes generated UUIDs deterministic.
17 BoardEditor(LoadedBoard& board, std::uint64_t seed = 1) : lb_(board), seed_(seed) {}
18
19 void add_track(const model::Track& t);
20 void add_via(const model::Via& v);
21 void remove_track(std::size_t index);
22 void remove_via(std::size_t index);
23 // Moves footprint `index` to `pos` with orientation `angle` (degrees). Pad and text orientations, which
24 // KiCad stores as absolute angles, are rotated by the same delta. Flipping sides is not supported here.
25 void move_footprint(std::size_t index, model::Point pos, double angle);
26 // Moves footprint `index` to the other side of the board the way KiCad does (FOOTPRINT::Flip, top/bottom, about
27 // its own origin: local y and pad orientations negated, text angles 180° − a, F.* <-> B.* layers, texts
28 // mirrored), then puts it at `pos` with the final orientation `angle` in degrees (flipped orientation −angle0
29 // plus any rotation). Only for footprints where flip_supported() holds.
30 void flip_footprint(std::size_t index, model::Point pos, double angle);
31
32 // Adds a board-level copper zone as KiCad writes one: net, layer (the zone's single copper layer), outline (first
33 // ring), clearance, minimum width, thermal and island settings, and its fills when it has any (doc 05 §53).
34 void add_zone(const model::Zone& z);
35 // Replaces the filled polygons of zone `index` (board.zones order) with `fills` (copper index, fractured polygon, as
36 // drc::refill_zones gives them) and marks the zone filled.
37 void set_zone_fills(std::size_t index, const std::vector<std::pair<int, std::vector<model::Point>>>& fills);
38 // Gives the board `n` copper layers (even, 2..32; doc 05 §53): inner layers are added after the last one, or the last
39 // ones removed. Removing needs those layers empty (no track, arc, blind via, zone, graphic, text or pad that names
40 // them); through vias and plated holes follow the layer count by themselves. A (stackup) block is removed, since its
41 // copper and dielectrics no longer match, and KiCad builds its default stackup for the new count. Returns false with
42 // the reason in `why` (and the document unchanged) when it cannot; `notes` receives what changed besides the layers.
43 bool set_copper_layer_count(int n, std::string* why = nullptr, std::vector<std::string>* notes = nullptr);
44
45 std::string write() const { return lb_.doc.write(); }
46 void save(const std::string& path) const { lb_.doc.save(path); }
47
48 // Deterministic RFC-4122-style v4 UUID string.
49 std::string next_uuid();
50
51 private:
52 std::string net_expr(model::NetId net) const;
53
54 LoadedBoard& lb_;
55 std::uint64_t seed_;
56 std::uint64_t uuid_counter_ = 0;
57};
58
59// True if BoardEditor::flip_footprint mirrors every item of footprint `index` exactly: no copper on inner
60// layers, no padstacks, no text on copper, and nothing it does not know (zones, text boxes, dimensions, private
61// layers, ...). `why` receives the first reason it cannot.
62bool flip_supported(const LoadedBoard& board, std::size_t index, std::string* why = nullptr);
63// KiCad's FlipLayer for outer layers: the first and last copper layer of `board` (by their names in the file) and
64// F.X <-> B.X for the other side-specific layers; any other name unchanged.
65std::string flip_layer_name(const model::Board& board, std::string_view name);
66
67// Formats an angle the way KiCad writes it: shortest decimal, no trailing zeros ("90", "45.5").
68std::string format_angle(double deg);
69
70} // namespace tmk::io
Reads .kicad_pcb files (KiCad 9 and 10 formats) into the board model, keeping the s-expression docume...
void set_zone_fills(std::size_t index, const std::vector< std::pair< int, std::vector< model::Point > > > &fills)
Replaces the filled polygons of zone index (board.zones order) with fills (copper index,...
void add_zone(const model::Zone &z)
Adds a board-level copper zone as KiCad writes one: net, layer (the zone's single copper layer),...
void add_via(const model::Via &v)
void flip_footprint(std::size_t index, model::Point pos, double angle)
Moves footprint index to the other side of the board the way KiCad does (FOOTPRINT::Flip,...
void save(const std::string &path) const
std::string next_uuid()
Deterministic RFC-4122-style v4 UUID string.
std::string write() const
void move_footprint(std::size_t index, model::Point pos, double angle)
Moves footprint index to pos with orientation angle (degrees).
void remove_track(std::size_t index)
void remove_via(std::size_t index)
BoardEditor(LoadedBoard &board, std::uint64_t seed=1)
seed makes generated UUIDs deterministic.
bool set_copper_layer_count(int n, std::string *why=nullptr, std::vector< std::string > *notes=nullptr)
Gives the board n copper layers (even, 2..32; doc 05 §53): inner layers are added after the last one,...
void add_track(const model::Track &t)
std::string format_angle(double deg)
Formats an angle the way KiCad writes it: shortest decimal, no trailing zeros ("90",...
std::string flip_layer_name(const model::Board &board, std::string_view name)
KiCad's FlipLayer for outer layers: the first and last copper layer of board (by their names in the f...
bool flip_supported(const LoadedBoard &board, std::size_t index, std::string *why=nullptr)
True if BoardEditor::flip_footprint mirrors every item of footprint index exactly: no copper on inner...
std::int32_t NetId
0 = no net
Definition board.hpp:21