Skip to content

Commit 4e53f4e

Browse files
authored
Option to offset rotation of back layers 180º (#332)
* Option to flip back of pcb * Update form builder project, move checkbox * Rename feature to "offset back rotation" * Missed a few spots
1 parent 31b20f8 commit 4e53f4e

File tree

6 files changed

+102
-11
lines changed

6 files changed

+102
-11
lines changed

InteractiveHtmlBom/core/config.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class Config:
3737
html_config_fields = [
3838
'dark_mode', 'show_pads', 'show_fabrication', 'show_silkscreen',
3939
'highlight_pin1', 'redraw_on_drag', 'board_rotation', 'checkboxes',
40-
'bom_view', 'layer_view'
40+
'bom_view', 'layer_view', 'offset_back_rotation'
4141
]
4242
default_show_group_fields = ["Value", "Footprint"]
4343

@@ -51,6 +51,7 @@ class Config:
5151
highlight_pin1 = False
5252
redraw_on_drag = True
5353
board_rotation = 0
54+
offset_back_rotation = False
5455
checkboxes = ','.join(default_checkboxes)
5556
bom_view = bom_view_choices[1]
5657
layer_view = layer_view_choices[1]
@@ -114,6 +115,8 @@ def load_from_ini(self):
114115
self.highlight_pin1 = f.ReadBool('highlight_pin1', self.highlight_pin1)
115116
self.redraw_on_drag = f.ReadBool('redraw_on_drag', self.redraw_on_drag)
116117
self.board_rotation = f.ReadInt('board_rotation', self.board_rotation)
118+
self.offset_back_rotation = f.ReadBool(
119+
'offset_back_rotation', self.offset_back_rotation)
117120
self.checkboxes = f.Read('checkboxes', self.checkboxes)
118121
self.bom_view = f.Read('bom_view', self.bom_view)
119122
self.layer_view = f.Read('layer_view', self.layer_view)
@@ -166,6 +169,7 @@ def save(self, locally):
166169
f.WriteBool('highlight_pin1', self.highlight_pin1)
167170
f.WriteBool('redraw_on_drag', self.redraw_on_drag)
168171
f.WriteInt('board_rotation', self.board_rotation)
172+
f.WriteBool('offset_back_rotation', self.offset_back_rotation)
169173
f.Write('checkboxes', self.checkboxes)
170174
f.Write('bom_view', self.bom_view)
171175
f.Write('layer_view', self.layer_view)
@@ -210,6 +214,8 @@ def set_from_dialog(self, dlg):
210214
self.highlight_pin1 = dlg.html.highlightPin1Checkbox.IsChecked()
211215
self.redraw_on_drag = dlg.html.continuousRedrawCheckbox.IsChecked()
212216
self.board_rotation = dlg.html.boardRotationSlider.Value
217+
self.offset_back_rotation = \
218+
dlg.html.offsetBackRotationCheckbox.IsChecked()
213219
self.checkboxes = dlg.html.bomCheckboxesCtrl.Value
214220
self.bom_view = self.bom_view_choices[dlg.html.bomDefaultView.Selection]
215221
self.layer_view = self.layer_view_choices[
@@ -255,6 +261,7 @@ def transfer_to_dialog(self, dlg):
255261
dlg.html.highlightPin1Checkbox.Value = self.highlight_pin1
256262
dlg.html.continuousRedrawCheckbox.value = self.redraw_on_drag
257263
dlg.html.boardRotationSlider.Value = self.board_rotation
264+
dlg.html.offsetBackRotationCheckbox.Value = self.offset_back_rotation
258265
dlg.html.bomCheckboxesCtrl.Value = self.checkboxes
259266
dlg.html.bomDefaultView.Selection = self.bom_view_choices.index(
260267
self.bom_view)
@@ -332,6 +339,9 @@ def add_options(cls, parser, version):
332339
default=cls.board_rotation * 5,
333340
help='Board rotation in degrees (-180 to 180). '
334341
'Will be rounded to multiple of 5.')
342+
parser.add_argument('--offset-back-rotation',
343+
help='Offset the back of the pcb by 180 degrees',
344+
action='store_true')
335345
parser.add_argument('--checkboxes',
336346
default=cls.checkboxes,
337347
help='Comma separated list of checkbox columns.')
@@ -417,6 +427,7 @@ def set_from_args(self, args):
417427
self.highlight_pin1 = args.highlight_pin1
418428
self.redraw_on_drag = not args.no_redraw_on_drag
419429
self.board_rotation = math.fmod(args.board_rotation // 5, 37)
430+
self.offset_back_rotation = args.offset_back_rotation
420431
self.checkboxes = args.checkboxes
421432
self.bom_view = args.bom_view
422433
self.layer_view = args.layer_view

InteractiveHtmlBom/dialog/dialog_base.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,9 @@ def __init__( self, parent, id = wx.ID_ANY, pos = wx.DefaultPosition, size = wx.
148148

149149
b_sizer.Add( bSizer18, 0, wx.EXPAND, 5 )
150150

151+
self.offsetBackRotationCheckbox = wx.CheckBox( self, wx.ID_ANY, u"Offset back rotation", wx.DefaultPosition, wx.DefaultSize, 0 )
152+
b_sizer.Add( self.offsetBackRotationCheckbox, 0, wx.ALL, 5 )
153+
151154
sbSizer31 = wx.StaticBoxSizer( wx.StaticBox( self, wx.ID_ANY, u"Checkboxes" ), wx.HORIZONTAL )
152155

153156
self.bomCheckboxesCtrl = wx.TextCtrl( sbSizer31.GetStaticBox(), wx.ID_ANY, u"Sourced,Placed", wx.DefaultPosition, wx.DefaultSize, 0 )
@@ -569,5 +572,3 @@ def OnNetlistFileChanged( self, event ):
569572

570573
def OnBoardVariantFieldChange( self, event ):
571574
event.Skip()
572-
573-

InteractiveHtmlBom/web/ibom.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@
115115
<span style="float: right"><span id="rotationDegree">0</span>&#176;</span>
116116
<input id="boardRotation" type="range" min="-36" max="36" value="0" class="slider" oninput="setBoardRotation(this.value)">
117117
</label>
118+
<label class="menu-label">
119+
<input id="offsetBackRotationCheckbox" type="checkbox" onchange="setOffsetBackRotation(this.checked)">
120+
Offset back rotation
121+
</label>
118122
<label class="menu-label">
119123
<div style="margin-left: 5px">Bom checkboxes</div>
120124
<input id="bomCheckboxes" class="menu-textbox" type=text

InteractiveHtmlBom/web/render.js

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -557,12 +557,12 @@ function prepareCanvas(canvas, flip, transform) {
557557
ctx.scale(-1, 1);
558558
}
559559
ctx.translate(transform.x, transform.y);
560-
ctx.rotate(deg2rad(settings.boardRotation));
560+
ctx.rotate(deg2rad(settings.boardRotation + (flip && settings.offsetBackRotation ? - 180 : 0)));
561561
ctx.scale(transform.s, transform.s);
562562
}
563563

564564
function prepareLayer(canvasdict) {
565-
var flip = (canvasdict.layer == "B");
565+
var flip = (canvasdict.layer === "B");
566566
for (var c of ["bg", "fab", "silk", "highlight"]) {
567567
prepareCanvas(canvasdict[c], flip, canvasdict.transform);
568568
}
@@ -576,14 +576,14 @@ function rotateVector(v, angle) {
576576
];
577577
}
578578

579-
function applyRotation(bbox) {
579+
function applyRotation(bbox, flip) {
580580
var corners = [
581581
[bbox.minx, bbox.miny],
582582
[bbox.minx, bbox.maxy],
583583
[bbox.maxx, bbox.miny],
584584
[bbox.maxx, bbox.maxy],
585585
];
586-
corners = corners.map((v) => rotateVector(v, settings.boardRotation));
586+
corners = corners.map((v) => rotateVector(v, settings.boardRotation + (flip && settings.offsetBackRotation ? - 180 : 0)));
587587
return {
588588
minx: corners.reduce((a, v) => Math.min(a, v[0]), Infinity),
589589
miny: corners.reduce((a, v) => Math.min(a, v[1]), Infinity),
@@ -593,7 +593,8 @@ function applyRotation(bbox) {
593593
}
594594

595595
function recalcLayerScale(layerdict, width, height) {
596-
var bbox = applyRotation(pcbdata.edges_bbox);
596+
var flip = (layerdict.layer === "B");
597+
var bbox = applyRotation(pcbdata.edges_bbox, flip);
597598
var scalefactor = 0.98 * Math.min(
598599
width / (bbox.maxx - bbox.minx),
599600
height / (bbox.maxy - bbox.miny)
@@ -602,7 +603,6 @@ function recalcLayerScale(layerdict, width, height) {
602603
scalefactor = 1;
603604
}
604605
layerdict.transform.s = scalefactor;
605-
var flip = (layerdict.layer == "B");
606606
if (flip) {
607607
layerdict.transform.x = -((bbox.maxx + bbox.minx) * scalefactor + width) * 0.5;
608608
} else {
@@ -794,13 +794,14 @@ function handleMouseClick(e, layerdict) {
794794
var x = e.offsetX;
795795
var y = e.offsetY;
796796
var t = layerdict.transform;
797-
if (layerdict.layer == "B") {
797+
var flip = layerdict.layer === "B";
798+
if (flip) {
798799
x = (devicePixelRatio * x / t.zoom - t.panx + t.x) / -t.s;
799800
} else {
800801
x = (devicePixelRatio * x / t.zoom - t.panx - t.x) / t.s;
801802
}
802803
y = (devicePixelRatio * y / t.zoom - t.y - t.pany) / t.s;
803-
var v = rotateVector([x, y], -settings.boardRotation);
804+
var v = rotateVector([x, y], -settings.boardRotation + (flip && settings.offsetBackRotation ? - 180 : 0));
804805
if ("nets" in pcbdata) {
805806
var net = netHitScan(layerdict.layer, ...v);
806807
if (net !== highlightedNet) {
@@ -992,6 +993,12 @@ function setBoardRotation(value) {
992993
resizeAll();
993994
}
994995

996+
function setOffsetBackRotation(value) {
997+
settings.offsetBackRotation = value;
998+
writeStorage("offsetBackRotation", value);
999+
resizeAll();
1000+
}
1001+
9951002
function initRender() {
9961003
allcanvas = {
9971004
front: {

InteractiveHtmlBom/web/util.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,8 @@ function overwriteSettings(newSettings) {
440440
writeStorage("boardRotation", settings.boardRotation);
441441
document.getElementById("boardRotation").value = settings.boardRotation / 5;
442442
document.getElementById("rotationDegree").textContent = settings.boardRotation;
443+
setOffsetBackRotation(settings.offsetBackRotation);
444+
document.getElementById("offsetBackRotationCheckbox").checked = settings.offsetBackRotation;
443445
initDone = true;
444446
prepCheckboxes();
445447
changeBomLayout(settings.bomlayout);
@@ -477,6 +479,7 @@ var settings = {
477479
highlightpin1: false,
478480
redrawOnDrag: true,
479481
boardRotation: 0,
482+
offsetBackRotation: false,
480483
renderPads: true,
481484
renderReferences: true,
482485
renderValues: true,
@@ -572,6 +575,7 @@ function initDefaults() {
572575
}
573576
document.getElementById("boardRotation").value = settings.boardRotation / 5;
574577
document.getElementById("rotationDegree").textContent = settings.boardRotation;
578+
initBooleanSetting("offsetBackRotation", config.offset_back_rotation, "offsetBackRotationCheckbox", setOffsetBackRotation);
575579
}
576580

577581
// Helper classes for user js callbacks.

settings_dialog.fbp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,70 @@
10311031
</object>
10321032
</object>
10331033
</object>
1034+
<object class="sizeritem" expanded="0">
1035+
<property name="border">5</property>
1036+
<property name="flag">wxALL</property>
1037+
<property name="proportion">0</property>
1038+
<object class="wxCheckBox" expanded="0">
1039+
<property name="BottomDockable">1</property>
1040+
<property name="LeftDockable">1</property>
1041+
<property name="RightDockable">1</property>
1042+
<property name="TopDockable">1</property>
1043+
<property name="aui_layer"></property>
1044+
<property name="aui_name"></property>
1045+
<property name="aui_position"></property>
1046+
<property name="aui_row"></property>
1047+
<property name="best_size"></property>
1048+
<property name="bg"></property>
1049+
<property name="caption"></property>
1050+
<property name="caption_visible">1</property>
1051+
<property name="center_pane">0</property>
1052+
<property name="checked">0</property>
1053+
<property name="close_button">1</property>
1054+
<property name="context_help"></property>
1055+
<property name="context_menu">1</property>
1056+
<property name="default_pane">0</property>
1057+
<property name="dock">Dock</property>
1058+
<property name="dock_fixed">0</property>
1059+
<property name="docking">Left</property>
1060+
<property name="enabled">1</property>
1061+
<property name="fg"></property>
1062+
<property name="floatable">1</property>
1063+
<property name="font"></property>
1064+
<property name="gripper">0</property>
1065+
<property name="hidden">0</property>
1066+
<property name="id">wxID_ANY</property>
1067+
<property name="label">Offset back rotation</property>
1068+
<property name="max_size"></property>
1069+
<property name="maximize_button">0</property>
1070+
<property name="maximum_size"></property>
1071+
<property name="min_size"></property>
1072+
<property name="minimize_button">0</property>
1073+
<property name="minimum_size"></property>
1074+
<property name="moveable">1</property>
1075+
<property name="name">offsetBackRotationCheckbox</property>
1076+
<property name="pane_border">1</property>
1077+
<property name="pane_position"></property>
1078+
<property name="pane_size"></property>
1079+
<property name="permission">protected</property>
1080+
<property name="pin_button">1</property>
1081+
<property name="pos"></property>
1082+
<property name="resize">Resizable</property>
1083+
<property name="show">1</property>
1084+
<property name="size"></property>
1085+
<property name="style"></property>
1086+
<property name="subclass">; ; forward_declare</property>
1087+
<property name="toolbar_pane">0</property>
1088+
<property name="tooltip"></property>
1089+
<property name="validator_data_type"></property>
1090+
<property name="validator_style">wxFILTER_NONE</property>
1091+
<property name="validator_type">wxDefaultValidator</property>
1092+
<property name="validator_variable"></property>
1093+
<property name="window_extra_style"></property>
1094+
<property name="window_name"></property>
1095+
<property name="window_style"></property>
1096+
</object>
1097+
</object>
10341098
<object class="sizeritem" expanded="1">
10351099
<property name="border">5</property>
10361100
<property name="flag">wxALL|wxEXPAND</property>

0 commit comments

Comments
 (0)