Resistors, capacitors, diodes, ICs, transistors and other PCB parts can be placed on the bottom of the board with the new 'Board Side' property; Gerber export puts their silkscreen on the bottom layer with the text mirrored

This commit is contained in:
Bane Stojkovic
2026-11-11 15:15:19 +01:00
parent 16f54fa479
commit df873df04a
36 changed files with 498 additions and 54 deletions
@@ -162,13 +162,16 @@ public class GerberExporter {
IGerberComponentSimple gerberComponentSimple = (IGerberComponentSimple) gerberComponent; IGerberComponentSimple gerberComponentSimple = (IGerberComponentSimple) gerberComponent;
GerberLayer layer = gerberComponentSimple.getGerberLayer(); GerberLayer layer = gerberComponentSimple.getGerberLayer();
// components emit their top-side layer; a part mounted underneath goes to the bottom one // components emit their top-side layer; a part mounted underneath goes to the bottom one
if (c instanceof IBoardSideComponent boolean bottomSide = c instanceof IBoardSideComponent
&& ((IBoardSideComponent) c).getBoardSide() == PCBLayer._1) { && ((IBoardSideComponent) c).getBoardSide() == PCBLayer._1;
if (bottomSide) {
layer = layer.flip(); layer = layer.flip();
} }
g2d.startGerberOutput(layer, gerberComponentSimple.getGerberFunction(), g2d.startGerberOutput(layer, gerberComponentSimple.getGerberFunction(),
gerberComponentSimple.isGerberNegative()); gerberComponentSimple.isGerberNegative());
g2d.setMirrorText(bottomSide);
c.draw(g2d, ComponentState.NORMAL, outlineMode, currentProject, g2d); c.draw(g2d, ComponentState.NORMAL, outlineMode, currentProject, g2d);
g2d.setMirrorText(false);
g2d.stopGerberOutput(); g2d.stopGerberOutput();
} }
} }
@@ -58,6 +58,7 @@ public class GerberG2DWrapper extends Graphics2D
private double tolerance; private double tolerance;
private Rectangle2D boardRect; private Rectangle2D boardRect;
private boolean mirrorText = false;
public GerberG2DWrapper(Graphics2D graphics2d, String diylcVersion, Rectangle2D boardRect) { public GerberG2DWrapper(Graphics2D graphics2d, String diylcVersion, Rectangle2D boardRect) {
super(); super();
@@ -154,6 +155,15 @@ public class GerberG2DWrapper extends Graphics2D
return layerMap; return layerMap;
} }
/**
* Sets whether text is written mirrored, each string about its own centre. The output is in top
* view, so text on the bottom side has to be mirrored to read correctly once the board is turned
* over.
*/
public void setMirrorText(boolean mirrorText) {
this.mirrorText = mirrorText;
}
@Override @Override
public void draw(Shape s) { public void draw(Shape s) {
if (trackingGerber && !getColor().equals(Constants.TRANSPARENT_COLOR)) { if (trackingGerber && !getColor().equals(Constants.TRANSPARENT_COLOR)) {
@@ -181,6 +191,10 @@ public class GerberG2DWrapper extends Graphics2D
GlyphVector gv = font.createGlyphVector(graphics2d.getFontRenderContext(), str); GlyphVector gv = font.createGlyphVector(graphics2d.getFontRenderContext(), str);
AffineTransform translateInstance = AffineTransform.getTranslateInstance(x, y); AffineTransform translateInstance = AffineTransform.getTranslateInstance(x, y);
if (mirrorText) {
translateInstance.translate(gv.getLogicalBounds().getWidth(), 0);
translateInstance.scale(-1, 1);
}
for (int i = 0; i < gv.getNumGlyphs(); i++) { for (int i = 0; i < gv.getNumGlyphs(); i++) {
Shape glyphShape = gv.getGlyphOutline(i); Shape glyphShape = gv.getGlyphOutline(i);
@@ -22,12 +22,17 @@
package org.diylc.core.gerber; package org.diylc.core.gerber;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.awt.Color; import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List;
import org.diylc.common.PCBLayer; import org.diylc.common.PCBLayer;
import org.diylc.core.ComponentState; import org.diylc.core.ComponentState;
@@ -74,6 +79,49 @@ public class GerberExporterTest {
assertEquals(EnumSet.of(GerberLayer.SilkscreenTop), EnumSet.copyOf(g2d.getLayerMap().keySet())); assertEquals(EnumSet.of(GerberLayer.SilkscreenTop), EnumSet.copyOf(g2d.getLayerMap().keySet()));
} }
@Test
public void testTopSideTextReadsLeftToRight() {
List<Rectangle2D> glyphs = drawText(PCBLayer._2);
assertTrue(glyphs.get(0).getMinX() < glyphs.get(1).getMinX());
}
@Test
public void testBottomSideTextIsMirrored() {
List<Rectangle2D> top = drawText(PCBLayer._2);
List<Rectangle2D> bottom = drawText(PCBLayer._1);
// seen from the top, the first letter of a bottom-side label is on the right
assertTrue(bottom.get(0).getMinX() > bottom.get(1).getMinX());
// mirrored about the centre of its layout box, so the text stays where it was; the glyphs'
// uneven side bearings move their drawn bounds by a pixel or so
assertEquals(union(top).getCenterX(), union(bottom).getCenterX(), 2);
}
private static List<Rectangle2D> drawText(PCBLayer side) {
List<Rectangle2D> glyphs = new ArrayList<Rectangle2D>();
BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = img.createGraphics();
GerberG2DWrapper g2d =
new GerberG2DWrapper(graphics, "test", new Rectangle2D.Double(0, 0, 100, 100)) {
@Override
public void fillShape(Shape s) {
glyphs.add(s.getBounds2D());
}
};
GerberExporter.drawComponent(new Project(), g2d, new TextGerberComponent(side), false);
graphics.dispose();
return glyphs;
}
private static Rectangle2D union(List<Rectangle2D> rects) {
Rectangle2D union = (Rectangle2D) rects.get(0).clone();
for (Rectangle2D rect : rects) {
union.add(rect);
}
return union;
}
private static GerberG2DWrapper draw(SimpleGerberComponent component) { private static GerberG2DWrapper draw(SimpleGerberComponent component) {
BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB); BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = img.createGraphics(); Graphics2D graphics = img.createGraphics();
@@ -126,4 +174,21 @@ public class GerberExporterTest {
return side; return side;
} }
} }
public static class TextGerberComponent extends SidedGerberComponent {
private static final long serialVersionUID = 1L;
public TextGerberComponent(PCBLayer side) {
super(side);
}
@Override
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode,
Project project, IDrawingObserver drawingObserver) {
g2d.setColor(Color.black);
g2d.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 20));
g2d.drawString("AB", 10, 50);
}
}
} }
@@ -32,10 +32,12 @@ import org.diylc.appframework.miscutils.ConfigurationManager;
import org.diylc.common.IPlugInPort; import org.diylc.common.IPlugInPort;
import org.diylc.common.ObjectCache; import org.diylc.common.ObjectCache;
import org.diylc.common.Orientation; import org.diylc.common.Orientation;
import org.diylc.common.PCBLayer;
import org.diylc.components.AbstractTransparentComponent; import org.diylc.components.AbstractTransparentComponent;
import org.diylc.components.connectivity.PCBTerminalBlock.PCBTerminalBlockCount; import org.diylc.components.connectivity.PCBTerminalBlock.PCBTerminalBlockCount;
import org.diylc.components.transform.PCBTerminalBlockTransformer; import org.diylc.components.transform.PCBTerminalBlockTransformer;
import org.diylc.core.ComponentState; import org.diylc.core.ComponentState;
import org.diylc.core.IBoardSideComponent;
import org.diylc.core.IDIYComponent; import org.diylc.core.IDIYComponent;
import org.diylc.core.IDrawingObserver; import org.diylc.core.IDrawingObserver;
import org.diylc.core.Project; import org.diylc.core.Project;
@@ -52,7 +54,7 @@ import org.diylc.utils.Constants;
author = "Branislav Stojkovic", description = "Horizontal PCB terminal block with configurable pitch", author = "Branislav Stojkovic", description = "Horizontal PCB terminal block with configurable pitch",
zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "TB", zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "TB",
enableCache = true, transformer = PCBTerminalBlockTransformer.class) enableCache = true, transformer = PCBTerminalBlockTransformer.class)
public class PCBTerminalBlock extends AbstractTransparentComponent<PCBTerminalBlockCount> implements IGerberComponentSimple { public class PCBTerminalBlock extends AbstractTransparentComponent<PCBTerminalBlockCount> implements IGerberComponentSimple, IBoardSideComponent {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -72,6 +74,7 @@ public class PCBTerminalBlock extends AbstractTransparentComponent<PCBTerminalBl
private Size width = new Size(0.3d, SizeUnit.in); private Size width = new Size(0.3d, SizeUnit.in);
private ScrewPosition screwPosition = ScrewPosition.Offset; private ScrewPosition screwPosition = ScrewPosition.Offset;
private String nodeNames = ""; private String nodeNames = "";
private PCBLayer boardSide;
public PCBTerminalBlock() { public PCBTerminalBlock() {
super(); super();
@@ -370,6 +373,16 @@ public class PCBTerminalBlock extends AbstractTransparentComponent<PCBTerminalBl
bounds.getWidth() + 2 * margin, bounds.getHeight() + 2 * margin); bounds.getWidth() + 2 * margin, bounds.getHeight() + 2 * margin);
} }
@EditableProperty(name = "Board Side")
@Override
public PCBLayer getBoardSide() {
return boardSide == null ? PCBLayer._2 : boardSide;
}
public void setBoardSide(PCBLayer boardSide) {
this.boardSide = boardSide;
}
static enum PCBTerminalBlockCount { static enum PCBTerminalBlockCount {
_2("Two"), _3("Three"), _4("Four"), _5("Five"), _6("Six"), _7("Seven"), _8("Eight"), _9( _2("Two"), _3("Three"), _4("Four"), _5("Five"), _6("Six"), _7("Seven"), _8("Eight"), _9(
"Nine"), _10("Ten"); "Nine"), _10("Ten");
@@ -40,10 +40,12 @@ import org.diylc.common.HorizontalAlignment;
import org.diylc.common.IPlugInPort; import org.diylc.common.IPlugInPort;
import org.diylc.common.ObjectCache; import org.diylc.common.ObjectCache;
import org.diylc.common.Orientation; import org.diylc.common.Orientation;
import org.diylc.common.PCBLayer;
import org.diylc.common.VerticalAlignment; import org.diylc.common.VerticalAlignment;
import org.diylc.components.AbstractMultiPartComponent; import org.diylc.components.AbstractMultiPartComponent;
import org.diylc.components.transform.CliffJackTransformer; import org.diylc.components.transform.CliffJackTransformer;
import org.diylc.core.ComponentState; import org.diylc.core.ComponentState;
import org.diylc.core.IBoardSideComponent;
import org.diylc.core.IDIYComponent; import org.diylc.core.IDIYComponent;
import org.diylc.core.IDrawingObserver; import org.diylc.core.IDrawingObserver;
import org.diylc.core.Project; import org.diylc.core.Project;
@@ -62,7 +64,7 @@ import org.diylc.utils.Constants;
description = "Cliff-style closed panel mount 1/4\" phono jack", description = "Cliff-style closed panel mount 1/4\" phono jack",
zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "J", transformer = CliffJackTransformer.class, zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "J", transformer = CliffJackTransformer.class,
enableCache = true) enableCache = true)
public class CliffJack1_4 extends AbstractMultiPartComponent<JackType> implements IGerberComponentSimple { public class CliffJack1_4 extends AbstractMultiPartComponent<JackType> implements IGerberComponentSimple, IBoardSideComponent {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -84,6 +86,7 @@ public class CliffJack1_4 extends AbstractMultiPartComponent<JackType> implement
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Deprecated @Deprecated
private transient String value = ""; private transient String value = "";
private PCBLayer boardSide;
public CliffJack1_4() { public CliffJack1_4() {
super(); super();
@@ -373,4 +376,14 @@ public class CliffJack1_4 extends AbstractMultiPartComponent<JackType> implement
public boolean canPointMoveFreely(int pointIndex) { public boolean canPointMoveFreely(int pointIndex) {
return false; return false;
} }
@EditableProperty(name = "Board Side")
@Override
public PCBLayer getBoardSide() {
return boardSide == null ? PCBLayer._2 : boardSide;
}
public void setBoardSide(PCBLayer boardSide) {
this.boardSide = boardSide;
}
} }
@@ -36,10 +36,12 @@ import org.diylc.common.HorizontalAlignment;
import org.diylc.common.IPlugInPort; import org.diylc.common.IPlugInPort;
import org.diylc.common.ObjectCache; import org.diylc.common.ObjectCache;
import org.diylc.common.Orientation; import org.diylc.common.Orientation;
import org.diylc.common.PCBLayer;
import org.diylc.common.VerticalAlignment; import org.diylc.common.VerticalAlignment;
import org.diylc.components.AbstractMultiPartComponent; import org.diylc.components.AbstractMultiPartComponent;
import org.diylc.components.transform.CliffJackTransformer; import org.diylc.components.transform.CliffJackTransformer;
import org.diylc.core.ComponentState; import org.diylc.core.ComponentState;
import org.diylc.core.IBoardSideComponent;
import org.diylc.core.IDIYComponent; import org.diylc.core.IDIYComponent;
import org.diylc.core.IDrawingObserver; import org.diylc.core.IDrawingObserver;
import org.diylc.core.Project; import org.diylc.core.Project;
@@ -56,7 +58,7 @@ import org.diylc.utils.Constants;
author = "Branislav Stojkovic", description = "Cliff-style closed 1/8\" phono jack", author = "Branislav Stojkovic", description = "Cliff-style closed 1/8\" phono jack",
zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "J", zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "J",
transformer = CliffJackTransformer.class, enableCache = true) transformer = CliffJackTransformer.class, enableCache = true)
public class CliffJack1_8 extends AbstractMultiPartComponent<JackType> implements IGerberComponentSimple { public class CliffJack1_8 extends AbstractMultiPartComponent<JackType> implements IGerberComponentSimple, IBoardSideComponent {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -80,6 +82,7 @@ public class CliffJack1_8 extends AbstractMultiPartComponent<JackType> implement
private Orientation orientation = Orientation.DEFAULT; private Orientation orientation = Orientation.DEFAULT;
transient private Shape[] body; transient private Shape[] body;
private boolean nut = false; private boolean nut = false;
private PCBLayer boardSide;
public CliffJack1_8() { public CliffJack1_8() {
super(); super();
@@ -394,4 +397,14 @@ public class CliffJack1_8 extends AbstractMultiPartComponent<JackType> implement
public boolean canPointMoveFreely(int pointIndex) { public boolean canPointMoveFreely(int pointIndex) {
return false; return false;
} }
@EditableProperty(name = "Board Side")
@Override
public PCBLayer getBoardSide() {
return boardSide == null ? PCBLayer._2 : boardSide;
}
public void setBoardSide(PCBLayer boardSide) {
this.boardSide = boardSide;
}
} }
@@ -41,10 +41,12 @@ import org.diylc.common.HorizontalAlignment;
import org.diylc.common.IPlugInPort; import org.diylc.common.IPlugInPort;
import org.diylc.common.ObjectCache; import org.diylc.common.ObjectCache;
import org.diylc.common.Orientation; import org.diylc.common.Orientation;
import org.diylc.common.PCBLayer;
import org.diylc.common.VerticalAlignment; import org.diylc.common.VerticalAlignment;
import org.diylc.components.AbstractMultiPartComponent; import org.diylc.components.AbstractMultiPartComponent;
import org.diylc.components.transform.ClosedJackTransformer; import org.diylc.components.transform.ClosedJackTransformer;
import org.diylc.core.ComponentState; import org.diylc.core.ComponentState;
import org.diylc.core.IBoardSideComponent;
import org.diylc.core.IDIYComponent; import org.diylc.core.IDIYComponent;
import org.diylc.core.IDrawingObserver; import org.diylc.core.IDrawingObserver;
import org.diylc.core.Project; import org.diylc.core.Project;
@@ -62,7 +64,7 @@ import org.diylc.utils.Constants;
@ComponentDescriptor(name = "Closed 1/4\" Jack", category = "Electro-Mechanical", author = "Branislav Stojkovic", @ComponentDescriptor(name = "Closed 1/4\" Jack", category = "Electro-Mechanical", author = "Branislav Stojkovic",
description = "Enclosed panel mount 1/4\" phono jack", zOrder = IDIYComponent.COMPONENT, description = "Enclosed panel mount 1/4\" phono jack", zOrder = IDIYComponent.COMPONENT,
instanceNamePrefix = "J", transformer = ClosedJackTransformer.class, enableCache = true) instanceNamePrefix = "J", transformer = ClosedJackTransformer.class, enableCache = true)
public class ClosedJack1_4 extends AbstractMultiPartComponent<JackType> implements IGerberComponentSimple { public class ClosedJack1_4 extends AbstractMultiPartComponent<JackType> implements IGerberComponentSimple, IBoardSideComponent {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -86,6 +88,7 @@ public class ClosedJack1_4 extends AbstractMultiPartComponent<JackType> implemen
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Deprecated @Deprecated
private transient String value = ""; private transient String value = "";
private PCBLayer boardSide;
public ClosedJack1_4() { public ClosedJack1_4() {
super(); super();
@@ -380,4 +383,14 @@ public class ClosedJack1_4 extends AbstractMultiPartComponent<JackType> implemen
public boolean canPointMoveFreely(int pointIndex) { public boolean canPointMoveFreely(int pointIndex) {
return false; return false;
} }
@EditableProperty(name = "Board Side")
@Override
public PCBLayer getBoardSide() {
return boardSide == null ? PCBLayer._2 : boardSide;
}
public void setBoardSide(PCBLayer boardSide) {
this.boardSide = boardSide;
}
} }
@@ -40,6 +40,7 @@ import org.diylc.components.AbstractTransparentComponent;
import org.diylc.components.guitar.ToggleSwitchPositionPropertyValueSource; import org.diylc.components.guitar.ToggleSwitchPositionPropertyValueSource;
import org.diylc.components.transform.MiniToggleSwitchTransformer; import org.diylc.components.transform.MiniToggleSwitchTransformer;
import org.diylc.core.ComponentState; import org.diylc.core.ComponentState;
import org.diylc.core.IBoardSideComponent;
import org.diylc.core.IDIYComponent; import org.diylc.core.IDIYComponent;
import org.diylc.core.IDrawingObserver; import org.diylc.core.IDrawingObserver;
import org.diylc.core.ILayeredComponent; import org.diylc.core.ILayeredComponent;
@@ -62,7 +63,7 @@ import org.diylc.utils.SwitchUtils;
@ComponentDescriptor(name = "Mini Toggle Switch", category = "Electro-Mechanical", author = "Branislav Stojkovic", @ComponentDescriptor(name = "Mini Toggle Switch", category = "Electro-Mechanical", author = "Branislav Stojkovic",
description = "Panel mounted mini toggle switch", zOrder = IDIYComponent.COMPONENT, description = "Panel mounted mini toggle switch", zOrder = IDIYComponent.COMPONENT,
instanceNamePrefix = "SW", enableCache = true, transformer = MiniToggleSwitchTransformer.class) instanceNamePrefix = "SW", enableCache = true, transformer = MiniToggleSwitchTransformer.class)
public class MiniToggleSwitch extends AbstractTransparentComponent<ToggleSwitchType> implements ISwitch, ILayeredComponent, IGerberComponentSimple { public class MiniToggleSwitch extends AbstractTransparentComponent<ToggleSwitchType> implements ISwitch, ILayeredComponent, IGerberComponentSimple, IBoardSideComponent {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -96,6 +97,7 @@ public class MiniToggleSwitch extends AbstractTransparentComponent<ToggleSwitchT
@Deprecated @Deprecated
protected String name; protected String name;
private PCBLayer boardSide;
public MiniToggleSwitch() { public MiniToggleSwitch() {
super(); super();
@@ -636,4 +638,14 @@ public class MiniToggleSwitch extends AbstractTransparentComponent<ToggleSwitchT
public int getLayerId() { public int getLayerId() {
return hashCode(); return hashCode();
} }
@EditableProperty(name = "Board Side")
@Override
public PCBLayer getBoardSide() {
return boardSide == null ? PCBLayer._2 : boardSide;
}
public void setBoardSide(PCBLayer boardSide) {
this.boardSide = boardSide;
}
} }
@@ -24,7 +24,9 @@ import org.diylc.appframework.miscutils.ConfigurationManager;
import org.diylc.common.IPlugInPort; import org.diylc.common.IPlugInPort;
import org.diylc.common.ObjectCache; import org.diylc.common.ObjectCache;
import org.diylc.common.PCBLayer;
import org.diylc.components.AbstractLeadedComponent; import org.diylc.components.AbstractLeadedComponent;
import org.diylc.core.IBoardSideComponent;
import org.diylc.core.Theme; import org.diylc.core.Theme;
import org.diylc.core.annotations.EditableProperty; import org.diylc.core.annotations.EditableProperty;
import org.diylc.core.annotations.PositiveMeasureValidator; import org.diylc.core.annotations.PositiveMeasureValidator;
@@ -34,7 +36,7 @@ import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit; import org.diylc.core.measures.SizeUnit;
import org.diylc.utils.Constants; import org.diylc.utils.Constants;
public abstract class AbstractFilmCapacitor extends AbstractLeadedComponent<Capacitance> implements IGerberComponentSimple { public abstract class AbstractFilmCapacitor extends AbstractLeadedComponent<Capacitance> implements IGerberComponentSimple, IBoardSideComponent {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -49,6 +51,7 @@ public abstract class AbstractFilmCapacitor extends AbstractLeadedComponent<Capa
protected Boolean showOuterFoil = false; protected Boolean showOuterFoil = false;
protected Color outerFoilColor = OUTER_FOIL_COLOR; protected Color outerFoilColor = OUTER_FOIL_COLOR;
protected String type; protected String type;
private PCBLayer boardSide;
@EditableProperty(validatorClass = PositiveMeasureValidator.class) @EditableProperty(validatorClass = PositiveMeasureValidator.class)
public Capacitance getValue() { public Capacitance getValue() {
@@ -145,4 +148,14 @@ public abstract class AbstractFilmCapacitor extends AbstractLeadedComponent<Capa
public void setOuterFoilColor(Color outerFoilColor) { public void setOuterFoilColor(Color outerFoilColor) {
this.outerFoilColor = outerFoilColor; this.outerFoilColor = outerFoilColor;
} }
@EditableProperty(name = "Board Side")
@Override
public PCBLayer getBoardSide() {
return boardSide == null ? PCBLayer._2 : boardSide;
}
public void setBoardSide(PCBLayer boardSide) {
this.boardSide = boardSide;
}
} }
@@ -24,14 +24,16 @@ package org.diylc.components.passive;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
import org.diylc.common.Orientation; import org.diylc.common.Orientation;
import org.diylc.common.PCBLayer;
import org.diylc.components.AbstractLabeledComponent; import org.diylc.components.AbstractLabeledComponent;
import org.diylc.core.IBoardSideComponent;
import org.diylc.core.VisibilityPolicy; import org.diylc.core.VisibilityPolicy;
import org.diylc.core.annotations.EditableProperty; import org.diylc.core.annotations.EditableProperty;
import org.diylc.core.annotations.PositiveMeasureValidator; import org.diylc.core.annotations.PositiveMeasureValidator;
import org.diylc.core.gerber.IGerberComponentSimple; import org.diylc.core.gerber.IGerberComponentSimple;
import org.diylc.core.measures.Resistance; import org.diylc.core.measures.Resistance;
public abstract class AbstractPotentiometer extends AbstractLabeledComponent<Resistance> implements IGerberComponentSimple { public abstract class AbstractPotentiometer extends AbstractLabeledComponent<Resistance> implements IGerberComponentSimple, IBoardSideComponent {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -40,6 +42,7 @@ public abstract class AbstractPotentiometer extends AbstractLabeledComponent<Res
protected Resistance resistance = null; protected Resistance resistance = null;
protected Orientation orientation = Orientation.DEFAULT; protected Orientation orientation = Orientation.DEFAULT;
protected Taper taper = Taper.LIN; protected Taper taper = Taper.LIN;
private PCBLayer boardSide;
@Override @Override
public int getControlPointCount() { public int getControlPointCount() {
@@ -110,4 +113,14 @@ public abstract class AbstractPotentiometer extends AbstractLabeledComponent<Res
return null; return null;
} }
@EditableProperty(name = "Board Side")
@Override
public PCBLayer getBoardSide() {
return boardSide == null ? PCBLayer._2 : boardSide;
}
public void setBoardSide(PCBLayer boardSide) {
this.boardSide = boardSide;
}
} }
@@ -23,7 +23,9 @@ package org.diylc.components.passive;
import java.awt.Rectangle; import java.awt.Rectangle;
import org.diylc.common.PCBLayer;
import org.diylc.components.AbstractLeadedComponent; import org.diylc.components.AbstractLeadedComponent;
import org.diylc.core.IBoardSideComponent;
import org.diylc.core.annotations.AiNote; import org.diylc.core.annotations.AiNote;
import org.diylc.core.annotations.EditableProperty; import org.diylc.core.annotations.EditableProperty;
import org.diylc.core.gerber.IGerberComponentSimple; import org.diylc.core.gerber.IGerberComponentSimple;
@@ -39,7 +41,7 @@ import org.diylc.core.measures.SizeUnit;
* @param <T> * @param <T>
*/ */
@AiNote("The two control points are the holes; the body's own leads are 'Lead Spacing' apart and centred between them, with lead wire drawn out to each hole. Place the points exactly 'Lead Spacing' apart for straight leads") @AiNote("The two control points are the holes; the body's own leads are 'Lead Spacing' apart and centred between them, with lead wire drawn out to each hole. Place the points exactly 'Lead Spacing' apart for straight leads")
public abstract class AbstractRadialComponent<T> extends AbstractLeadedComponent<T> implements IGerberComponentSimple { public abstract class AbstractRadialComponent<T> extends AbstractLeadedComponent<T> implements IGerberComponentSimple, IBoardSideComponent {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -48,6 +50,7 @@ public abstract class AbstractRadialComponent<T> extends AbstractLeadedComponent
protected Size pinSpacing = PIN_SPACING; protected Size pinSpacing = PIN_SPACING;
protected String type; protected String type;
private PCBLayer boardSide;
@Override @Override
protected int calculatePinSpacing(Rectangle shapeRect) { protected int calculatePinSpacing(Rectangle shapeRect) {
@@ -74,4 +77,14 @@ public abstract class AbstractRadialComponent<T> extends AbstractLeadedComponent
public void setType(String type) { public void setType(String type) {
this.type = type; this.type = type;
} }
@EditableProperty(name = "Board Side")
@Override
public PCBLayer getBoardSide() {
return boardSide == null ? PCBLayer._2 : boardSide;
}
public void setBoardSide(PCBLayer boardSide) {
this.boardSide = boardSide;
}
} }
@@ -29,10 +29,12 @@ import org.diylc.appframework.miscutils.ConfigurationManager;
import org.diylc.common.IPlugInPort; import org.diylc.common.IPlugInPort;
import org.diylc.common.ObjectCache; import org.diylc.common.ObjectCache;
import org.diylc.common.PCBLayer;
import org.diylc.components.AbstractLeadedComponent; import org.diylc.components.AbstractLeadedComponent;
import org.diylc.components.passive.CapacitorDatasheetService.CapacitorDatasheet; import org.diylc.components.passive.CapacitorDatasheetService.CapacitorDatasheet;
import org.diylc.components.transform.SimpleComponentTransformer; import org.diylc.components.transform.SimpleComponentTransformer;
import org.diylc.core.CreationMethod; import org.diylc.core.CreationMethod;
import org.diylc.core.IBoardSideComponent;
import org.diylc.core.IDIYComponent; import org.diylc.core.IDIYComponent;
import org.diylc.core.IDatasheetSupport; import org.diylc.core.IDatasheetSupport;
import org.diylc.core.Theme; import org.diylc.core.Theme;
@@ -53,7 +55,7 @@ import org.diylc.utils.Constants;
description = "Axial electrolytic capacitor, similar to Sprague Atom, F&T, etc", description = "Axial electrolytic capacitor, similar to Sprague Atom, F&T, etc",
zOrder = IDIYComponent.COMPONENT, transformer = SimpleComponentTransformer.class, zOrder = IDIYComponent.COMPONENT, transformer = SimpleComponentTransformer.class,
enableCache = true, enableDatasheet = true, datasheetCreationStepCount = 3) enableCache = true, enableDatasheet = true, datasheetCreationStepCount = 3)
public class AxialElectrolyticCapacitor extends AbstractLeadedComponent<Capacitance> implements IDatasheetSupport, IGerberComponentSimple { public class AxialElectrolyticCapacitor extends AbstractLeadedComponent<Capacitance> implements IDatasheetSupport, IGerberComponentSimple, IBoardSideComponent {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -73,6 +75,7 @@ public class AxialElectrolyticCapacitor extends AbstractLeadedComponent<Capacita
private Color tickColor = TICK_COLOR; private Color tickColor = TICK_COLOR;
private boolean polarized = true; private boolean polarized = true;
private String type; private String type;
private PCBLayer boardSide;
public AxialElectrolyticCapacitor() { public AxialElectrolyticCapacitor() {
super(); super();
@@ -296,4 +299,14 @@ public class AxialElectrolyticCapacitor extends AbstractLeadedComponent<Capacita
return new Color((int) r, (int) g, (int) b, (int) a); return new Color((int) r, (int) g, (int) b, (int) a);
} }
@EditableProperty(name = "Board Side")
@Override
public PCBLayer getBoardSide() {
return boardSide == null ? PCBLayer._2 : boardSide;
}
public void setBoardSide(PCBLayer boardSide) {
this.boardSide = boardSide;
}
} }
@@ -28,9 +28,11 @@ import java.awt.Shape;
import java.awt.geom.RoundRectangle2D; import java.awt.geom.RoundRectangle2D;
import org.diylc.common.ObjectCache; import org.diylc.common.ObjectCache;
import org.diylc.common.PCBLayer;
import org.diylc.components.AbstractLeadedComponent; import org.diylc.components.AbstractLeadedComponent;
import org.diylc.components.transform.SimpleComponentTransformer; import org.diylc.components.transform.SimpleComponentTransformer;
import org.diylc.core.CreationMethod; import org.diylc.core.CreationMethod;
import org.diylc.core.IBoardSideComponent;
import org.diylc.core.IDIYComponent; import org.diylc.core.IDIYComponent;
import org.diylc.core.annotations.ComponentDescriptor; import org.diylc.core.annotations.ComponentDescriptor;
import org.diylc.core.annotations.EditableProperty; import org.diylc.core.annotations.EditableProperty;
@@ -43,7 +45,7 @@ import org.diylc.core.measures.SizeUnit;
creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "X", creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "X",
description = "Radial crystal oscillator", zOrder = IDIYComponent.COMPONENT, description = "Radial crystal oscillator", zOrder = IDIYComponent.COMPONENT,
transformer = SimpleComponentTransformer.class) transformer = SimpleComponentTransformer.class)
public class CrystalOscillator extends AbstractLeadedComponent<Frequency> implements IGerberComponentSimple { public class CrystalOscillator extends AbstractLeadedComponent<Frequency> implements IGerberComponentSimple, IBoardSideComponent {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -59,6 +61,7 @@ public class CrystalOscillator extends AbstractLeadedComponent<Frequency> implem
private Size pinSpacing = PIN_SPACING; private Size pinSpacing = PIN_SPACING;
private Frequency value; private Frequency value;
private PCBLayer boardSide;
public CrystalOscillator() { public CrystalOscillator() {
super(); super();
@@ -133,4 +136,14 @@ public class CrystalOscillator extends AbstractLeadedComponent<Frequency> implem
protected Size getDefaultWidth() { protected Size getDefaultWidth() {
return DEFAULT_WIDTH; return DEFAULT_WIDTH;
} }
@EditableProperty(name = "Board Side")
@Override
public PCBLayer getBoardSide() {
return boardSide == null ? PCBLayer._2 : boardSide;
}
public void setBoardSide(PCBLayer boardSide) {
this.boardSide = boardSide;
}
} }
@@ -36,9 +36,11 @@ import java.awt.geom.Rectangle2D;
import org.diylc.appframework.miscutils.ConfigurationManager; import org.diylc.appframework.miscutils.ConfigurationManager;
import org.diylc.common.IPlugInPort; import org.diylc.common.IPlugInPort;
import org.diylc.common.ObjectCache; import org.diylc.common.ObjectCache;
import org.diylc.common.PCBLayer;
import org.diylc.components.AbstractLeadedComponent; import org.diylc.components.AbstractLeadedComponent;
import org.diylc.components.transform.SimpleComponentTransformer; import org.diylc.components.transform.SimpleComponentTransformer;
import org.diylc.core.CreationMethod; import org.diylc.core.CreationMethod;
import org.diylc.core.IBoardSideComponent;
import org.diylc.core.IDIYComponent; import org.diylc.core.IDIYComponent;
import org.diylc.core.IDatasheetSupport; import org.diylc.core.IDatasheetSupport;
import org.diylc.core.annotations.AiNote; import org.diylc.core.annotations.AiNote;
@@ -63,7 +65,7 @@ import org.diylc.utils.Constants;
zOrder = IDIYComponent.COMPONENT, transformer = SimpleComponentTransformer.class, enableCache = true, zOrder = IDIYComponent.COMPONENT, transformer = SimpleComponentTransformer.class, enableCache = true,
enableDatasheet = true, datasheetCreationStepCount = 2, datasheetModelColumn = 1) enableDatasheet = true, datasheetCreationStepCount = 2, datasheetModelColumn = 1)
public class HeatSinkResistor extends AbstractLeadedComponent<Resistance> public class HeatSinkResistor extends AbstractLeadedComponent<Resistance>
implements IGerberComponentSimple, IDatasheetSupport { implements IGerberComponentSimple, IDatasheetSupport, IBoardSideComponent {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -101,6 +103,7 @@ public class HeatSinkResistor extends AbstractLeadedComponent<Resistance>
* Top/bottom lip thickness; main body height = A − 2 × lip = D (HS25: A=28, D=14 → lip 7 mm each). * Top/bottom lip thickness; main body height = A − 2 × lip = D (HS25: A=28, D=14 → lip 7 mm each).
*/ */
private Size lipSize = DEFAULT_LIP_SIZE; private Size lipSize = DEFAULT_LIP_SIZE;
private PCBLayer boardSide;
public HeatSinkResistor() { public HeatSinkResistor() {
super(); super();
@@ -544,6 +547,16 @@ public class HeatSinkResistor extends AbstractLeadedComponent<Resistance>
g2d.draw(a); g2d.draw(a);
} }
@EditableProperty(name = "Board Side")
@Override
public PCBLayer getBoardSide() {
return boardSide == null ? PCBLayer._2 : boardSide;
}
public void setBoardSide(PCBLayer boardSide) {
this.boardSide = boardSide;
}
public enum MountingHoleCount { public enum MountingHoleCount {
TWO_DIAGONAL("2 diagonal"), TWO_DIAGONAL("2 diagonal"),
FOUR("4 holes"), FOUR("4 holes"),
@@ -32,10 +32,12 @@ import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D; import java.awt.geom.RoundRectangle2D;
import org.diylc.common.ObjectCache; import org.diylc.common.ObjectCache;
import org.diylc.common.PCBLayer;
import org.diylc.common.ResistorColorCode; import org.diylc.common.ResistorColorCode;
import org.diylc.components.AbstractLeadedComponent; import org.diylc.components.AbstractLeadedComponent;
import org.diylc.components.transform.SimpleComponentTransformer; import org.diylc.components.transform.SimpleComponentTransformer;
import org.diylc.core.CreationMethod; import org.diylc.core.CreationMethod;
import org.diylc.core.IBoardSideComponent;
import org.diylc.core.IDIYComponent; import org.diylc.core.IDIYComponent;
import org.diylc.core.IDatasheetSupport; import org.diylc.core.IDatasheetSupport;
import org.diylc.core.annotations.AiNote; import org.diylc.core.annotations.AiNote;
@@ -55,7 +57,7 @@ import org.diylc.core.measures.SizeUnit;
zOrder = IDIYComponent.COMPONENT, transformer = SimpleComponentTransformer.class, enableCache = true, zOrder = IDIYComponent.COMPONENT, transformer = SimpleComponentTransformer.class, enableCache = true,
enableDatasheet = true, datasheetCreationStepCount = 2) enableDatasheet = true, datasheetCreationStepCount = 2)
public class Resistor extends AbstractLeadedComponent<Resistance> public class Resistor extends AbstractLeadedComponent<Resistance>
implements IGerberComponentSimple, IDatasheetSupport { implements IGerberComponentSimple, IDatasheetSupport, IBoardSideComponent {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -72,6 +74,7 @@ public class Resistor extends AbstractLeadedComponent<Resistance>
private org.diylc.core.measures.Power powerNew = null; private org.diylc.core.measures.Power powerNew = null;
private ResistorColorCode colorCode = ResistorColorCode._5_BAND; private ResistorColorCode colorCode = ResistorColorCode._5_BAND;
private ResistorShape shape = ResistorShape.Standard; private ResistorShape shape = ResistorShape.Standard;
private PCBLayer boardSide;
public Resistor() { public Resistor() {
super(); super();
@@ -263,6 +266,16 @@ public class Resistor extends AbstractLeadedComponent<Resistance>
return super.getFlipStanding(); return super.getFlipStanding();
} }
@EditableProperty(name = "Board Side")
@Override
public PCBLayer getBoardSide() {
return boardSide == null ? PCBLayer._2 : boardSide;
}
public void setBoardSide(PCBLayer boardSide) {
this.boardSide = boardSide;
}
public enum ResistorShape { public enum ResistorShape {
Tubular, Tubular_Beveled, Standard; Tubular, Tubular_Beveled, Standard;
@@ -28,9 +28,11 @@ import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D; import java.awt.geom.RoundRectangle2D;
import org.diylc.common.ObjectCache; import org.diylc.common.ObjectCache;
import org.diylc.common.PCBLayer;
import org.diylc.components.AbstractLeadedComponent; import org.diylc.components.AbstractLeadedComponent;
import org.diylc.components.transform.SimpleComponentTransformer; import org.diylc.components.transform.SimpleComponentTransformer;
import org.diylc.core.CreationMethod; import org.diylc.core.CreationMethod;
import org.diylc.core.IBoardSideComponent;
import org.diylc.core.IDIYComponent; import org.diylc.core.IDIYComponent;
import org.diylc.core.annotations.ComponentDescriptor; import org.diylc.core.annotations.ComponentDescriptor;
import org.diylc.core.annotations.EditableProperty; import org.diylc.core.annotations.EditableProperty;
@@ -45,7 +47,7 @@ import org.diylc.core.measures.SizeUnit;
creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "L", creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "L",
description = "Ferrite core toroidal inductor mounted vertically", zOrder = IDIYComponent.COMPONENT, description = "Ferrite core toroidal inductor mounted vertically", zOrder = IDIYComponent.COMPONENT,
transformer = SimpleComponentTransformer.class) transformer = SimpleComponentTransformer.class)
public class ToroidalInductor extends AbstractLeadedComponent<Inductance> implements IGerberComponentSimple { public class ToroidalInductor extends AbstractLeadedComponent<Inductance> implements IGerberComponentSimple, IBoardSideComponent {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -59,6 +61,7 @@ public class ToroidalInductor extends AbstractLeadedComponent<Inductance> implem
private Inductance value = null; private Inductance value = null;
private Resistance resistance = null; private Resistance resistance = null;
private PCBLayer boardSide;
public ToroidalInductor() { public ToroidalInductor() {
super(); super();
@@ -165,4 +168,14 @@ public class ToroidalInductor extends AbstractLeadedComponent<Inductance> implem
public void setResistance(Resistance resistance) { public void setResistance(Resistance resistance) {
this.resistance = resistance; this.resistance = resistance;
} }
@EditableProperty(name = "Board Side")
@Override
public PCBLayer getBoardSide() {
return boardSide == null ? PCBLayer._2 : boardSide;
}
public void setBoardSide(PCBLayer boardSide) {
this.boardSide = boardSide;
}
} }
@@ -39,11 +39,13 @@ import org.diylc.common.HorizontalAlignment;
import org.diylc.common.IPlugInPort; import org.diylc.common.IPlugInPort;
import org.diylc.common.ObjectCache; import org.diylc.common.ObjectCache;
import org.diylc.common.Orientation; import org.diylc.common.Orientation;
import org.diylc.common.PCBLayer;
import org.diylc.common.VerticalAlignment; import org.diylc.common.VerticalAlignment;
import org.diylc.components.AbstractLabeledComponent; import org.diylc.components.AbstractLabeledComponent;
import org.diylc.components.AbstractMakerBoard; import org.diylc.components.AbstractMakerBoard;
import org.diylc.components.transform.DIL_ICTransformer; import org.diylc.components.transform.DIL_ICTransformer;
import org.diylc.core.ComponentState; import org.diylc.core.ComponentState;
import org.diylc.core.IBoardSideComponent;
import org.diylc.core.IDIYComponent; import org.diylc.core.IDIYComponent;
import org.diylc.core.IDatasheetSupport; import org.diylc.core.IDatasheetSupport;
import org.diylc.core.IDrawingObserver; import org.diylc.core.IDrawingObserver;
@@ -69,7 +71,7 @@ import org.diylc.utils.Constants;
transformer = DIL_ICTransformer.class, enableCache = true, enableDatasheet = true, transformer = DIL_ICTransformer.class, enableCache = true, enableDatasheet = true,
datasheetCreationStepCount = 2, datasheetModelColumn = 1) datasheetCreationStepCount = 2, datasheetModelColumn = 1)
public class DIL_IC extends AbstractLabeledComponent<String> public class DIL_IC extends AbstractLabeledComponent<String>
implements IGerberComponentSimple, IDatasheetSupport { implements IGerberComponentSimple, IDatasheetSupport, IBoardSideComponent {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -97,6 +99,7 @@ public class DIL_IC extends AbstractLabeledComponent<String>
private Color indentColor = INDENT_COLOR; private Color indentColor = INDENT_COLOR;
private DisplayNumbers displayNumbers = DISPLAY_NUMBERS; private DisplayNumbers displayNumbers = DISPLAY_NUMBERS;
private String pinNames = null; private String pinNames = null;
private PCBLayer boardSide;
// new Point(0, pinSpacing.convertToPixels()), // new Point(0, pinSpacing.convertToPixels()),
// new Point(0, 2 * pinSpacing.convertToPixels()), // new Point(0, 2 * pinSpacing.convertToPixels()),
// new Point(0, 3 * pinSpacing.convertToPixels()), // new Point(0, 3 * pinSpacing.convertToPixels()),
@@ -695,6 +698,16 @@ public class DIL_IC extends AbstractLabeledComponent<String>
return name == null ? Integer.toString(pinNumber) : name; return name == null ? Integer.toString(pinNumber) : name;
} }
@EditableProperty(name = "Board Side")
@Override
public PCBLayer getBoardSide() {
return boardSide == null ? PCBLayer._2 : boardSide;
}
public void setBoardSide(PCBLayer boardSide) {
this.boardSide = boardSide;
}
public static enum PinCount { public static enum PinCount {
_4, _6, _8, _10, _12, _14, _16, _18, _20, _22, _24, _26, _28, _30, _32, _34, _36, _38, _40, _42, _44, _46, _48, _50; _4, _6, _8, _10, _12, _14, _16, _18, _20, _22, _24, _26, _28, _30, _32, _34, _36, _38, _40, _42, _44, _46, _48, _50;
@@ -28,9 +28,11 @@ import java.awt.geom.Rectangle2D;
import org.diylc.appframework.miscutils.ConfigurationManager; import org.diylc.appframework.miscutils.ConfigurationManager;
import org.diylc.common.IPlugInPort; import org.diylc.common.IPlugInPort;
import org.diylc.common.PCBLayer;
import org.diylc.components.AbstractLeadedComponent; import org.diylc.components.AbstractLeadedComponent;
import org.diylc.components.transform.SimpleComponentTransformer; import org.diylc.components.transform.SimpleComponentTransformer;
import org.diylc.core.CreationMethod; import org.diylc.core.CreationMethod;
import org.diylc.core.IBoardSideComponent;
import org.diylc.core.IDatasheetSupport; import org.diylc.core.IDatasheetSupport;
import org.diylc.core.IDIYComponent; import org.diylc.core.IDIYComponent;
import org.diylc.core.Theme; import org.diylc.core.Theme;
@@ -51,7 +53,7 @@ import org.diylc.utils.Constants;
transformer = SimpleComponentTransformer.class, enableCache = true, enableDatasheet = true, transformer = SimpleComponentTransformer.class, enableCache = true, enableDatasheet = true,
datasheetCreationStepCount = 2, datasheetModelColumn = 1) datasheetCreationStepCount = 2, datasheetModelColumn = 1)
public class DiodeGlass extends AbstractLeadedComponent<String> public class DiodeGlass extends AbstractLeadedComponent<String>
implements IGerberComponentSimple, IDatasheetSupport { implements IGerberComponentSimple, IDatasheetSupport, IBoardSideComponent {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -67,6 +69,7 @@ public class DiodeGlass extends AbstractLeadedComponent<String>
private String value = ""; private String value = "";
private Color markerColor = MARKER_COLOR; private Color markerColor = MARKER_COLOR;
private Color insideColor = INSIDE_COLOR; private Color insideColor = INSIDE_COLOR;
private PCBLayer boardSide;
public DiodeGlass() { public DiodeGlass() {
super(); super();
@@ -204,4 +207,14 @@ public class DiodeGlass extends AbstractLeadedComponent<String>
public void setInsideColor(Color insideColor) { public void setInsideColor(Color insideColor) {
this.insideColor = insideColor; this.insideColor = insideColor;
} }
@EditableProperty(name = "Board Side")
@Override
public PCBLayer getBoardSide() {
return boardSide == null ? PCBLayer._2 : boardSide;
}
public void setBoardSide(PCBLayer boardSide) {
this.boardSide = boardSide;
}
} }
@@ -28,9 +28,11 @@ import java.awt.geom.Rectangle2D;
import org.diylc.appframework.miscutils.ConfigurationManager; import org.diylc.appframework.miscutils.ConfigurationManager;
import org.diylc.common.IPlugInPort; import org.diylc.common.IPlugInPort;
import org.diylc.common.PCBLayer;
import org.diylc.components.AbstractLeadedComponent; import org.diylc.components.AbstractLeadedComponent;
import org.diylc.components.transform.SimpleComponentTransformer; import org.diylc.components.transform.SimpleComponentTransformer;
import org.diylc.core.CreationMethod; import org.diylc.core.CreationMethod;
import org.diylc.core.IBoardSideComponent;
import org.diylc.core.IDatasheetSupport; import org.diylc.core.IDatasheetSupport;
import org.diylc.core.IDIYComponent; import org.diylc.core.IDIYComponent;
import org.diylc.core.Theme; import org.diylc.core.Theme;
@@ -51,7 +53,7 @@ import org.diylc.utils.Constants;
transformer = SimpleComponentTransformer.class, enableCache = true, enableDatasheet = true, transformer = SimpleComponentTransformer.class, enableCache = true, enableDatasheet = true,
datasheetCreationStepCount = 2, datasheetModelColumn = 1) datasheetCreationStepCount = 2, datasheetModelColumn = 1)
public class DiodePlastic extends AbstractLeadedComponent<String> public class DiodePlastic extends AbstractLeadedComponent<String>
implements IGerberComponentSimple, IDatasheetSupport { implements IGerberComponentSimple, IDatasheetSupport, IBoardSideComponent {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -65,6 +67,7 @@ public class DiodePlastic extends AbstractLeadedComponent<String>
private String value = ""; private String value = "";
private Color markerColor = MARKER_COLOR; private Color markerColor = MARKER_COLOR;
private PCBLayer boardSide;
public DiodePlastic() { public DiodePlastic() {
super(); super();
@@ -178,4 +181,14 @@ public class DiodePlastic extends AbstractLeadedComponent<String>
public void setMarkerColor(Color markerColor) { public void setMarkerColor(Color markerColor) {
this.markerColor = markerColor; this.markerColor = markerColor;
} }
@EditableProperty(name = "Board Side")
@Override
public PCBLayer getBoardSide() {
return boardSide == null ? PCBLayer._2 : boardSide;
}
public void setBoardSide(PCBLayer boardSide) {
this.boardSide = boardSide;
}
} }
@@ -40,6 +40,7 @@ import org.diylc.components.AbstractMakerBoard;
import org.diylc.components.AbstractTransparentComponent; import org.diylc.components.AbstractTransparentComponent;
import org.diylc.components.transform.SIL_ICTransformer; import org.diylc.components.transform.SIL_ICTransformer;
import org.diylc.core.ComponentState; import org.diylc.core.ComponentState;
import org.diylc.core.IBoardSideComponent;
import org.diylc.core.IDIYComponent; import org.diylc.core.IDIYComponent;
import org.diylc.core.IDatasheetSupport; import org.diylc.core.IDatasheetSupport;
import org.diylc.core.IDrawingObserver; import org.diylc.core.IDrawingObserver;
@@ -65,7 +66,7 @@ import org.diylc.utils.Constants;
enableCache = true, enableDatasheet = true, datasheetCreationStepCount = 2, enableCache = true, enableDatasheet = true, datasheetCreationStepCount = 2,
datasheetModelColumn = 1) datasheetModelColumn = 1)
public class SIL_IC extends AbstractTransparentComponent<String> public class SIL_IC extends AbstractTransparentComponent<String>
implements IGerberComponentSimple, IDatasheetSupport { implements IGerberComponentSimple, IDatasheetSupport, IBoardSideComponent {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -90,6 +91,7 @@ public class SIL_IC extends AbstractTransparentComponent<String>
private Color indentColor = INDENT_COLOR; private Color indentColor = INDENT_COLOR;
private String pinNames = null; private String pinNames = null;
private PinLabels pinLabels = null; private PinLabels pinLabels = null;
private PCBLayer boardSide;
// new Point(0, pinSpacing.convertToPixels()), // new Point(0, pinSpacing.convertToPixels()),
// new Point(0, 2 * pinSpacing.convertToPixels()), // new Point(0, 2 * pinSpacing.convertToPixels()),
// new Point(0, 3 * pinSpacing.convertToPixels()), // new Point(0, 3 * pinSpacing.convertToPixels()),
@@ -553,6 +555,16 @@ public class SIL_IC extends AbstractTransparentComponent<String>
return new Rectangle2D.Double(minX - margin, minY - margin, maxX - minX + 2 * margin, maxY - minY + 2 * margin); return new Rectangle2D.Double(minX - margin, minY - margin, maxX - minX + 2 * margin, maxY - minY + 2 * margin);
} }
@EditableProperty(name = "Board Side")
@Override
public PCBLayer getBoardSide() {
return boardSide == null ? PCBLayer._2 : boardSide;
}
public void setBoardSide(PCBLayer boardSide) {
this.boardSide = boardSide;
}
public static enum PinCount { public static enum PinCount {
_2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20; _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20;
@@ -37,9 +37,11 @@ import org.diylc.appframework.miscutils.ConfigurationManager;
import org.diylc.common.IPlugInPort; import org.diylc.common.IPlugInPort;
import org.diylc.common.ObjectCache; import org.diylc.common.ObjectCache;
import org.diylc.common.PCBLayer;
import org.diylc.common.Percentage; import org.diylc.common.Percentage;
import org.diylc.components.transform.TO1Transformer; import org.diylc.components.transform.TO1Transformer;
import org.diylc.core.ComponentState; import org.diylc.core.ComponentState;
import org.diylc.core.IBoardSideComponent;
import org.diylc.core.IDIYComponent; import org.diylc.core.IDIYComponent;
import org.diylc.core.IDrawingObserver; import org.diylc.core.IDrawingObserver;
import org.diylc.core.Project; import org.diylc.core.Project;
@@ -60,7 +62,7 @@ import org.diylc.utils.Constants;
zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, transformer = TO1Transformer.class, zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, transformer = TO1Transformer.class,
enableCache = true, enableDatasheet = true, datasheetCreationStepCount = 2, enableCache = true, enableDatasheet = true, datasheetCreationStepCount = 2,
datasheetModelColumn = 1) datasheetModelColumn = 1)
public class TransistorTO1 extends AbstractTransistorPackage { public class TransistorTO1 extends AbstractTransistorPackage implements IBoardSideComponent {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -77,6 +79,7 @@ public class TransistorTO1 extends AbstractTransistorPackage {
private Size pinSpacing = PIN_SPACING; private Size pinSpacing = PIN_SPACING;
private Boolean flange = true; private Boolean flange = true;
private PCBLayer boardSide;
public TransistorTO1() { public TransistorTO1() {
super(); super();
@@ -329,4 +332,14 @@ public class TransistorTO1 extends AbstractTransistorPackage {
protected boolean flipPinoutLabel() { protected boolean flipPinoutLabel() {
return true; return true;
} }
@EditableProperty(name = "Board Side")
@Override
public PCBLayer getBoardSide() {
return boardSide == null ? PCBLayer._2 : boardSide;
}
public void setBoardSide(PCBLayer boardSide) {
this.boardSide = boardSide;
}
} }
@@ -37,9 +37,11 @@ import org.diylc.appframework.miscutils.ConfigurationManager;
import org.diylc.common.IPlugInPort; import org.diylc.common.IPlugInPort;
import org.diylc.common.ObjectCache; import org.diylc.common.ObjectCache;
import org.diylc.common.PCBLayer;
import org.diylc.common.Percentage; import org.diylc.common.Percentage;
import org.diylc.components.transform.TO220Transformer; import org.diylc.components.transform.TO220Transformer;
import org.diylc.core.ComponentState; import org.diylc.core.ComponentState;
import org.diylc.core.IBoardSideComponent;
import org.diylc.core.IDIYComponent; import org.diylc.core.IDIYComponent;
import org.diylc.core.IDrawingObserver; import org.diylc.core.IDrawingObserver;
import org.diylc.core.Project; import org.diylc.core.Project;
@@ -60,7 +62,7 @@ import org.diylc.utils.Constants;
zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, transformer = TO220Transformer.class, zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, transformer = TO220Transformer.class,
enableCache = true, enableDatasheet = true, datasheetCreationStepCount = 2, enableCache = true, enableDatasheet = true, datasheetCreationStepCount = 2,
datasheetModelColumn = 1) datasheetModelColumn = 1)
public class TransistorTO220 extends AbstractTransistorPackage { public class TransistorTO220 extends AbstractTransistorPackage implements IBoardSideComponent {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -83,6 +85,7 @@ public class TransistorTO220 extends AbstractTransistorPackage {
private Color tabColor = TAB_COLOR; private Color tabColor = TAB_COLOR;
private Color tabBorderColor = TAB_BORDER_COLOR; private Color tabBorderColor = TAB_BORDER_COLOR;
private Size leadLength = LEAD_LENGTH; private Size leadLength = LEAD_LENGTH;
private PCBLayer boardSide;
public TransistorTO220() { public TransistorTO220() {
super(); super();
@@ -437,4 +440,14 @@ public class TransistorTO220 extends AbstractTransistorPackage {
protected boolean flipPinoutLabel() { protected boolean flipPinoutLabel() {
return true; return true;
} }
@EditableProperty(name = "Board Side")
@Override
public PCBLayer getBoardSide() {
return boardSide == null ? PCBLayer._2 : boardSide;
}
public void setBoardSide(PCBLayer boardSide) {
this.boardSide = boardSide;
}
} }
@@ -36,9 +36,11 @@ import org.diylc.appframework.miscutils.ConfigurationManager;
import org.diylc.common.IPlugInPort; import org.diylc.common.IPlugInPort;
import org.diylc.common.ObjectCache; import org.diylc.common.ObjectCache;
import org.diylc.common.PCBLayer;
import org.diylc.common.Percentage; import org.diylc.common.Percentage;
import org.diylc.components.transform.TO92Transformer; import org.diylc.components.transform.TO92Transformer;
import org.diylc.core.ComponentState; import org.diylc.core.ComponentState;
import org.diylc.core.IBoardSideComponent;
import org.diylc.core.IDIYComponent; import org.diylc.core.IDIYComponent;
import org.diylc.core.IDrawingObserver; import org.diylc.core.IDrawingObserver;
import org.diylc.core.Project; import org.diylc.core.Project;
@@ -60,7 +62,7 @@ import org.diylc.utils.Constants;
zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, transformer = TO92Transformer.class, zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, transformer = TO92Transformer.class,
enableCache = true, enableDatasheet = true, datasheetCreationStepCount = 2, enableCache = true, enableDatasheet = true, datasheetCreationStepCount = 2,
datasheetModelColumn = 1) datasheetModelColumn = 1)
public class TransistorTO92 extends AbstractTransistorPackage { public class TransistorTO92 extends AbstractTransistorPackage implements IBoardSideComponent {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -72,6 +74,7 @@ public class TransistorTO92 extends AbstractTransistorPackage {
public static Size BODY_DIAMETER = new Size(0.2d, SizeUnit.in); public static Size BODY_DIAMETER = new Size(0.2d, SizeUnit.in);
private Size pinSpacing = PIN_SPACING; private Size pinSpacing = PIN_SPACING;
private PCBLayer boardSide;
public TransistorTO92() { public TransistorTO92() {
super(); super();
@@ -285,4 +288,14 @@ public class TransistorTO92 extends AbstractTransistorPackage {
g2d.fillOval(width / 2 - pinSize / 2, (height / 4) * (i + 1), pinSize, pinSize); g2d.fillOval(width / 2 - pinSize / 2, (height / 4) * (i + 1), pinSize, pinSize);
} }
} }
@EditableProperty(name = "Board Side")
@Override
public PCBLayer getBoardSide() {
return boardSide == null ? PCBLayer._2 : boardSide;
}
public void setBoardSide(PCBLayer boardSide) {
this.boardSide = boardSide;
}
} }
@@ -37,8 +37,10 @@ import org.diylc.common.Display;
import org.diylc.common.IPlugInPort; import org.diylc.common.IPlugInPort;
import org.diylc.common.ObjectCache; import org.diylc.common.ObjectCache;
import org.diylc.common.Orientation; import org.diylc.common.Orientation;
import org.diylc.common.PCBLayer;
import org.diylc.components.AbstractLabeledComponent; import org.diylc.components.AbstractLabeledComponent;
import org.diylc.core.ComponentState; import org.diylc.core.ComponentState;
import org.diylc.core.IBoardSideComponent;
import org.diylc.core.IDrawingObserver; import org.diylc.core.IDrawingObserver;
import org.diylc.core.Project; import org.diylc.core.Project;
import org.diylc.core.Theme; import org.diylc.core.Theme;
@@ -49,7 +51,7 @@ import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit; import org.diylc.core.measures.SizeUnit;
import org.diylc.utils.Constants; import org.diylc.utils.Constants;
public abstract class PassiveSMDComponent<T> extends AbstractLabeledComponent<T> implements IGerberComponentSimple { public abstract class PassiveSMDComponent<T> extends AbstractLabeledComponent<T> implements IGerberComponentSimple, IBoardSideComponent {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -68,6 +70,7 @@ public abstract class PassiveSMDComponent<T> extends AbstractLabeledComponent<T>
protected Color bodyColor; protected Color bodyColor;
protected Color borderColor; protected Color borderColor;
private Color labelColor = LABEL_COLOR; private Color labelColor = LABEL_COLOR;
private PCBLayer boardSide;
transient private Area[] body; transient private Area[] body;
public PassiveSMDComponent() { public PassiveSMDComponent() {
@@ -413,6 +416,16 @@ public abstract class PassiveSMDComponent<T> extends AbstractLabeledComponent<T>
return false; return false;
} }
@EditableProperty(name = "Board Side")
@Override
public PCBLayer getBoardSide() {
return boardSide == null ? PCBLayer._2 : boardSide;
}
public void setBoardSide(PCBLayer boardSide) {
this.boardSide = boardSide;
}
public static enum SMDSize { public static enum SMDSize {
_0805(new Size(0.05d, SizeUnit.in), new Size(0.08d, SizeUnit.in)), _1206(new Size(1.6d, SizeUnit.mm), new Size(3.2d, _0805(new Size(0.05d, SizeUnit.in), new Size(0.08d, SizeUnit.in)), _1206(new Size(1.6d, SizeUnit.mm), new Size(3.2d,
@@ -0,0 +1,80 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2025 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.components;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import org.diylc.common.ComponentType;
import org.diylc.common.PCBLayer;
import org.diylc.core.IBoardSideComponent;
import org.diylc.core.IDIYComponent;
import org.diylc.presenter.ComponentProcessor;
import org.diylc.utils.ReflectionUtils;
import org.junit.Test;
public class BoardSideComponentsTest {
@Test
public void testBoardSideComponentsStartOnTop() throws Exception {
for (IDIYComponent<?> component : createBoardSideComponents()) {
assertEquals(component.getClass().getName(), PCBLayer._2,
((IBoardSideComponent) component).getBoardSide());
}
}
@Test
public void testBoardSideCanBeChanged() throws Exception {
for (IDIYComponent<?> component : createBoardSideComponents()) {
component.getClass().getMethod("setBoardSide", PCBLayer.class).invoke(component, PCBLayer._1);
assertEquals(component.getClass().getName(), PCBLayer._1,
((IBoardSideComponent) component).getBoardSide());
}
}
// a part moved to the bottom is seen mirrored from the top, so it must be possible to mirror it
@Test
public void testBoardSideComponentsCanBeMirrored() throws Exception {
for (IDIYComponent<?> component : createBoardSideComponents()) {
@SuppressWarnings("unchecked")
ComponentType type = ComponentProcessor.getInstance().extractComponentTypeFrom(
(Class<? extends IDIYComponent<?>>) component.getClass());
assertTrue(component.getClass().getName(), type.getTransformer().canMirror(component));
}
}
private static List<IDIYComponent<?>> createBoardSideComponents() throws Exception {
List<IDIYComponent<?>> components = new ArrayList<IDIYComponent<?>>();
for (Class<?> type : ReflectionUtils.getIndexedClasses(IDIYComponent.class)) {
if (IBoardSideComponent.class.isAssignableFrom(type)
&& !Modifier.isAbstract(type.getModifiers())) {
components.add((IDIYComponent<?>) type.getDeclaredConstructor().newInstance());
}
}
assertTrue(components.size() > 0);
return components;
}
}
@@ -733,3 +733,4 @@ Value Notation|Wertnotation
Decimal (4.7K, 0.22uF, 6.3V)|Dezimal (4.7K, 0.22uF, 6.3V) Decimal (4.7K, 0.22uF, 6.3V)|Dezimal (4.7K, 0.22uF, 6.3V)
RKM (4K7, 0u22, 6V3)|RKM (4K7, 0u22, 6V3) RKM (4K7, 0u22, 6V3)|RKM (4K7, 0u22, 6V3)
Fade Copper Under Board|Kupfer unter der Platine abblenden Fade Copper Under Board|Kupfer unter der Platine abblenden
Board Side|Platinenseite
@@ -726,3 +726,4 @@ Value Notation
Decimal (4.7K, 0.22uF, 6.3V) Decimal (4.7K, 0.22uF, 6.3V)
RKM (4K7, 0u22, 6V3) RKM (4K7, 0u22, 6V3)
Fade Copper Under Board Fade Copper Under Board
Board Side
@@ -729,3 +729,4 @@ Value Notation|Notación de valores
Decimal (4.7K, 0.22uF, 6.3V)|Decimal (4.7K, 0.22uF, 6.3V) Decimal (4.7K, 0.22uF, 6.3V)|Decimal (4.7K, 0.22uF, 6.3V)
RKM (4K7, 0u22, 6V3)|RKM (4K7, 0u22, 6V3) RKM (4K7, 0u22, 6V3)|RKM (4K7, 0u22, 6V3)
Fade Copper Under Board|Atenuar cobre bajo la placa Fade Copper Under Board|Atenuar cobre bajo la placa
Board Side|Lado de la placa
@@ -728,3 +728,4 @@ Value Notation|Notation des valeurs
Decimal (4.7K, 0.22uF, 6.3V)|Décimale (4.7K, 0.22uF, 6.3V) Decimal (4.7K, 0.22uF, 6.3V)|Décimale (4.7K, 0.22uF, 6.3V)
RKM (4K7, 0u22, 6V3)|RKM (4K7, 0u22, 6V3) RKM (4K7, 0u22, 6V3)|RKM (4K7, 0u22, 6V3)
Fade Copper Under Board|Estomper le cuivre sous la carte Fade Copper Under Board|Estomper le cuivre sous la carte
Board Side|Côté de la carte
@@ -730,3 +730,4 @@ Value Notation|Notazione dei valori
Decimal (4.7K, 0.22uF, 6.3V)|Decimale (4.7K, 0.22uF, 6.3V) Decimal (4.7K, 0.22uF, 6.3V)|Decimale (4.7K, 0.22uF, 6.3V)
RKM (4K7, 0u22, 6V3)|RKM (4K7, 0u22, 6V3) RKM (4K7, 0u22, 6V3)|RKM (4K7, 0u22, 6V3)
Fade Copper Under Board|Attenua il rame sotto la scheda Fade Copper Under Board|Attenua il rame sotto la scheda
Board Side|Lato della scheda
@@ -734,3 +734,4 @@ Value Notation|Waardenotatie
Decimal (4.7K, 0.22uF, 6.3V)|Decimaal (4.7K, 0.22uF, 6.3V) Decimal (4.7K, 0.22uF, 6.3V)|Decimaal (4.7K, 0.22uF, 6.3V)
RKM (4K7, 0u22, 6V3)|RKM (4K7, 0u22, 6V3) RKM (4K7, 0u22, 6V3)|RKM (4K7, 0u22, 6V3)
Fade Copper Under Board|Koper onder de print vervagen Fade Copper Under Board|Koper onder de print vervagen
Board Side|Printzijde
@@ -729,3 +729,4 @@ Value Notation|Notação de valores
Decimal (4.7K, 0.22uF, 6.3V)|Decimal (4.7K, 0.22uF, 6.3V) Decimal (4.7K, 0.22uF, 6.3V)|Decimal (4.7K, 0.22uF, 6.3V)
RKM (4K7, 0u22, 6V3)|RKM (4K7, 0u22, 6V3) RKM (4K7, 0u22, 6V3)|RKM (4K7, 0u22, 6V3)
Fade Copper Under Board|Esmaecer cobre sob a placa Fade Copper Under Board|Esmaecer cobre sob a placa
Board Side|Lado da placa
@@ -725,3 +725,4 @@ Value Notation|Zapis vrednosti
Decimal (4.7K, 0.22uF, 6.3V)|Decimalni (4.7K, 0.22uF, 6.3V) Decimal (4.7K, 0.22uF, 6.3V)|Decimalni (4.7K, 0.22uF, 6.3V)
RKM (4K7, 0u22, 6V3)|RKM (4K7, 0u22, 6V3) RKM (4K7, 0u22, 6V3)|RKM (4K7, 0u22, 6V3)
Fade Copper Under Board|Prigušen Bakar Ispod Ploče Fade Copper Under Board|Prigušen Bakar Ispod Ploče
Board Side|Strana Ploče
@@ -727,3 +727,4 @@ Value Notation|मान संकेतन
Decimal (4.7K, 0.22uF, 6.3V)|दशमलव (4.7K, 0.22uF, 6.3V) Decimal (4.7K, 0.22uF, 6.3V)|दशमलव (4.7K, 0.22uF, 6.3V)
RKM (4K7, 0u22, 6V3)|RKM (4K7, 0u22, 6V3) RKM (4K7, 0u22, 6V3)|RKM (4K7, 0u22, 6V3)
Fade Copper Under Board|बोर्ड के नीचे तांबा धुंधला करें Fade Copper Under Board|बोर्ड के नीचे तांबा धुंधला करें
Board Side|बोर्ड का पक्ष
@@ -727,3 +727,4 @@ Value Notation|数值表示法
Decimal (4.7K, 0.22uF, 6.3V)|小数 (4.7K, 0.22uF, 6.3V) Decimal (4.7K, 0.22uF, 6.3V)|小数 (4.7K, 0.22uF, 6.3V)
RKM (4K7, 0u22, 6V3)|RKM (4K7, 0u22, 6V3) RKM (4K7, 0u22, 6V3)|RKM (4K7, 0u22, 6V3)
Fade Copper Under Board|淡化板下铜箔 Fade Copper Under Board|淡化板下铜箔
Board Side|板面
+32 -31
View File
@@ -3,9 +3,10 @@
Let a component be mounted on the bottom of a PCB, so that its silkscreen goes to the bottom Let a component be mounted on the bottom of a PCB, so that its silkscreen goes to the bottom
Gerber layers and the canvas shows it as a part on the far side of the board. Gerber layers and the canvas shows it as a part on the far side of the board.
Status: the core Gerber side is done, with tests: `IBoardSideComponent` exists and the export Status: 32 parts have a Board Side property, and Gerber export sends a bottom-side part's
sends a bottom-side part to the bottom layers, but no component implements it yet. Parts can be silkscreen to the bottom layer with its text mirrored. Parts can be selected, dragged and stretched
selected, dragged and stretched through the Underside Display mirror. The next steps below remain. through the Underside Display mirror. The canvas does not show the side yet, and the Flip to Other
Side action does not exist; the next steps below remain.
## 1. Current state ## 1. Current state
@@ -41,6 +42,9 @@ selected, dragged and stretched through the Underside Display mirror. The next s
| Flipping a part is an action that sets the side, mirrors the part and sends it back | A part seen from above through the board is a mirror image. Changing the side without mirroring gives a footprint that is wrong for fabrication. | | Flipping a part is an action that sets the side, mirrors the part and sends it back | A part seen from above through the board is a mirror image. Changing the side without mirroring gives a footprint that is wrong for fabrication. |
| The Gerber layer is swapped centrally, not inside each component | Components keep emitting their `*Top` layer. One place maps it to the other side. | | The Gerber layer is swapped centrally, not inside each component | Components keep emitting their `*Top` layer. One place maps it to the other side. |
| Default `_2` (Top), with `null` meaning Top | Fields added to existing classes deserialize as `null` in old files. | | Default `_2` (Top), with `null` meaning Top | Fields added to existing classes deserialize as `null` in old files. |
| The side is both an editable property and the Flip to Other Side action | The action is the normal way to move a part, because it also mirrors it. The property stays for a part that is already drawn mirrored and only needs its side set. |
| Bottom-side text is mirrored centrally in the Gerber output | Parts draw their labels readable from the top, which is backwards on the bottom silkscreen once the board is turned over. While `GerberExporter.drawComponent` draws a bottom-side part, `GerberG2DWrapper.setMirrorText` mirrors each string about the centre of its layout box, so no component changes and the canvas keeps readable labels. |
| A `SolderPad` opens the solder mask on its own side | It used to write `SolderMaskBot` whatever its layer, which was wrong for top-layer pads. It now writes `SolderMaskTop` for a pad on `_2`. |
## 3. Design ## 3. Design
@@ -52,18 +56,28 @@ selected, dragged and stretched through the Underside Display mirror. The next s
### diylc-library ### diylc-library
- The ~35 classes that use the `SilkscreenTop` default implement `IBoardSideComponent`. Each adds a - **Done.** Every part that uses the `SilkscreenTop` default and whose transformer can mirror it
nullable `PCBLayer boardSide` field and a getter/setter pair, with implements `IBoardSideComponent`: a nullable `PCBLayer boardSide` field and a getter/setter pair
`@EditableProperty(name = "Board Side")` on the getter. The getter returns `_2` (Top) when the with `@EditableProperty(name = "Board Side")` on the getter, which returns `_2` (Top) when the
field is `null`. This duplicates the field across classes in the same way the `PCBLayer` field is field is `null`. The key is in every language file.
duplicated today. Where several of these classes share an abstract base - On a shared base, covering every subclass: `AbstractFilmCapacitor`, `AbstractPotentiometer`,
(`AbstractRadialComponent`, `AbstractFilmCapacitor`, `AbstractTransistorPackage`, ...), put it on `AbstractRadialComponent`, `PassiveSMDComponent`.
the base. - On the class itself: `Resistor`, `HeatSinkResistor`, `AxialElectrolyticCapacitor`,
`CrystalOscillator`, `ToroidalInductor`, `DiodePlastic`, `DiodeGlass`, `DIL_IC`, `SIL_IC`,
`TransistorTO1`, `TransistorTO92`, `TransistorTO220`, `CliffJack1_4`, `CliffJack1_8`,
`ClosedJack1_4`, `MiniToggleSwitch`, `PCBTerminalBlock`. The transistors are not done on
`AbstractTransistorPackage` because `TransistorTO126` cannot be mirrored, and a property on the
base cannot be hidden from one subclass.
- Left out because they cannot be mirrored: `TubeSocket`, `RotarySwitchOpen`,
`RotarySwitchSealed`, `RotarySelectorSwitch`, `SlideSwitch`, `PlasticDCJack`,
`TactileMicroSwitch`, `MiniRelay`, `AudioTransformer`, `MultiSectionCapacitor`, `MultiwattIC`,
`BridgeRectifier`, `TransistorTO126`. Making one of them mirrorable is what it takes to give it
a side.
- `Label` is left out too: it is text, not a mounted part, and `PCBText` already has a layer.
- `BoardSideComponentsTest` checks that every such part starts on Top, takes Bottom, and can be
mirrored.
- `CopperTrace`, `CurvedTrace`, `GroundFill`, `SolderPad`, `PCBText` and `DrillHole` do **not** - `CopperTrace`, `CurvedTrace`, `GroundFill`, `SolderPad`, `PCBText` and `DrillHole` do **not**
implement it. Their `PCBLayer` already says where they are. implement it. Their `PCBLayer` already says where they are.
- Before allowing Bottom on a class, check that its transformer can mirror it
(`canMirror`). A class that cannot be mirrored must not offer Bottom, or the footprint would be
wrong.
### diylc-swing ### diylc-swing
@@ -115,17 +129,6 @@ order.
## 4. Open questions ## 4. Open questions
- **Bottom silkscreen text.** Component labels drawn through `IGerberComponentSimple` have to read
correctly once the board is turned over, which means they must look mirrored from the top. Check
whether mirroring through the transformer does that for every class, or whether labels are drawn
unmirrored regardless. `GerberLayer.mirrored` is currently `false` for every layer, and the
exporter output must stay in top view.
- **SolderPad solder mask.** `SolderPad` always writes its mask opening to `SolderMaskBot`,
whatever its own `PCBLayer`. Confirm whether this is intended for top-layer SMD pads before
`GerberLayer.flip()` is introduced next to it.
- **Plain property or action only.** A plain editable property lets a user change the side without
mirroring. Either keep both (the property for already-mirrored parts) or show the side as
read-only and change it only through the action.
- **Components that belong to no side.** In mirror stage 3 a jumper, eyelet or wire dropped in the - **Components that belong to no side.** In mirror stage 3 a jumper, eyelet or wire dropped in the
mirror has no side to set. Confirm that placing it at the reflected point unchanged is what users mirror has no side to set. Confirm that placing it at the reflected point unchanged is what users
expect, or whether such parts should be refused in the mirror. expect, or whether such parts should be refused in the mirror.
@@ -153,10 +156,8 @@ order.
## 6. Next steps ## 6. Next steps
1. Add the field to the library components, putting it on shared bases where they exist. Settle 1. Wrap bottom-side painting in `startDrawingSide(getBoardSide())`.
the silkscreen-text question while doing so. 2. Add the Flip to Other Side action.
2. Wrap bottom-side painting in `startDrawingSide(getBoardSide())`. 3. Split the silkscreen print-out by side.
3. Add the Flip to Other Side action. 4. Mirror stage 3: placing in the mirror, after Flip to Other Side exists.
4. Split the silkscreen print-out by side. 5. Run the regression suite.
5. Mirror stage 3: placing in the mirror, after Flip to Other Side exists.
6. Run the regression suite.