Compare commits

..

19 Commits

Author SHA1 Message Date
Bane Stojkovic 3c7d3ec45c Merge branch 'master' into feature/multimeter2 2025-03-09 21:26:50 +01:00
Bane Stojkovic def979adf8 Update update.xml 2025-03-09 21:26:31 +01:00
Bane Stojkovic 62ae5011ff Update update.xml 2025-03-09 21:26:10 +01:00
Bane Stojkovic 8a1b3c271e Merge branch 'master' into feature/multimeter2 2025-03-09 21:24:36 +01:00
Bane Stojkovic bd172ec0fd Update .gitignore 2025-03-09 21:23:40 +01:00
Bane Stojkovic b8a2e3a727 Moving selected components with a mouse doesn't register file modification action and doesn't enable Undo action 2025-03-09 21:21:09 +01:00
Bane Stojkovic c067118d77 merge 2025-03-09 12:30:40 +01:00
Bane Stojkovic 9913e7ddb1 Merge branch 'master' into feature/multimeter2 2025-03-09 12:27:22 +01:00
Bane Stojkovic ace11a8d7d Merge branch 'master' into feature/multimeter2 2025-03-07 23:26:52 +01:00
Bane Stojkovic f152167602 Merge branch 'master' into feature/multimeter2 2025-03-07 23:09:39 +01:00
Bane Stojkovic 3838b81612 Merge branch 'master' into feature/multimeter2 2025-03-07 20:54:08 +01:00
Bane Stojkovic e5b7c4ff88 fix 2025-03-05 20:01:07 +01:00
Bane Stojkovic 5f3e290bd0 Merge branch 'feature/multimeter2' of https://github.com/bancika/diy-layout-creator into feature/multimeter2 2025-03-05 19:56:34 +01:00
Bane Stojkovic 9a9c875e8b cleaner switch positions display 2025-03-02 23:04:09 +01:00
Bane Stojkovic 9f8fd634cc Update MultimeterProbe.java 2025-03-02 22:12:23 +01:00
Bane Stojkovic 8d4f6fd46c add icon 2025-03-02 22:11:14 +01:00
Bane Stojkovic b469ab9aa3 cleanup 2025-03-02 16:12:12 +01:00
Bane Stojkovic 1492831678 multimeter analyzer 2025-03-02 09:38:21 +01:00
Bane Stojkovic b997c18558 probe added and multimeter analyzer 2025-03-01 19:08:23 +01:00
28 changed files with 552 additions and 332 deletions
+1
View File
@@ -2,3 +2,4 @@
*.iml
*.eml
/.project
**/.DS_Store
@@ -35,19 +35,9 @@ public enum Orientation {
}
public double toDegrees() {
switch (this) {
case DEFAULT:
return 0;
case _180:
return 180;
case _270:
return 270;
case _90:
return 90;
default:
break;
}
return 0;
if (this == DEFAULT)
return 0;
return Integer.parseInt(name().replace("_", ""));
}
public double toRadians() {
@@ -0,0 +1,46 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 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.common;
public enum Orientation45 {
DEFAULT, _45, _90, _135, _180, _225, _270, _315;
@Override
public String toString() {
if (this == DEFAULT) {
return "Default";
} else {
return name().replace("_", "") + " degrees clockwise";
}
}
public double toDegrees() {
if (this == DEFAULT)
return 0;
return Integer.parseInt(name().replace("_", ""));
}
public double toRadians() {
return Math.toRadians(toDegrees());
}
}
@@ -1,10 +0,0 @@
package org.diylc.core;
public enum BoardUndersideDisplay {
NONE, ABOVE, BELOW, LEFT, RIGHT;
@Override
public String toString() {
return super.toString().charAt(0) + super.toString().substring(1).toLowerCase();
}
}
@@ -1,12 +0,0 @@
package org.diylc.core;
import java.awt.geom.Rectangle2D;
public interface IBoard {
Rectangle2D getBoardRectangle();
BoardUndersideDisplay getBoardUndersideDisplay();
boolean shouldExportToGerber();
}
@@ -14,7 +14,6 @@ import java.util.Set;
import java.util.stream.Collectors;
import org.apache.log4j.Logger;
import org.diylc.core.ComponentState;
import org.diylc.core.IBoard;
import org.diylc.core.IDIYComponent;
import org.diylc.core.IView;
import org.diylc.core.Project;
@@ -30,15 +29,12 @@ public class GerberExporter {
public static void exportGerber(String fileNameBase, Project currentProject, IView view,
Graphics2D graphics2d, String diylcVersion) {
List<IBoard> gerberBoards =
currentProject.getComponents().stream()
.filter(IBoard.class::isInstance)
.map(IBoard.class::cast)
.filter(IBoard::shouldExportToGerber).collect(Collectors.toList());
List<IGerberBoard> gerberBoards =
currentProject.getComponents().stream().filter(c -> c instanceof IGerberBoard)
.map(x -> (IGerberBoard) x).collect(Collectors.toList());
Map<IBoard, List<IDIYComponent<?>>> boardComponentMap =
new HashMap<IBoard, List<IDIYComponent<?>>>();
Map<IGerberBoard, List<IDIYComponent<?>>> boardComponentMap =
new HashMap<IGerberBoard, List<IDIYComponent<?>>>();
// DefaultGerberBoard defaultGerberBoard = new DefaultGerberBoard();
@@ -47,7 +43,7 @@ public class GerberExporter {
currentProject.getComponents().stream().filter(c -> c instanceof IGerberComponent)
.forEach(c -> {
Point2D firstPoint = c.getControlPoint(0);
IBoard board = gerberBoards.stream()
IGerberBoard board = gerberBoards.stream()
.filter(b -> b.getBoardRectangle().contains(firstPoint)).findFirst().orElse(null);
if (board == null) {
componentsWithoutBoard.add(c);
@@ -174,6 +174,7 @@ public class GerberG2DWrapper extends Graphics2D
if (str == null || str.trim().isEmpty()) {
return;
}
GlyphVector gv = font.createGlyphVector(graphics2d.getFontRenderContext(), str);
@@ -0,0 +1,8 @@
package org.diylc.core.gerber;
import java.awt.geom.Rectangle2D;
public interface IGerberBoard {
Rectangle2D getBoardRectangle();
}
@@ -23,6 +23,8 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.diylc.core.IDIYComponent;
public class Netlist implements Comparable<Netlist> {
@@ -58,10 +60,6 @@ public class Netlist implements Comparable<Netlist> {
return switchSetup;
}
public void done() {
Collections.sort(switchSetup);
}
@Override
public int hashCode() {
final int prime = 31;
@@ -86,11 +84,16 @@ public class Netlist implements Comparable<Netlist> {
return false;
return true;
}
public String getSwitchSetupString() {
return getSwitchSetup().isEmpty() ? "[ ALL ]" : "[ " +
getSwitchSetup().stream().map(x -> x.toString()).collect(Collectors.joining(",")) + " ]";
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Switch setup: ").append(getSwitchSetup()).append("\n\n");
sb.append("Switch setup: ").append(getSwitchSetupString()).append("\n\n");
List<Group> list = getSortedGroups();
for (Group g : list) {
sb.append("\t").append(g).append("\n");
@@ -22,6 +22,7 @@ import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -29,6 +30,7 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
import org.apache.log4j.Logger;
import org.diylc.common.ComponentType;
import org.diylc.core.ICommonNode;
@@ -42,6 +44,7 @@ import org.diylc.presenter.ComponentProcessor;
import org.diylc.presenter.Connection;
import org.diylc.presenter.ContinuityArea;
import org.diylc.utils.RTree;
import com.google.common.graph.GraphBuilder;
import com.google.common.graph.ImmutableGraph;
import com.google.common.graph.ImmutableGraph.Builder;
@@ -188,10 +191,29 @@ public class NetlistBuilder {
// sort everything alphabetically
List<Netlist> netlists = new ArrayList<Netlist>(result.keySet());
Collections.sort(netlists);
netlists.forEach(netlist -> cleanupRedundantSwitches(netlist.getSwitchSetup()));
return netlists;
}
public static void cleanupRedundantSwitches(List<SwitchSetup> switchSetups) {
Map<ISwitch, Set<Integer>> positionCountMap = new HashMap<>();
switchSetups.forEach(s -> s.getPositions().forEach(pos -> {
positionCountMap.computeIfAbsent(pos.getSwitch(), k -> new HashSet<Integer>()).add(pos.getPosition());
}));
// find switches that are here in all the positions, meaning that they don't affect the circuit
Set<ISwitch> switchesToPrune = positionCountMap.entrySet().stream()
.filter(e -> e.getKey().getPositionCount() == e.getValue().size())
.map(x -> x.getKey())
.collect(Collectors.toSet());
switchSetups.forEach(s -> s.getPositions().removeIf(x -> switchesToPrune.contains(x.getSwitch())));
switchSetups.removeIf(x -> x.getPositions().isEmpty());
HashSet<SwitchSetup> uniqueSetups = new HashSet<>(switchSetups);
switchSetups.clear();
switchSetups.addAll(uniqueSetups);
switchSetups.sort(Comparator.comparing(x -> x.toString()));
}
public static Netlist buildNetlist(List<IDIYComponent<?>> components, Collection<Node> nodes,
Collection<ContinuityArea> continuityAreas, Collection<Connection> connections) {
ImmutableGraph<ProjectGraphNode> graph = buildGraph(nodes, continuityAreas, connections);
@@ -161,10 +161,10 @@ public class Tree {
}
public String toAsciiString() {
return String.join("<br>", toAscii());
return String.join("<br>", toAsciiLines());
}
private List<String> toAscii() {
private List<String> toAsciiLines() {
if (leaf != null) {
return Arrays.asList(TreeAsciiUtil.generateString(TreeAsciiUtil.BOXH, 1) + " " + leaf.toHTML() + " " + TreeAsciiUtil.generateString(TreeAsciiUtil.BOXH, 1));
}
@@ -172,7 +172,7 @@ public class Tree {
List<Tree> children = getOrderedChildren();
List<List<String>> childrenAscii =
children.stream().map(c -> c.toAscii()).collect(Collectors.toList());
children.stream().map(c -> c.toAsciiLines()).collect(Collectors.toList());
if (TreeConnectionType.Series.equals(connectionType)) {
return TreeAsciiUtil.concatenateMultiLineSerial(TreeAsciiUtil.generateString(TreeAsciiUtil.BOXH, 1), childrenAscii);
@@ -54,11 +54,8 @@ import org.diylc.common.GridType;
import org.diylc.common.IComponentFilter;
import org.diylc.common.IPlugInPort;
import org.diylc.common.ObjectCache;
import org.diylc.components.AbstractTransparentComponent;
import org.diylc.core.BoardUndersideDisplay;
import org.diylc.core.ComponentForRender;
import org.diylc.core.ComponentState;
import org.diylc.core.IBoard;
import org.diylc.core.IContinuity;
import org.diylc.core.IDIYComponent;
import org.diylc.core.ILayeredComponent;
@@ -84,7 +81,7 @@ public class DrawingManager {
public static int CONTROL_POINT_SIZE = 7;
public static double EXTRA_SPACE = 0.25;
public static final String ZOOM_KEY = "zoom";
public static final String ZOOM_KEY = "zoom";
private static boolean SHADE_EXTRA_SPACE = true;
@@ -93,9 +90,6 @@ public class DrawingManager {
public static Color CONTROL_POINT_COLOR = Color.blue;
public static Color SELECTED_CONTROL_POINT_COLOR = Color.green;
public static Size BOARD_MIRROR_SPACING = new Size(0.1, SizeUnit.in);
private static final Byte MIRRORED_ALPHA = 64;
private Theme theme;
@@ -176,14 +170,12 @@ public class DrawingManager {
* @param visibleRect
* @return
*/
@SuppressWarnings("unlikely-arg-type")
public List<IDIYComponent<?>> drawProject(Graphics2D g2d, Project project,
Set<DrawOption> drawOptions, IComponentFilter filter, Rectangle selectionRect,
Collection<IDIYComponent<?>> selectedComponents, Set<IDIYComponent<?>> lockedComponents,
Set<IDIYComponent<?>> groupedComponents, List<Point2D> controlPointSlot,
List<IDIYComponent<?>> componentSlot, boolean dragInProgress, Double externalZoom,
Double scaleFactor, Rectangle2D visibleRect) {
long totalStartTime = System.nanoTime();
failedComponents.clear();
if (project == null) {
@@ -202,35 +194,38 @@ public class DrawingManager {
G2DWrapper g2dWrapper = new G2DWrapper(g2d, zoom);
configureG2D(g2d, drawOptions);
// group components with boards that contain them
Map<IBoard, List<IDIYComponent<?>>> boardMap = project.getComponents().stream()
.filter(IBoard.class::isInstance)
.map(IBoard.class::cast)
.filter(b -> b.getBoardUndersideDisplay() != BoardUndersideDisplay.NONE)
.collect(Collectors.toMap(x -> x, x -> new ArrayList<IDIYComponent<?>>()));
Map<IDIYComponent<?>, List<IBoard>> componentBoardMap = new HashMap<IDIYComponent<?>, List<IBoard>>();
for (IBoard board : boardMap.keySet()) {
Rectangle2D boardRect = board.getBoardRectangle();
for (IDIYComponent<?> c : project.getComponents()) {
if (c == board) {
continue;
}
boolean include = true;
for (int i = 0; i < c.getControlPointCount(); i++) {
if (!boardRect.contains(c.getControlPoint(i))) {
include = false;
break;
}
}
if (include) {
boardMap.get(board).add(c);
componentBoardMap.computeIfAbsent(c, key -> new ArrayList<IBoard>()).add(board);
}
}
if (drawOptions.contains(DrawOption.ANTIALIASING)) {
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
} else {
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
}
if (configManager.readBoolean(IPlugInPort.HI_QUALITY_RENDER_KEY, false)) {
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
// g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
// RenderingHints.VALUE_STROKE_PURE);
} else {
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_SPEED);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
}
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
// AffineTransform initialTx = g2d.getTransform();
Dimension canvasDimension =
@@ -296,7 +291,6 @@ public class DrawingManager {
if (filter != null && !filter.testComponent(component)) {
continue;
}
ComponentState state = componentStateMap.get(component);
// Do not track the area if component is not invalidated and was
// drawn in the same state.
@@ -317,21 +311,15 @@ public class DrawingManager {
long componentStart = System.nanoTime();
try {
drawComponent(project, drawOptions, scaleFactor, visibleRect, zoom, g2dWrapper,
outlineMode, i, component, state);
double boardMirrorSpacing = BOARD_MIRROR_SPACING.convertToPixels();
List<IBoard> boards = componentBoardMap.get(component);
if (boards != null) {
for (IBoard board : boards) {
drawMirroredComponent(project, drawOptions, scaleFactor, visibleRect, zoom,
g2dWrapper, outlineMode, i, state, boardMirrorSpacing, component, board);
}
}
if (boardMap.keySet().contains(component)) {
drawMirroredComponent(project, drawOptions, scaleFactor, visibleRect, zoom,
g2dWrapper, outlineMode, i, state, boardMirrorSpacing, component, (IBoard)component);
if (drawOptions.contains(DrawOption.ENABLE_CACHING)) // go through the DrawingCache
DrawingCache.Instance.draw(component, g2dWrapper, state,
drawOptions.contains(DrawOption.OUTLINE_MODE), project, zoom, scaleFactor, i, visibleRect);
else // go straight to the wrapper
component.draw(g2dWrapper, state, outlineMode, project, g2dWrapper);
if (g2dWrapper.isTrackingContinuityArea()) {
LOG.info("Component " + component.getName() + " of type "
+ component.getClass().getName() + " did not stop tracking continuity area.");
}
} catch (Exception e) {
LOG.error("Error drawing " + component.getName(), e);
@@ -521,114 +509,6 @@ public class DrawingManager {
return failedComponents;
}
private void drawMirroredComponent(Project project, Set<DrawOption> drawOptions,
Double scaleFactor, Rectangle2D visibleRect, double zoom, G2DWrapper g2dWrapper,
boolean outlineMode, int i, ComponentState state, double boardMirrorSpacing,
IDIYComponent<?> componentToDraw, IBoard board) {
Rectangle2D boardRectangle = board.getBoardRectangle();
AffineTransform mirrorTx = null;
switch (board.getBoardUndersideDisplay()) {
case ABOVE:
mirrorTx = new AffineTransform();
mirrorTx.translate(boardRectangle.getMinX(), boardRectangle.getMinY());
mirrorTx.scale(1, -1);
mirrorTx.translate(-boardRectangle.getMinX(), -boardRectangle.getMinY());
mirrorTx.translate(0, boardMirrorSpacing);
break;
case BELOW:
mirrorTx = new AffineTransform();
mirrorTx.translate(boardRectangle.getMinX(), boardRectangle.getMaxY());
mirrorTx.scale(1, -1);
mirrorTx.translate(-boardRectangle.getMinX(), -boardRectangle.getMaxY());
mirrorTx.translate(0, -boardMirrorSpacing);
break;
case LEFT:
mirrorTx = new AffineTransform();
mirrorTx.translate(boardRectangle.getMinX(), boardRectangle.getMinY());
mirrorTx.scale(-1, 1);
mirrorTx.translate(-boardRectangle.getMinX(), -boardRectangle.getMinY());
mirrorTx.translate(boardMirrorSpacing, 0);
break;
case RIGHT:
mirrorTx = new AffineTransform();
mirrorTx.translate(boardRectangle.getMaxX(), boardRectangle.getMinY());
mirrorTx.scale(-1, 1);
mirrorTx.translate(-boardRectangle.getMaxX(), -boardRectangle.getMinY());
mirrorTx.translate(-boardMirrorSpacing, 0);
break;
default:
LOG.warn("Unexpected board underside display: " + board.getBoardUndersideDisplay());
break;
}
AffineTransform txBefore = new AffineTransform(g2dWrapper.getTransform());
byte alphaBefore = 0;
if (AbstractTransparentComponent.class.isInstance(componentToDraw)) {
alphaBefore = ((AbstractTransparentComponent<?>)componentToDraw).getAlpha();
((AbstractTransparentComponent<?>)componentToDraw).setAlpha(MIRRORED_ALPHA);
}
try {
g2dWrapper.setMirrorTransform(mirrorTx);
g2dWrapper.transform(mirrorTx);
componentToDraw.draw(g2dWrapper, state, outlineMode, project, g2dWrapper);
} finally {
g2dWrapper.setTransform(txBefore);
g2dWrapper.setMirrorTransform(null);
if (AbstractTransparentComponent.class.isInstance(componentToDraw)) {
((AbstractTransparentComponent<?>)componentToDraw).setAlpha(alphaBefore);
}
}
}
private void drawComponent(Project project, Set<DrawOption> drawOptions, Double scaleFactor,
Rectangle2D visibleRect, double zoom, G2DWrapper g2dWrapper, boolean outlineMode, int i,
IDIYComponent<?> component, ComponentState state) {
if (drawOptions.contains(DrawOption.ENABLE_CACHING)) // go through the DrawingCache
DrawingCache.Instance.draw(component, g2dWrapper, state,
drawOptions.contains(DrawOption.OUTLINE_MODE), project, zoom, scaleFactor, i, visibleRect);
else // go straight to the wrapper
component.draw(g2dWrapper, state, outlineMode, project, g2dWrapper);
if (g2dWrapper.isTrackingContinuityArea()) {
LOG.debug("Component " + component.getName() + " of type "
+ component.getClass().getName() + " did not stop tracking continuity area.");
}
}
private void configureG2D(Graphics2D g2d, Set<DrawOption> drawOptions) {
if (drawOptions.contains(DrawOption.ANTIALIASING)) {
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
} else {
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
}
if (configManager.readBoolean(IPlugInPort.HI_QUALITY_RENDER_KEY, false)) {
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
// g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
// RenderingHints.VALUE_STROKE_PURE);
} else {
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_SPEED);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
}
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
}
private double zoomCached = 0;
private Dimension canvasDimensionCached;
private double extraSpaceCached;
@@ -105,8 +105,6 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
private double zoom;
private int zOrder;
private AffineTransform mirrorTransform;
/**
* Creates a wrapper around specified {@link Graphics2D} object.
@@ -220,12 +218,8 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
@Override
public void setContinuityMarker(String marker) {
continuityMarker = marker;
}
public void setMirrorTransform(AffineTransform mirrorTransform) {
this.mirrorTransform = mirrorTransform;
}
}
/**
* Appends shape interior to the current component area.
*
@@ -350,73 +344,22 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
@Override
public void drawString(String str, int x, int y) {
this.drawString(str, (float)x, (float)y);
canvasGraphics.drawString(str, x, y);
if (drawingComponent && trackingAllowed) {
FontMetrics fontMetrics = canvasGraphics.getFontMetrics();
Rectangle2D rect = fontMetrics.getStringBounds(str, canvasGraphics);
Point2D point = new Point2D.Double(x, y);
// currentTx.transform(point, point);
Rectangle2D finalRec =
new Rectangle2D.Double(rect.getX() + point.getX(), rect.getY() + point.getY(), rect.getWidth(),
rect.getHeight());
appendShape(finalRec);
}
}
@Override
public void drawString(String str, float x, float y) {
if (this.mirrorTransform == null) {
canvasGraphics.drawString(str, x, y);
} else {
drawStringUnmirrored(str, x, y);
}
handleDrawString(str, x, y);
}
private void drawStringUnmirrored(String str, float x, float y) {
// Save the current transform (T), which includes the mirror.
AffineTransform originalTransform = new AffineTransform(getTransform());
// Compute the non-mirrored transform A by "canceling" the mirror:
// Since T = A × M and M is self-inverse, we have A = T × M.
AffineTransform nonMirroredTransform = new AffineTransform(originalTransform);
nonMirroredTransform.concatenate(mirrorTransform);
GlyphVector gv = getFont().createGlyphVector(this.getFontRenderContext(), str);
Rectangle2D visualBounds = gv.getVisualBounds();
// Use a temporary Graphics2D (with transform A) to obtain correct FontMetrics.
Graphics2D gTemp = (Graphics2D) canvasGraphics.create();
gTemp.setTransform(nonMirroredTransform);
FontMetrics fm = gTemp.getFontMetrics();
double textWidth = fm.stringWidth(str);
// Use ascent + descent as the bounding box height.
double textHeight = visualBounds.getHeight();//fm.getAscent() + fm.getDescent();
double ascent = fm.getAscent();
gTemp.dispose();
// 1. Compute the center of the text’s bounding box in the mirrored (T) space.
Point2D centerMirrored = new Point2D.Double(x + textWidth / 2.0,
y + textHeight / 2.0);
// 2. Convert that center to screen coordinates using the original transform T.
Point2D centerScreen = originalTransform.transform(centerMirrored, null);
// 3. Map the screen coordinate into the non-mirrored coordinate system (A).
Point2D centerNonMirrored;
try {
centerNonMirrored = nonMirroredTransform.createInverse().transform(centerScreen, null);
} catch (NoninvertibleTransformException e) {
e.printStackTrace();
centerNonMirrored = centerMirrored; // Fallback if inversion fails.
}
// 4. Compute the new top-left in A so that the bounding box (width x height)
// remains centered at centerNonMirrored.
double newTopLeftX = centerNonMirrored.getX() - textWidth / 2.0;
double newTopLeftY = centerNonMirrored.getY() - textHeight / 2.0;
// Adjust for the baseline (drawString uses the baseline for y)
float drawX = (float) newTopLeftX;
float drawY = (float) (newTopLeftY + ascent);
// 5. Set the transform to the non-mirrored transform (A) so that mirror is canceled.
canvasGraphics.setTransform(nonMirroredTransform);
canvasGraphics.drawString(str, drawX, drawY);
// 6. Restore the original transform.
setTransform(originalTransform);
}
private void handleDrawString(String str, float x, float y) {
canvasGraphics.drawString(str, x, y);
if (drawingComponent && trackingAllowed) {
FontMetrics fontMetrics = canvasGraphics.getFontMetrics();
Rectangle2D rect = fontMetrics.getStringBounds(str, canvasGraphics);
@@ -38,6 +38,7 @@ import org.diylc.clipboard.ComponentTransferable;
import org.diylc.common.ComponentType;
import org.diylc.common.IPlugInPort;
import org.diylc.common.Orientation;
import org.diylc.common.Orientation45;
import org.diylc.common.OrientationHV;
import org.diylc.common.PropertyWrapper;
import org.diylc.core.Angle;
@@ -436,6 +437,7 @@ public class InstantiationManager {
for (PropertyWrapper propertyWrapper : properties) {
if (propertyWrapper.getType().getName().equals(Orientation.class.getName())
|| propertyWrapper.getType().getName().equals(OrientationHV.class.getName())
|| propertyWrapper.getType().getName().equals(Orientation45.class.getName())
|| propertyWrapper.getName().equalsIgnoreCase("angle")) {
angleProperty = propertyWrapper;
break;
@@ -455,6 +457,9 @@ public class InstantiationManager {
} else if (value instanceof OrientationHV) {
angleProperty.setValue(OrientationHV.values()[(((OrientationHV) value).ordinal() + 1)
% OrientationHV.values().length]);
} else if (value instanceof Orientation45) {
angleProperty.setValue(Orientation45.values()[(((Orientation45) value).ordinal() + 1)
% Orientation45.values().length]);
} else if (value instanceof Angle) {
Angle angle = (Angle) angleProperty.getValue();
Angle newAngle = angle.rotate(1);
@@ -1619,8 +1619,13 @@ public class Presenter implements IPlugInPort, IConfigListener {
}
// There is selection, so we need to finalize the drag&drop
// operation.
dragInProgress = false;
if (!preDragProject.equals(currentProject)) {
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, preDragProject, currentProject, "Drag");
drawingManager.clearContinuityArea();
projectFileManager.notifyFileChange();
}
messageDispatcher.dispatchMessage(EventType.REPAINT);
dragInProgress = false;
}
@Override
@@ -223,7 +223,7 @@
<changes>
<org.diylc.appframework.update.Change>
<changeType>NEW_FEATURE</changeType>
<description>Switched to AppImage distribution for Linux system, abandoning Flatpak as a means of distribution. DIYLC AppImage will be available alongside with other executables on the official DIYLC GitHub page.</description>
<description>Switched to AppImage distribution for Linux system, abandoning Flatpak as a means of distribution. DIYLC AppImage will be available alongside with other executables on the official DIYLC GitHub page</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>IMPROVEMENT</changeType>
@@ -240,5 +240,29 @@
</changes>
<url>https://github.com/bancika/diy-layout-creator/releases</url>
</org.diylc.appframework.update.Version>
<org.diylc.appframework.update.Version>
<versionNumber>
<major>5</major>
<minor>1</minor>
<build>0</build>
</versionNumber>
<releaseDate>2025-03-09 00:00:00.000 CET</releaseDate>
<name></name>
<changes>
<org.diylc.appframework.update.Change>
<changeType>NEW_FEATURE</changeType>
<description>'Multimeter Probe' component added and 'Virtual Multimeter' functionality that uses it</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>IMPROVEMENT</changeType>
<description>Cleaner text representation of switch configuration in analyzer windows - removed switches and positions that have no effect on the effective circuit</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>BUG_FIX</changeType>
<description>Moving selected components with a mouse doesn't register file modification action and doesn't enable Undo action</description>
</org.diylc.appframework.update.Change>
</changes>
<url>https://github.com/bancika/diy-layout-creator/releases</url>
</org.diylc.appframework.update.Version>
</a>
</java.util.Arrays_-ArrayList>
@@ -20,6 +20,17 @@ public class TreeAsciiUtilTest {
assertEquals("yy-yyy", result.get(1));
assertEquals("&nbsp;&nbsp;&nbsp;aaa", result.get(2));
}
@Test
public void testSimpleParallel() {
List<String> result = TreeAsciiUtil.concatenateMultiLineParallel(
Arrays.asList(Arrays.asList("xx"), Arrays.asList("yy")));
assertNotNull(result);
assertEquals(3, result.size());
assertEquals("&nbsp;&#x250C;xx&#x2510;&nbsp;", result.get(0));
assertEquals("&#x2500;&#x2524;&nbsp;&nbsp;&#x251C;&#x2500;", result.get(1));
assertEquals("&nbsp;&#x2514;yy&#x2518;&nbsp;", result.get(2));
}
@Test
public void testConcatenateMultiLineSerial_singleInput() {
Binary file not shown.
@@ -34,9 +34,7 @@ import org.diylc.common.IPlugInPort;
import org.diylc.common.ObjectCache;
import org.diylc.common.VerticalAlignment;
import org.diylc.components.AbstractTransparentComponent;
import org.diylc.core.BoardUndersideDisplay;
import org.diylc.core.ComponentState;
import org.diylc.core.IBoard;
import org.diylc.core.IDrawingObserver;
import org.diylc.core.Project;
import org.diylc.core.VisibilityPolicy;
@@ -44,7 +42,7 @@ import org.diylc.core.annotations.EditableProperty;
import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit;
public abstract class AbstractBoard extends AbstractTransparentComponent<String> implements IBoard {
public abstract class AbstractBoard extends AbstractTransparentComponent<String> {
private static final long serialVersionUID = 1L;
@@ -74,8 +72,6 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
protected Size length;
protected Size width;
protected BoardSizingMode mode = BoardSizingMode.TwoPoints;
protected BoardUndersideDisplay boardUndersideDisplay = BoardUndersideDisplay.NONE;
@Override
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
@@ -367,32 +363,6 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
this.mode = mode;
}
@EditableProperty(name = "Underside Display")
@Override
public BoardUndersideDisplay getBoardUndersideDisplay() {
if (this.boardUndersideDisplay == null) {
this.boardUndersideDisplay = BoardUndersideDisplay.NONE;
}
return this.boardUndersideDisplay;
}
public void setBoardUndersideDisplay(BoardUndersideDisplay boardUndersideDisplay) {
this.boardUndersideDisplay = boardUndersideDisplay;
}
@Override
public Rectangle2D getBoardRectangle() {
Point2D finalSecondPoint = getFinalSecondPoint();
return new Rectangle2D.Double(firstPoint.getX(), firstPoint.getY(),
finalSecondPoint.getX() - firstPoint.getX(), finalSecondPoint.getY() - firstPoint.getY());
}
@Override
public boolean shouldExportToGerber() {
return false;
}
@Override
public Rectangle2D getCachingBounds() {
Point2D finalSecondPoint = getFinalSecondPoint();
@@ -37,11 +37,12 @@ import org.diylc.core.Project;
import org.diylc.core.annotations.BomPolicy;
import org.diylc.core.annotations.ComponentDescriptor;
import org.diylc.core.annotations.EditableProperty;
import org.diylc.core.gerber.IGerberBoard;
@ComponentDescriptor(name = "Blank Board", category = "Boards", author = "Branislav Stojkovic",
zOrder = IDIYComponent.BOARD, instanceNamePrefix = "Board", description = "Blank circuit board",
bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false, transformer = SimpleComponentTransformer.class)
public class BlankBoard extends AbstractBoard {
public class BlankBoard extends AbstractBoard implements IGerberBoard {
private static final long serialVersionUID = 1L;
@@ -131,11 +132,6 @@ public class BlankBoard extends AbstractBoard {
public String getControlPointNodeName(int index) {
return null;
}
@Override
public boolean shouldExportToGerber() {
return true;
}
static enum Type {
ROUND, SQUARE;
@@ -145,4 +141,12 @@ public class BlankBoard extends AbstractBoard {
return name().substring(0, 1) + name().substring(1).toLowerCase();
}
}
@Override
public Rectangle2D getBoardRectangle() {
Point2D finalSecondPoint = getFinalSecondPoint();
return new Rectangle2D.Double(firstPoint.getX(), firstPoint.getY(),
finalSecondPoint.getX() - firstPoint.getX(), finalSecondPoint.getY() - firstPoint.getY());
}
}
@@ -0,0 +1,243 @@
/*
*
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 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.connectivity;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import org.diylc.common.ObjectCache;
import org.diylc.common.Orientation45;
import org.diylc.components.AbstractTransparentComponent;
import org.diylc.components.transform.SimpleComponentTransformer;
import org.diylc.core.ComponentState;
import org.diylc.core.IDIYComponent;
import org.diylc.core.IDrawingObserver;
import org.diylc.core.Project;
import org.diylc.core.VisibilityPolicy;
import org.diylc.core.annotations.BomPolicy;
import org.diylc.core.annotations.ComponentDescriptor;
import org.diylc.core.annotations.EditableProperty;
import org.diylc.core.annotations.KeywordPolicy;
import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit;
@ComponentDescriptor(name = "Multimeter Probe", category = "Connectivity",
author = "Branislav Stojkovic", description = "Multimeter Probe", instanceNamePrefix = "Probe",
zOrder = IDIYComponent.TEXT, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, transformer = SimpleComponentTransformer.class,
enableCache = true)
public class MultimeterProbe extends AbstractTransparentComponent<Color> {
private static final long serialVersionUID = 1L;
public static Size PROBE_DIAMETER = new Size(0.05d, SizeUnit.in);
public static Size PROBE_LENGTH = new Size(0.4d, SizeUnit.in);
public static Color PROBE_COLOR = METAL_COLOR;
public static Size HANDLE_DIAMETER = new Size(0.2d, SizeUnit.in);
public static Size HANDLE_LENGTH = new Size(0.4d, SizeUnit.in);
public static Color HANDLE_COLOR = Color.red;
private Point2D.Double point = new Point2D.Double(0, 0);
private Color handleColor = HANDLE_COLOR;
private Orientation45 orientation = Orientation45._315;
private transient Shape[] body = null;
public MultimeterProbe() {
this.alpha = (byte) (MAX_ALPHA / 2);
}
@Override
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode,
Project project, IDrawingObserver drawingObserver) {
Shape[] shapes = getBody();
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f));
if (!outlineMode) {
Composite oldComposite = g2d.getComposite();
if (alpha < MAX_ALPHA) {
g2d.setComposite(
AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
}
g2d.setColor(PROBE_COLOR);
g2d.fill(shapes[0]);
g2d.setColor(handleColor);
g2d.fill(shapes[1]);
g2d.setComposite(oldComposite);
}
g2d.setColor(
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING
? SELECTION_COLOR
: handleColor.darker());
g2d.draw(shapes[1]);
g2d.setColor(
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING
? SELECTION_COLOR
: PROBE_COLOR.darker());
g2d.draw(shapes[0]);
}
@Override
public void drawIcon(Graphics2D g2d, int width, int height) {
double probeDiameter = 2;
double probeLength = height / 2 + 2;
double handleDiameter = width / 4;
double handleLength = height / 2 + 2;
double x = 2;
double y = height - 2;
Shape probe = buildProbeShape(probeDiameter, probeLength, x, y);
Shape handle = buildHandleShape(probeDiameter, probeLength, handleDiameter, handleLength, x, y);
double theta = Math.PI / 4;
AffineTransform tx = AffineTransform.getRotateInstance(theta, x, y);
probe = tx.createTransformedShape(probe);
handle = tx.createTransformedShape(handle);
g2d.setColor(PROBE_COLOR);
g2d.fill(probe);
g2d.setColor(HANDLE_COLOR);
g2d.fill(handle);
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
g2d.setColor(PROBE_COLOR.darker());
g2d.draw(probe);
g2d.setColor(HANDLE_COLOR.darker());
g2d.draw(handle);
}
public Shape[] getBody() {
if (body == null) {
double probeDiameter = PROBE_DIAMETER.convertToPixels();
double probeLength = PROBE_LENGTH.convertToPixels();
double handleDiameter = HANDLE_DIAMETER.convertToPixels();
double handleLength = HANDLE_LENGTH.convertToPixels();
double x = point.getX();
double y = point.getY();
body = new Shape[2];
Path2D probe = buildProbeShape(probeDiameter, probeLength, x, y);
body[0] = probe;
Path2D handle =
buildHandleShape(probeDiameter, probeLength, handleDiameter, handleLength, x, y);
body[1] = handle;
double theta = orientation.toRadians();
if (theta != 0) {
AffineTransform tx = AffineTransform.getRotateInstance(theta, x, y);
body[0] = tx.createTransformedShape(body[0]);
body[1] = tx.createTransformedShape(body[1]);
}
}
return body;
}
private Path2D buildHandleShape(double probeDiameter, double probeLength, double handleDiameter,
double handleLength, double x, double y) {
Path2D handle = new Path2D.Double();
handle.moveTo(x + probeDiameter, y - probeLength);
handle.lineTo(x + handleDiameter / 2, y - handleLength - probeLength);
handle.lineTo(x - handleDiameter / 2, y - handleLength - probeLength);
handle.lineTo(x - probeDiameter, y - probeLength);
handle.moveTo(x + probeDiameter, y - probeLength);
handle.closePath();
return handle;
}
private Path2D buildProbeShape(double probeDiameter, double probeLength, double x, double y) {
Path2D probe = new Path2D.Double();
probe.moveTo(x, y);
probe.lineTo(x - probeDiameter / 2, y - probeDiameter);
probe.lineTo(x - probeDiameter / 2, y - probeLength);
probe.lineTo(x + probeDiameter / 2, y - probeLength);
probe.lineTo(x + probeDiameter / 2, y - probeDiameter);
probe.lineTo(x, y);
probe.closePath();
return probe;
}
@Override
public int getControlPointCount() {
return 1;
}
@Override
public boolean isControlPointSticky(int index) {
return true;
}
@Override
public VisibilityPolicy getControlPointVisibilityPolicy(int index) {
return VisibilityPolicy.NEVER;
}
@Override
public Point2D getControlPoint(int index) {
return point;
}
@Override
public void setControlPoint(Point2D point, int index) {
this.point.setLocation(point);
this.body = null;
}
@Override
@EditableProperty(name = "Color")
public Color getValue() {
return handleColor;
}
public void setValue(Color color) {
this.handleColor = color;
}
@EditableProperty(name = "Angle")
public Orientation45 getOrientation() {
return orientation;
}
public void setOrientation(Orientation45 orientation) {
this.orientation = orientation;
this.body = null;
}
@Override
public String getControlPointNodeName(int index) {
return "Tip";
}
@Override
public Rectangle2D getCachingBounds() {
Shape[] shapes = getBody();
Rectangle2D bounds1 = shapes[0].getBounds2D();
Rectangle2D bounds2 = shapes[1].getBounds2D();
double minX = Math.min(bounds1.getMinX(), bounds2.getMinX());
double minY = Math.min(bounds1.getMinY(), bounds2.getMinY());
double maxX = Math.max(bounds1.getMaxX(), bounds2.getMaxX());
double maxY = Math.max(bounds1.getMaxY(), bounds2.getMaxY());
return new Rectangle2D.Double(minX - 1, minY - 1, maxX - minX + 2, maxY - minY + 2);
}
}
@@ -0,0 +1,91 @@
/*
*
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 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.netlist;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.swing.JLabel;
import org.diylc.common.INetlistAnalyzer;
import org.diylc.components.connectivity.MultimeterProbe;
public class MultimeterAnalyzer extends NetlistAnalyzer implements INetlistAnalyzer {
@Override
public String getName() {
return "Virtual Multimeter";
}
@Override
public String getShortName() {
return "multimeter";
}
@Override
public String getIconName() {
return "Multimeter";
}
@Override
public String getFontName() {
return new JLabel().getFont().getName();
}
protected Summary summarize(Netlist netlist, Node preferredOutput) throws TreeException {
Tree tree = constructTree(netlist);
if (tree == null) {
return new Summary(netlist, "No components found connecting the two multimeter probes.");
}
List<String> notes = new ArrayList<String>();
StringBuilder sb = new StringBuilder();
String asciiTree = tree.toAsciiString();
sb.append("<br><br>")
.append("<font face='Courier New'>")
.append(asciiTree)
.append("</font>");
if (!notes.isEmpty()) {
Collections.sort(notes);
sb.append("<br><br>");
for (String v : notes) {
sb.append(v).append("<br>");
}
}
return new Summary(netlist, sb.toString());
}
public Tree constructTree(Netlist netlist) throws TreeException {
List<Node> probeNodes = find(Set.of(MultimeterProbe.class.getCanonicalName()), null, netlist);
if (probeNodes.size() == 0) {
throw new TreeException("No multimeter probes are placed on the circuit.");
} else if (probeNodes.size() != 2) {
throw new TreeException(
"Place exactly two multimeter probes on the circuit in order to run the analysis.");
} else {
return constructTreeBetween(netlist, probeNodes.get(0), probeNodes.get(1));
}
}
}
BIN
View File
Binary file not shown.
+5 -6
View File
@@ -17,18 +17,22 @@
10 throws / 10 positions
11 throws / 11 positions
12 throws / 12 positions
135 degrees clockwise
1P12T
2 throws / 2 positions
2 throws / 3 positions / OFF even positions
225 degrees clockwise
2P5T
2P6T
3 throws / 3 positions
3 throws / 5 positions / SHORT even positions
315 degrees clockwise
3P4T
3PDT
3PDT (On/Off/On)
4 band
4 throws / 4 positions
45 degrees clockwise
4P3T
4P5T
4P5T (Super/Mega)
@@ -52,15 +56,10 @@ AWG
Alternate
And
Angle Offset
Apply Model
B-C-E BJT
Background
Board1
Box
C-B-E BJT
C1
C2
C3
Circle
Coil(s)
Component reordering is possible only when Project Explorer is sorted by z-index.
@@ -177,7 +176,7 @@ Ten
Terminal
Timing
Tubular Beveled
Underside Display
Virtual Multimeter
Xnor
Xor
cm
Binary file not shown.
Binary file not shown.
@@ -69,7 +69,7 @@ public enum IconLoader {
SnapToComponents("snap_to_components.png"), SnapToNone("snap_to_none.png"), TraceProximity("trace_proximity.png"),
ComponentLarge("component_large.png"), ImportNetlist("import_netlist.png"), SplashIC("splash_ic.png"),
ComponentPreferences("component_preferences.png"), ComponentReplace("component_replace.png"), Barcode("barcode.png"),
DocumentGerber("document_gerber.png"), DocumentX2("document_x2.png"), Export("export.png");
Multimeter("multimeter.png"), DocumentGerber("document_gerber.png"), DocumentX2("document_x2.png"), Export("export.png");
protected String name;
Binary file not shown.

After

Width:  |  Height:  |  Size: 864 B