diff --git a/diylc/diylc-core/src/main/resources/update.xml b/diylc/diylc-core/src/main/resources/update.xml index 8b04e3ddc..6944f89c4 100644 --- a/diylc/diylc-core/src/main/resources/update.xml +++ b/diylc/diylc-core/src/main/resources/update.xml @@ -645,6 +645,10 @@ BUG_FIX 'Highlight Connected Areas', netlists and AI analysis could ignore trace cuts after the board under them was moved or edited, or when the cuts were scrolled out of view, and showed the whole strip as connected + + BUG_FIX + 'Solder Pad' on the top layer put its solder mask opening on the bottom layer in Gerber export + https://github.com/bancika/diy-layout-creator/releases diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/SolderPad.java b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/SolderPad.java index f89c18aa0..e254955bc 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/SolderPad.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/SolderPad.java @@ -92,9 +92,12 @@ public class SolderPad extends AbstractTransparentComponent : color); drawingObserver.startTrackingContinuityArea(true); GerberLayer gerberCopperLayer = this.getLayer().toGerberCopperLayer(); + // the mask is opened on the side the pad is on + GerberLayer gerberMaskLayer = gerberCopperLayer == GerberLayer.CopperTop + ? GerberLayer.SolderMaskTop : GerberLayer.SolderMaskBot; if (gerberDrawingObserver != null) { gerberDrawingObserver.startGerberOutput(gerberCopperLayer, GerberFunctions.CONNECTOR_PAD, false); - gerberDrawingObserver.startGerberOutput(org.diylc.core.gerber.GerberLayer.SolderMaskBot, "Material", false); + gerberDrawingObserver.startGerberOutput(gerberMaskLayer, "Material", false); } Composite oldComposite = applyAlpha(g2d, componentState); drawingObserver.startDrawingSide(getLayer()); @@ -115,8 +118,9 @@ public class SolderPad extends AbstractTransparentComponent drawingObserver.stopDrawingSide(); drawingObserver.stopTracking(); drawingObserver.stopTrackingContinuityArea(); - if (gerberDrawingObserver != null) - gerberDrawingObserver.stopGerberOutput(org.diylc.core.gerber.GerberLayer.SolderMaskBot); + if (gerberDrawingObserver != null) { + gerberDrawingObserver.stopGerberOutput(gerberMaskLayer); + } if (getHoleSize().getValue() > 0 && !HoleType.NONE.equals(getHoleType())) { if (gerberDrawingObserver != null) { gerberDrawingObserver.setGerberNegative(gerberCopperLayer, true); diff --git a/diylc/diylc-library/src/test/java/org/diylc/components/connectivity/SolderPadGerberTest.java b/diylc/diylc-library/src/test/java/org/diylc/components/connectivity/SolderPadGerberTest.java new file mode 100644 index 000000000..113a349da --- /dev/null +++ b/diylc/diylc-library/src/test/java/org/diylc/components/connectivity/SolderPadGerberTest.java @@ -0,0 +1,68 @@ +/* + + 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 . + +*/ +package org.diylc.components.connectivity; + +import static org.junit.Assert.assertTrue; + +import java.awt.Graphics2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.util.Set; + +import org.diylc.common.PCBLayer; +import org.diylc.core.ComponentState; +import org.diylc.core.Project; +import org.diylc.core.gerber.GerberG2DWrapper; +import org.diylc.core.gerber.GerberLayer; +import org.junit.Test; + +public class SolderPadGerberTest { + + @Test + public void testTopPadOpensTopMask() { + Set layers = drawGerber(PCBLayer._2); + assertTrue(layers.contains(GerberLayer.CopperTop)); + assertTrue(layers.contains(GerberLayer.SolderMaskTop)); + assertTrue(!layers.contains(GerberLayer.SolderMaskBot)); + } + + @Test + public void testBottomPadOpensBottomMask() { + Set layers = drawGerber(PCBLayer._1); + assertTrue(layers.contains(GerberLayer.CopperBot)); + assertTrue(layers.contains(GerberLayer.SolderMaskBot)); + assertTrue(!layers.contains(GerberLayer.SolderMaskTop)); + } + + private static Set drawGerber(PCBLayer layer) { + SolderPad pad = new SolderPad(); + pad.setLayer(layer); + BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB); + Graphics2D graphics = img.createGraphics(); + GerberG2DWrapper g2d = + new GerberG2DWrapper(graphics, "test", new Rectangle2D.Double(-50, -50, 100, 100)); + g2d.startedDrawingComponent(); + pad.draw(g2d, ComponentState.NORMAL, false, new Project(), g2d, g2d); + graphics.dispose(); + return g2d.getLayerMap().keySet(); + } +}