Skip to content

Commit d3039e1

Browse files
imp board: add user layers
changelog: New Features/Board Editor: add user layers
1 parent d8adc48 commit d3039e1

20 files changed

+848
-125
lines changed

scripts/app_versions.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ versions:
2020
18: increase maximum number of inner layers to 8
2121
19: add blind and buried vias
2222
20: add via definitions
23+
21: add user layers
2324
schematic:
2425
1: add custom values on symbols
2526
2: add hierarchy

src/board/board.cpp

Lines changed: 145 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ const LutEnumStr<Board::OutputFormat> Board::output_format_lut = {
4343
{"odb", Board::OutputFormat::ODB},
4444
};
4545

46-
static const unsigned int app_version = 20;
46+
static const unsigned int app_version = 21;
4747

4848
unsigned int Board::get_app_version()
4949
{
@@ -62,6 +62,14 @@ Board::Board(const UUID &uu, const json &j, Block &iblock, IPool &pool, const st
6262
stackup.emplace(std::piecewise_construct, std::forward_as_tuple(l), std::forward_as_tuple(l, it.value()));
6363
}
6464
}
65+
if (j.count("user_layers")) {
66+
const json &o = j["user_layers"];
67+
for (auto it = o.cbegin(); it != o.cend(); ++it) {
68+
int l = std::stoi(it.key());
69+
user_layers.emplace(std::piecewise_construct, std::forward_as_tuple(l),
70+
std::forward_as_tuple(l, it.value()));
71+
}
72+
}
6573
set_n_inner_layers(n_inner_layers);
6674
if (j.count("polygons")) {
6775
const json &o = j["polygons"];
@@ -369,7 +377,7 @@ Board::Board(const Board &brd, CopyMode copy_mode)
369377
grid_settings(brd.grid_settings), airwires(brd.airwires), stackup(brd.stackup), colors(brd.colors),
370378
pdf_export_settings(brd.pdf_export_settings), step_export_settings(brd.step_export_settings),
371379
pnp_export_settings(brd.pnp_export_settings), version(brd.version), board_directory(brd.board_directory),
372-
n_inner_layers(brd.n_inner_layers)
380+
n_inner_layers(brd.n_inner_layers), user_layers(brd.user_layers)
373381
{
374382
if (copy_mode == CopyMode::DEEP) {
375383
packages = brd.packages;
@@ -510,6 +518,11 @@ unsigned int Board::get_n_inner_layers() const
510518
void Board::set_n_inner_layers(unsigned int n)
511519
{
512520
n_inner_layers = n;
521+
update_layers();
522+
}
523+
524+
void Board::update_layers()
525+
{
513526
layers.clear();
514527
layers = {{200, {200, "Top Notes"}},
515528
{BoardLayers::OUTLINE_NOTES, {BoardLayers::OUTLINE_NOTES, "Outline Notes"}},
@@ -539,12 +552,132 @@ void Board::set_n_inner_layers(unsigned int n)
539552
layers.emplace(std::make_pair(-j, Layer(-j, "Inner " + std::to_string(j), false, true)));
540553
stackup.emplace(-j, -j);
541554
}
555+
for (const auto &[i, ul] : user_layers) {
556+
auto &l = layers.emplace(std::piecewise_construct, std::forward_as_tuple(i), std::forward_as_tuple(i, ul.name))
557+
.first->second;
558+
l.position = ul.position;
559+
l.color_layer = ul.id_color;
560+
stackup.emplace(i, i);
561+
}
562+
assign_user_layer_positions();
563+
542564
map_erase_if(stackup, [this](const auto &x) { return layers.count(x.first) == 0; });
543565
gerber_output_settings.update_for_board(*this);
544566
odb_output_settings.update_for_board(*this);
545567
update_pdf_export_settings(pdf_export_settings);
546568
}
547569

570+
unsigned int Board::count_available_user_layers() const
571+
{
572+
return std::max(0, (int)BoardLayers::max_user_layers - (int)user_layers.size());
573+
}
574+
575+
Board::UserLayer::UserLayer(int l)
576+
: id(l), id_color(l), name("User Layer " + std::to_string(l - BoardLayers::FIRST_USER_LAYER)), position(l),
577+
type(Type::DOCUMENTATION)
578+
{
579+
}
580+
581+
static const LutEnumStr<Board::UserLayer::Type> user_layer_type_lut = {
582+
{"documentation", Board::UserLayer::Type::DOCUMENTATION}, {"stiffener", Board::UserLayer::Type::STIFFENER},
583+
{"bend_area", Board::UserLayer::Type::BEND_AREA}, {"flex_area", Board::UserLayer::Type::FLEX_AREA},
584+
{"rigid_area", Board::UserLayer::Type::RIGID_AREA}, {"carbon_mask", Board::UserLayer::Type::CARBON_MASK},
585+
{"silver_mask", Board::UserLayer::Type::SILVER_MASK}, {"covercoat", Board::UserLayer::Type::COVERCOAT},
586+
{"coverlay", Board::UserLayer::Type::COVERLAY}, {"psa", Board::UserLayer::Type::PSA},
587+
};
588+
589+
Board::UserLayer::UserLayer(int l, const json &j)
590+
: id(l), id_color(j.value("id_color", l)), name(j.at("name").get<std::string>()),
591+
position(j.at("position").get<double>()), type(user_layer_type_lut.lookup(j.at("type")))
592+
{
593+
}
594+
595+
json Board::UserLayer::serialize() const
596+
{
597+
json j;
598+
j["name"] = name;
599+
j["position"] = position;
600+
j["id_color"] = id_color;
601+
j["type"] = user_layer_type_lut.lookup_reverse(type);
602+
return j;
603+
}
604+
605+
int Board::add_user_layer(int other_layer, UserLayerOrder order)
606+
{
607+
if (count_available_user_layers() < 1)
608+
throw std::runtime_error("no more user layers available");
609+
int user_layer;
610+
for (user_layer = BoardLayers::FIRST_USER_LAYER; user_layer <= BoardLayers::LAST_USER_LAYER; user_layer++) {
611+
if (user_layers.count(user_layer) == 0)
612+
break;
613+
}
614+
if (user_layers.count(user_layer))
615+
throw std::runtime_error("no more user layers available");
616+
617+
618+
auto &ul = user_layers.emplace(user_layer, user_layer).first->second;
619+
const double offset = 1.0 / (2 * BoardLayers::max_user_layers);
620+
const auto other_pos = layers.at(other_layer).position;
621+
ul.position = other_pos + offset * static_cast<int>(order);
622+
623+
624+
update_layers();
625+
return user_layer;
626+
}
627+
628+
void Board::delete_user_layer(int layer)
629+
{
630+
user_layers.erase(layer);
631+
update_layers();
632+
}
633+
634+
void Board::assign_user_layer_positions()
635+
{
636+
const auto layers_sorted = get_layers_sorted(LayerSortOrder::BOTTOM_TO_TOP);
637+
const double step = 1.0 / BoardLayers::max_user_layers;
638+
double pos = BoardLayers::BOTTOM_NOTES - 1;
639+
for (const auto &it : layers_sorted) {
640+
if (BoardLayers::is_user(it.index)) {
641+
pos += step;
642+
layers.at(it.index).position = pos;
643+
user_layers.at(it.index).position = pos;
644+
}
645+
else {
646+
layers.at(it.index).position = it.index;
647+
pos = it.index;
648+
}
649+
}
650+
}
651+
652+
void Board::set_user_layer_name(int user_layer, const std::string &name)
653+
{
654+
user_layers.at(user_layer).name = name;
655+
update_layers();
656+
}
657+
658+
void Board::set_user_layer_type(int user_layer, UserLayer::Type type)
659+
{
660+
user_layers.at(user_layer).type = type;
661+
}
662+
663+
void Board::set_user_layer_color(int user_layer, int color_layer)
664+
{
665+
user_layers.at(user_layer).id_color = color_layer;
666+
}
667+
668+
void Board::move_user_layer(int user_layer, int other_layer, UserLayerOrder pos)
669+
{
670+
const double offset = 1.0 / (2 * BoardLayers::max_user_layers) * static_cast<int>(pos);
671+
user_layers.at(user_layer).position = layers.at(other_layer).position + offset;
672+
update_layers();
673+
}
674+
675+
676+
const std::map<int, Board::UserLayer> &Board::get_user_layers() const
677+
{
678+
return user_layers;
679+
}
680+
548681
void Board::update_pdf_export_settings(PDFExportSettings &settings)
549682
{
550683
auto layers_from_board = get_layers();
@@ -573,9 +706,10 @@ void Board::update_pdf_export_settings(PDFExportSettings &settings)
573706
add_layer(BoardLayers::TOP_PACKAGE, false);
574707
add_layer(BoardLayers::TOP_COPPER, false);
575708
for (const auto &la : layers_from_board) {
576-
if (BoardLayers::is_copper(la.first) && la.first > BoardLayers::BOTTOM_COPPER
577-
&& la.first < BoardLayers::TOP_COPPER)
578-
add_layer(la.first, false);
709+
if ((BoardLayers::is_copper(la.first) && la.first > BoardLayers::BOTTOM_COPPER
710+
&& la.first < BoardLayers::TOP_COPPER)
711+
|| BoardLayers::is_user(la.first))
712+
add_layer(la.first, BoardLayers::is_user(la.first));
579713
}
580714
add_layer(BoardLayers::BOTTOM_COPPER, false);
581715
add_layer(BoardLayers::BOTTOM_MASK, false);
@@ -1214,6 +1348,12 @@ json Board::serialize() const
12141348
j["net_ties"][(std::string)it.first] = it.second.serialize();
12151349
}
12161350
}
1351+
if (user_layers.size()) {
1352+
j["user_layers"] = json::object();
1353+
for (const auto &it : user_layers) {
1354+
j["user_layers"][std::to_string(it.first)] = it.second.serialize();
1355+
}
1356+
}
12171357
return j;
12181358
}
12191359

src/board/board.hpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,42 @@ class Board : public ObjectProvider, public LayerProvider {
139139
};
140140
std::map<int, StackupLayer> stackup;
141141

142+
143+
class UserLayer {
144+
public:
145+
UserLayer(int l, const json &j);
146+
UserLayer(int l);
147+
json serialize() const;
148+
149+
int id;
150+
int id_color;
151+
std::string name;
152+
double position;
153+
enum class Type {
154+
DOCUMENTATION,
155+
STIFFENER,
156+
COVERLAY,
157+
COVERCOAT,
158+
BEND_AREA,
159+
FLEX_AREA,
160+
RIGID_AREA,
161+
PSA,
162+
SILVER_MASK,
163+
CARBON_MASK
164+
};
165+
Type type;
166+
};
167+
const std::map<int, UserLayer> &get_user_layers() const;
168+
169+
enum class UserLayerOrder : int { ABOVE = 1, BELOW = -1 };
170+
int add_user_layer(int other_layer, UserLayerOrder pos);
171+
void delete_user_layer(int user_layer);
172+
unsigned int count_available_user_layers() const;
173+
void move_user_layer(int user_layer, int other_layer, UserLayerOrder pos);
174+
void set_user_layer_name(int user_layer, const std::string &name);
175+
void set_user_layer_type(int user_layer, UserLayer::Type type);
176+
void set_user_layer_color(int user_layer, int layer_color);
177+
142178
BoardColors colors;
143179
PDFExportSettings pdf_export_settings;
144180
STEPExportSettings step_export_settings;
@@ -197,6 +233,10 @@ class Board : public ObjectProvider, public LayerProvider {
197233
Board(const Board &brd, CopyMode copy_mode);
198234
void expand_packages();
199235
Outline get_outline(bool with_errors) const;
236+
237+
std::map<int, UserLayer> user_layers;
238+
void update_layers();
239+
void assign_user_layer_positions();
200240
};
201241

202242
inline Board::ExpandFlags operator|(Board::ExpandFlags a, Board::ExpandFlags b)

src/board/board_layers.cpp

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,20 +67,55 @@ std::string BoardLayers::get_layer_name(int l)
6767

6868
case BOTTOM_NOTES:
6969
return "Bottom Notes";
70+
71+
case USER1:
72+
case USER2:
73+
case USER3:
74+
case USER4:
75+
case USER5:
76+
case USER6:
77+
case USER7:
78+
case USER8:
79+
return "User " + std::to_string(l - FIRST_USER_LAYER + 1);
7080
}
7181
return "Invalid layer " + std::to_string(l);
7282
}
7383

7484
static const std::vector<int> layers = {
75-
BoardLayers::TOP_NOTES, BoardLayers::OUTLINE_NOTES, BoardLayers::L_OUTLINE,
76-
BoardLayers::TOP_COURTYARD, BoardLayers::TOP_ASSEMBLY, BoardLayers::TOP_PACKAGE,
77-
BoardLayers::TOP_PASTE, BoardLayers::TOP_SILKSCREEN, BoardLayers::TOP_MASK,
78-
BoardLayers::TOP_COPPER, BoardLayers::IN1_COPPER, BoardLayers::IN2_COPPER,
79-
BoardLayers::IN3_COPPER, BoardLayers::IN4_COPPER, BoardLayers::IN5_COPPER,
80-
BoardLayers::IN6_COPPER, BoardLayers::IN7_COPPER, BoardLayers::IN8_COPPER,
81-
BoardLayers::BOTTOM_COPPER, BoardLayers::BOTTOM_MASK, BoardLayers::BOTTOM_SILKSCREEN,
82-
BoardLayers::BOTTOM_PASTE, BoardLayers::BOTTOM_PACKAGE, BoardLayers::BOTTOM_ASSEMBLY,
83-
BoardLayers::BOTTOM_COURTYARD, BoardLayers::BOTTOM_NOTES,
85+
BoardLayers::TOP_NOTES,
86+
BoardLayers::OUTLINE_NOTES,
87+
BoardLayers::L_OUTLINE,
88+
BoardLayers::TOP_COURTYARD,
89+
BoardLayers::TOP_ASSEMBLY,
90+
BoardLayers::TOP_PACKAGE,
91+
BoardLayers::TOP_PASTE,
92+
BoardLayers::TOP_SILKSCREEN,
93+
BoardLayers::TOP_MASK,
94+
BoardLayers::TOP_COPPER,
95+
BoardLayers::IN1_COPPER,
96+
BoardLayers::IN2_COPPER,
97+
BoardLayers::IN3_COPPER,
98+
BoardLayers::IN4_COPPER,
99+
BoardLayers::IN5_COPPER,
100+
BoardLayers::IN6_COPPER,
101+
BoardLayers::IN7_COPPER,
102+
BoardLayers::IN8_COPPER,
103+
BoardLayers::BOTTOM_COPPER,
104+
BoardLayers::BOTTOM_MASK,
105+
BoardLayers::BOTTOM_SILKSCREEN,
106+
BoardLayers::BOTTOM_PASTE,
107+
BoardLayers::BOTTOM_PACKAGE,
108+
BoardLayers::BOTTOM_ASSEMBLY,
109+
BoardLayers::BOTTOM_COURTYARD,
110+
BoardLayers::BOTTOM_NOTES,
111+
BoardLayers::USER1,
112+
BoardLayers::USER2,
113+
BoardLayers::USER3,
114+
BoardLayers::USER4,
115+
BoardLayers::USER5,
116+
BoardLayers::USER6,
117+
BoardLayers::USER7,
118+
BoardLayers::USER8,
84119
};
85120

86121
const std::vector<int> &BoardLayers::get_layers()

src/board/board_layers.hpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ namespace horizon {
77
class BoardLayers {
88
public:
99
enum Layer {
10+
LAST_USER_LAYER = 1007,
11+
FIRST_USER_LAYER = 1000,
12+
USER1 = FIRST_USER_LAYER + 0,
13+
USER2 = FIRST_USER_LAYER + 1,
14+
USER3 = FIRST_USER_LAYER + 2,
15+
USER4 = FIRST_USER_LAYER + 3,
16+
USER5 = FIRST_USER_LAYER + 4,
17+
USER6 = FIRST_USER_LAYER + 5,
18+
USER7 = FIRST_USER_LAYER + 6,
19+
USER8 = FIRST_USER_LAYER + 7,
1020
TOP_NOTES = 200,
1121
OUTLINE_NOTES = 110,
1222
L_OUTLINE = 100,
@@ -35,6 +45,8 @@ class BoardLayers {
3545
BOTTOM_NOTES = -200
3646
};
3747

48+
static const unsigned int max_user_layers = LAST_USER_LAYER - FIRST_USER_LAYER + 1;
49+
3850
static const LayerRange layer_range_through;
3951

4052
static bool is_copper(int l)
@@ -52,6 +64,11 @@ class BoardLayers {
5264
return l == TOP_SILKSCREEN || l == BOTTOM_SILKSCREEN;
5365
}
5466

67+
static bool is_user(int l)
68+
{
69+
return l <= LAST_USER_LAYER && l >= FIRST_USER_LAYER;
70+
}
71+
5572
static const unsigned int max_inner_layers;
5673

5774
static std::string get_layer_name(int l);

src/board/gerber_output_settings.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,9 @@ void GerberOutputSettings::update_for_board(const Board &brd)
9696
add_layer(BoardLayers::TOP_MASK);
9797
add_layer(BoardLayers::TOP_COPPER);
9898
for (const auto &la : layers_from_board) {
99-
if (BoardLayers::is_copper(la.first) && la.first > BoardLayers::BOTTOM_COPPER
100-
&& la.first < BoardLayers::TOP_COPPER)
99+
if ((BoardLayers::is_copper(la.first) && la.first > BoardLayers::BOTTOM_COPPER
100+
&& la.first < BoardLayers::TOP_COPPER)
101+
|| BoardLayers::is_user(la.first))
101102
add_layer(la.first);
102103
}
103104
add_layer(BoardLayers::BOTTOM_COPPER);

src/canvas/appearance.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,15 @@ Appearance::Appearance()
6767
layer_colors[BoardLayers::BOTTOM_COURTYARD] = {.5, .5, .5};
6868

6969
layer_colors[BoardLayers::BOTTOM_NOTES] = {1, 1, 1};
70+
layer_colors[BoardLayers::USER1] = {.25, 1, 1};
71+
layer_colors[BoardLayers::USER2] = {.25, 1, 1};
72+
layer_colors[BoardLayers::USER3] = {.25, 1, 1};
73+
layer_colors[BoardLayers::USER4] = {.25, 1, 1};
74+
layer_colors[BoardLayers::USER5] = {.25, 1, 1};
75+
layer_colors[BoardLayers::USER6] = {.25, 1, 1};
76+
layer_colors[BoardLayers::USER7] = {.25, 1, 1};
77+
layer_colors[BoardLayers::USER8] = {.25, 1, 1};
78+
7079
layer_colors[10000] = {1, 1, 1};
7180
}
7281
} // namespace horizon

0 commit comments

Comments
 (0)