mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-13 10:42:09 +10:00
Gerber export writes drill files in Excellon format, picked by a constant in GerberExporter, through gerber-writer 1.2.0; a Drill Hole no longer adds its outline and crosshair to the drill file
This commit is contained in:
@@ -97,10 +97,10 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.diylc.local</groupId>
|
||||
<artifactId>gerber-writer-api-1.1.0</artifactId>
|
||||
<artifactId>gerber-writer-api-1.2.0</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${project.basedir}/../lib/gerber-writer-api-1.1.0.jar</systemPath>
|
||||
<systemPath>${project.basedir}/../lib/gerber-writer-api-1.2.0.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.diylc.local</groupId>
|
||||
|
||||
@@ -15,6 +15,7 @@ import java.util.stream.Collectors;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.bancika.gerberwriter.DataLayer;
|
||||
import com.bancika.gerberwriter.DrillFormat;
|
||||
|
||||
import org.diylc.common.PCBLayer;
|
||||
import org.diylc.core.ComponentState;
|
||||
@@ -32,6 +33,9 @@ public class GerberExporter {
|
||||
public static final double OUTLINE_THICKNESS = new Size(0.3d, SizeUnit.mm).convertToPixels();
|
||||
private static final Logger LOG = Logger.getLogger(GerberExporter.class);
|
||||
|
||||
// Excellon is the drill format every fab accepts; Gerber drill files are not read by all of them
|
||||
private static final DrillFormat DRILL_FORMAT = DrillFormat.EXCELLON;
|
||||
|
||||
public static void exportGerber(String fileNameBase, Project currentProject, IView view,
|
||||
Graphics2D graphics2d, String diylcVersion) {
|
||||
|
||||
@@ -137,6 +141,23 @@ public class GerberExporter {
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
g2d.getDrillLayerMap().forEach((layer, drillLayer) -> {
|
||||
try {
|
||||
String fileName = layer.formatFileName(fileNameBase, boardComponent.getName(),
|
||||
DRILL_FORMAT == DrillFormat.EXCELLON ? "drl" : "gbr");
|
||||
LOG.info("Exporting layer: " + layer + " for board " + boardComponent.getName()
|
||||
+ " to file: " + fileName);
|
||||
drillLayer.dumpToFile(fileName, DRILL_FORMAT);
|
||||
generatedFiles.add(fileName);
|
||||
} catch (IOException e) {
|
||||
LOG.error("Error writing drill file: " + e.getMessage());
|
||||
view.showMessage(
|
||||
LangUtil.translate(
|
||||
"Failed to export the project to gerber. Please check the log for details"),
|
||||
LangUtil.translate("Gerber Export"), IView.ERROR_MESSAGE);
|
||||
}
|
||||
});
|
||||
});
|
||||
view.showMessage(
|
||||
String.format(
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.awt.font.GlyphVector;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.BufferedImageOp;
|
||||
@@ -32,6 +33,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.bancika.gerberwriter.DataLayer;
|
||||
import com.bancika.gerberwriter.DrillLayer;
|
||||
import com.bancika.gerberwriter.Point;
|
||||
import com.bancika.gerberwriter.padmasters.Circle;
|
||||
|
||||
@@ -45,6 +47,7 @@ public class GerberG2DWrapper extends Graphics2D
|
||||
private static final double CURVE_APPROXIMATION_TOLERANCE = 1d;
|
||||
|
||||
private Map<GerberLayer, DataLayer> layerMap;
|
||||
private Map<GerberLayer, DrillLayer> drillLayerMap;
|
||||
private boolean trackingGerber = false;
|
||||
private Map<GerberLayer, GerberProperties> currentLayers =
|
||||
new HashMap<GerberLayer, GerberProperties>();
|
||||
@@ -65,6 +68,7 @@ public class GerberG2DWrapper extends Graphics2D
|
||||
this.graphics2d = graphics2d;
|
||||
this.boardRect = boardRect;
|
||||
this.layerMap = new HashMap<GerberLayer, DataLayer>();
|
||||
this.drillLayerMap = new HashMap<GerberLayer, DrillLayer>();
|
||||
this.diylcVersion = diylcVersion;
|
||||
}
|
||||
|
||||
@@ -115,7 +119,11 @@ public class GerberG2DWrapper extends Graphics2D
|
||||
|
||||
@Override
|
||||
public void startGerberOutput(GerberLayer layer, String function, boolean negative) {
|
||||
layerMap.computeIfAbsent(layer, k -> layer.buildLayer(diylcVersion));
|
||||
if (layer.isDrill()) {
|
||||
drillLayerMap.computeIfAbsent(layer, k -> layer.buildDrillLayer(diylcVersion));
|
||||
} else {
|
||||
layerMap.computeIfAbsent(layer, k -> layer.buildLayer(diylcVersion));
|
||||
}
|
||||
currentLayers.put(layer, new GerberProperties(function, negative));
|
||||
trackingGerber = true;
|
||||
}
|
||||
@@ -155,6 +163,10 @@ public class GerberG2DWrapper extends Graphics2D
|
||||
return layerMap;
|
||||
}
|
||||
|
||||
public Map<GerberLayer, DrillLayer> getDrillLayerMap() {
|
||||
return drillLayerMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -168,6 +180,11 @@ public class GerberG2DWrapper extends Graphics2D
|
||||
public void draw(Shape s) {
|
||||
if (trackingGerber && !getColor().equals(Constants.TRANSPARENT_COLOR)) {
|
||||
currentLayers.entrySet().forEach(entry -> {
|
||||
// only round fills are holes; outlines, such as a drill hole marker's border and
|
||||
// crosshair, are not drilled
|
||||
if (entry.getKey().isDrill()) {
|
||||
return;
|
||||
}
|
||||
double width = 1;
|
||||
if (stroke != null && stroke instanceof BasicStroke) {
|
||||
width = ((BasicStroke) stroke).getLineWidth();
|
||||
@@ -222,6 +239,10 @@ public class GerberG2DWrapper extends Graphics2D
|
||||
public void fillShape(Shape s) {
|
||||
if (trackingGerber && !getColor().equals(Constants.TRANSPARENT_COLOR)) {
|
||||
currentLayers.entrySet().forEach(entry -> {
|
||||
// only round fills are holes
|
||||
if (entry.getKey().isDrill()) {
|
||||
return;
|
||||
}
|
||||
DataLayer dataLayer = layerMap.get(entry.getKey());
|
||||
AffineTransform finalTx = getFinalTx(entry.getKey().isMirrored());
|
||||
GerberPathRenderer.outputPathArea(s.getPathIterator(finalTx), dataLayer,
|
||||
@@ -234,6 +255,10 @@ public class GerberG2DWrapper extends Graphics2D
|
||||
private void fillFlash(Ellipse2D c) {
|
||||
if (trackingGerber && !getColor().equals(Constants.TRANSPARENT_COLOR)) {
|
||||
currentLayers.entrySet().forEach(entry -> {
|
||||
if (entry.getKey().isDrill()) {
|
||||
addHole(c, entry.getKey(), entry.getValue().function);
|
||||
return;
|
||||
}
|
||||
DataLayer dataLayer = layerMap.get(entry.getKey());
|
||||
AffineTransform finalTx = getFinalTx(entry.getKey().isMirrored());
|
||||
if (Math.abs(c.getWidth() - c.getHeight()) < 0.1 && finalTx.getShearX() == 0
|
||||
@@ -255,6 +280,17 @@ public class GerberG2DWrapper extends Graphics2D
|
||||
}
|
||||
}
|
||||
|
||||
private void addHole(Ellipse2D c, GerberLayer layer, String function) {
|
||||
AffineTransform finalTx = getFinalTx(layer.isMirrored());
|
||||
Point2D center = finalTx.transform(new Point2D.Double(c.getCenterX(), c.getCenterY()), null);
|
||||
double factor = SizeUnit.px.getFactor();
|
||||
// the drawing transform scales evenly, so the circle stays a circle, scaled by the square root
|
||||
// of the determinant whether or not it is also rotated
|
||||
double diameter = c.getWidth() * Math.sqrt(Math.abs(finalTx.getDeterminant())) * factor;
|
||||
drillLayerMap.get(layer).addHole(new Point(center.getX() * factor, center.getY() * factor),
|
||||
diameter, function);
|
||||
}
|
||||
|
||||
private AffineTransform getFinalTx(boolean isMirrored) {
|
||||
AffineTransform finalTx = new AffineTransform();
|
||||
if (isMirrored) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.diylc.core.gerber;
|
||||
|
||||
import com.bancika.gerberwriter.DataLayer;
|
||||
import com.bancika.gerberwriter.DrillLayer;
|
||||
import com.bancika.gerberwriter.GenerationSoftware;
|
||||
|
||||
public enum GerberLayer {
|
||||
@@ -30,9 +31,18 @@ public enum GerberLayer {
|
||||
}
|
||||
|
||||
public DataLayer buildLayer(String diylcVersion) {
|
||||
GenerationSoftware genSoftware =
|
||||
new GenerationSoftware("bancika", "DIY Layout Creator", diylcVersion);
|
||||
return new DataLayer(function, negative, genSoftware);
|
||||
return new DataLayer(function, negative, createGenerationSoftware(diylcVersion));
|
||||
}
|
||||
|
||||
public DrillLayer buildDrillLayer(String diylcVersion) {
|
||||
return new DrillLayer(this == DrillPlated, createGenerationSoftware(diylcVersion));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true for the drill layers, which hold holes rather than drawn copper or graphics
|
||||
*/
|
||||
public boolean isDrill() {
|
||||
return this == DrillPlated || this == DrillNonPlated;
|
||||
}
|
||||
|
||||
public String getExtension() {
|
||||
@@ -56,7 +66,15 @@ public enum GerberLayer {
|
||||
}
|
||||
|
||||
public String formatFileName(String fileNameBase, String boardName) {
|
||||
return formatFileName(fileNameBase, boardName, getExtension());
|
||||
}
|
||||
|
||||
public String formatFileName(String fileNameBase, String boardName, String extension) {
|
||||
return fileNameBase + (fileNameBase.endsWith(".") ? "" : ".")
|
||||
+ boardName + "-" + getSuffix() + "." + getExtension();
|
||||
+ boardName + "-" + getSuffix() + "." + extension;
|
||||
}
|
||||
|
||||
private static GenerationSoftware createGenerationSoftware(String diylcVersion) {
|
||||
return new GenerationSoftware("bancika", "DIY Layout Creator", diylcVersion);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -673,6 +673,10 @@
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Gerber export no longer cuts the holes of solder pads and vias out of the copper layers; the holes are defined by the drill files alone, as the Gerber specification recommends</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Gerber export writes the drill files in Excellon format, the drill format every PCB fab accepts, instead of Gerber format; a 'Drill Hole' no longer adds its outline and crosshair to the drill file</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>BUG_FIX</changeType>
|
||||
<description>Rotated labels in pasted components and building blocks were drawn in the wrong place and at the wrong angle while following the mouse, until the components were placed</description>
|
||||
|
||||
Reference in New Issue
Block a user