mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-10 17:22:09 +10:00
Circuit analysis algorithm that supports netlist extraction, 'Highlight connected Areas' and 'Guitar Wiring Analyzer' features improved to take PCB trace layer and component z-order into account for better accuracy
This commit is contained in:
@@ -23,9 +23,13 @@ package org.diylc.common;
|
||||
|
||||
public enum PCBLayer {
|
||||
|
||||
_1, _2, _3, _4, _5;
|
||||
_1, _2, _3, _4, _5, _6, _7, _8;
|
||||
|
||||
public String toString() {
|
||||
return name().substring(1);
|
||||
};
|
||||
|
||||
public int getId() {
|
||||
return Integer.parseInt(toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
|
||||
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.core;
|
||||
|
||||
/**
|
||||
* Component with all extra info for it to be rendered on the screen.
|
||||
*
|
||||
* @author Branislav Stojkovic
|
||||
*/
|
||||
public class ComponentForRender {
|
||||
|
||||
private IDIYComponent<?> component;
|
||||
private ComponentState state;
|
||||
private int zOrder;
|
||||
|
||||
public ComponentForRender(IDIYComponent<?> component, ComponentState state, int zOrder) {
|
||||
super();
|
||||
this.component = component;
|
||||
this.state = state;
|
||||
this.zOrder = zOrder;
|
||||
}
|
||||
|
||||
public IDIYComponent<?> getComponent() {
|
||||
return component;
|
||||
}
|
||||
|
||||
public ComponentState getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public int getZOrder() {
|
||||
return zOrder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.diylc.core;
|
||||
|
||||
public interface ILayer {
|
||||
|
||||
int getLayerId();
|
||||
}
|
||||
@@ -23,6 +23,8 @@ import java.awt.geom.Point2D;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import org.diylc.presenter.ContinuityArea;
|
||||
import org.diylc.utils.RTree;
|
||||
|
||||
/***
|
||||
@@ -34,9 +36,9 @@ import org.diylc.utils.RTree;
|
||||
public class ContinuityGraph {
|
||||
|
||||
private RTree<ContinuityNode> groupTree;
|
||||
private Map<Integer, List<Area>> areaGroupMap;
|
||||
private Map<Integer, List<ContinuityArea>> areaGroupMap;
|
||||
|
||||
public ContinuityGraph(RTree<ContinuityNode> groupTree, Map<Integer, List<Area>> areaGroupMap) {
|
||||
public ContinuityGraph(RTree<ContinuityNode> groupTree, Map<Integer, List<ContinuityArea>> areaGroupMap) {
|
||||
super();
|
||||
this.groupTree = groupTree;
|
||||
this.areaGroupMap = areaGroupMap;
|
||||
@@ -44,22 +46,26 @@ public class ContinuityGraph {
|
||||
|
||||
public List<Area> findAreasFor(Point2D point) {
|
||||
Optional<ContinuityNode> first = groupTree.search(point, NetlistBuilder.eps).stream()
|
||||
.filter(node -> node.getArea().contains(point)).findFirst();
|
||||
.filter(node -> node.getArea().getArea().contains(point)).findFirst();
|
||||
|
||||
return first.map(node -> areaGroupMap.get(node.getGroupId())).orElse(null);
|
||||
return first.map(node ->
|
||||
areaGroupMap.get(node.getGroupId())
|
||||
.stream()
|
||||
.map(x -> x.getArea())
|
||||
.collect(Collectors.toList())).orElse(null);
|
||||
}
|
||||
|
||||
public static class ContinuityNode {
|
||||
private Area area;
|
||||
private ContinuityArea area;
|
||||
private Integer groupId;
|
||||
|
||||
public ContinuityNode(Area area, Integer groupId) {
|
||||
public ContinuityNode(ContinuityArea area, Integer groupId) {
|
||||
super();
|
||||
this.area = area;
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public Area getArea() {
|
||||
public ContinuityArea getArea() {
|
||||
return area;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,11 @@ public class Group implements Comparable<Group> {
|
||||
}
|
||||
|
||||
public Group connect(IDIYComponent<?> component, int index) {
|
||||
getNodes().add(new Node(component, index));
|
||||
return connect(component, index, 0);
|
||||
}
|
||||
|
||||
public Group connect(IDIYComponent<?> component, int index, int zOrder) {
|
||||
getNodes().add(new Node(component, index, zOrder));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ public abstract class NetlistAnalyzer {
|
||||
for (int i = 0; i < c.getControlPointCount(); i++) {
|
||||
if (i != n.getPointIndex() && c.getInternalLinkName(i, n.getPointIndex()) != null) {
|
||||
TreeLeaf l = new TreeLeaf(c, i, n.getPointIndex());
|
||||
Node newNodeA = new Node(c, i);
|
||||
Node newNodeA = new Node(c, i, n.getZIndex());
|
||||
if (!visited.contains(newNodeA)) {
|
||||
// visited.add(n);
|
||||
Tree newCurrentPath = null;
|
||||
|
||||
@@ -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;
|
||||
@@ -39,6 +40,7 @@ import org.diylc.lang.LangUtil;
|
||||
import org.diylc.netlist.ContinuityGraph.ContinuityNode;
|
||||
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;
|
||||
@@ -55,8 +57,8 @@ public class NetlistBuilder {
|
||||
.translate("Maximum number of switching combinations exceeded. Allowed: %s, actual: %s");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static List<Netlist> extractNetlists(boolean includeSwitches, Project project, List<Area> continuityAreas)
|
||||
throws NetlistException {
|
||||
public static List<Netlist> extractNetlists(boolean includeSwitches, Project project,
|
||||
List<ContinuityArea> continuityAreas) throws NetlistException {
|
||||
Map<Netlist, Netlist> result = new HashMap<Netlist, Netlist>();
|
||||
List<Node> nodes = new ArrayList<Node>();
|
||||
|
||||
@@ -64,27 +66,30 @@ public class NetlistBuilder {
|
||||
|
||||
Set<String> commonNodes = new HashSet<String>();
|
||||
|
||||
for (IDIYComponent<?> c : project.getComponents()) {
|
||||
for (int j = 0; j < project.getComponents().size(); j++) {
|
||||
IDIYComponent<?> c = project.getComponents().get(j);
|
||||
ComponentType type = ComponentProcessor.getInstance()
|
||||
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) c.getClass());
|
||||
|
||||
// extract nodes
|
||||
if (!(c instanceof IContinuity) && !(c instanceof ICommonNode)) {
|
||||
// regular components, create a node per control point
|
||||
for (int i = 0; i < c.getControlPointCount(); i++) {
|
||||
String nodeName = c.getControlPointNodeName(i);
|
||||
if (nodeName != null
|
||||
if (c.isControlPointSticky(i) && nodeName != null
|
||||
&& (!includeSwitches || !ISwitch.class.isAssignableFrom(type.getInstanceClass()))) {
|
||||
nodes.add(new Node(c, i));
|
||||
nodes.add(new Node(c, i, j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create only one node per common label to avoid duplications in the netlist, as they will get eventually connected anyways
|
||||
// create only one node per common label to avoid duplications in the netlist, as they will
|
||||
// get eventually connected anyways
|
||||
if (c instanceof ICommonNode) {
|
||||
String label = ((ICommonNode)c).getCommonNodeLabel();
|
||||
String label = ((ICommonNode) c).getCommonNodeLabel();
|
||||
if (!commonNodes.contains(label)) {
|
||||
commonNodes.add(label);
|
||||
nodes.add(new Node(c, 0));
|
||||
nodes.add(new Node(c, 0, j));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,8 +147,8 @@ public class NetlistBuilder {
|
||||
}
|
||||
List<Connection> connections = getConnections(project, switchPositions);
|
||||
|
||||
Netlist netlist = NetlistBuilder.buildNetlist(project.getComponents(), nodes,
|
||||
continuityAreas, connections);
|
||||
Netlist netlist =
|
||||
NetlistBuilder.buildNetlist(project.getComponents(), nodes, continuityAreas, connections);
|
||||
|
||||
// merge graphs that are effectively the same
|
||||
if (result.containsKey(netlist)) {
|
||||
@@ -176,7 +181,7 @@ public class NetlistBuilder {
|
||||
}
|
||||
|
||||
public static Netlist buildNetlist(List<IDIYComponent<?>> components, Collection<Node> nodes,
|
||||
Collection<Area> continuityAreas, Collection<Connection> connections) {
|
||||
Collection<ContinuityArea> continuityAreas, Collection<Connection> connections) {
|
||||
ImmutableGraph<ProjectGraphNode> graph = buildGraph(nodes, continuityAreas, connections);
|
||||
|
||||
Traverser<ProjectGraphNode> traverser = Traverser.forGraph(graph);
|
||||
@@ -211,7 +216,7 @@ public class NetlistBuilder {
|
||||
return netlist;
|
||||
}
|
||||
|
||||
public static ContinuityGraph buildContinuityGraph(Collection<Area> continuityAreas,
|
||||
public static ContinuityGraph buildContinuityGraph(Collection<ContinuityArea> continuityAreas,
|
||||
Collection<Connection> connections) {
|
||||
ImmutableGraph<ProjectGraphNode> graph =
|
||||
buildGraph(new ArrayList<Node>(), continuityAreas, connections);
|
||||
@@ -224,7 +229,7 @@ public class NetlistBuilder {
|
||||
int groupId = 1;
|
||||
|
||||
RTree<ContinuityNode> groupTree = new RTree<ContinuityGraph.ContinuityNode>();
|
||||
Map<Integer, List<Area>> areaGroupMap = new HashMap<Integer, List<Area>>();
|
||||
Map<Integer, List<ContinuityArea>> areaGroupMap = new HashMap<Integer, List<ContinuityArea>>();
|
||||
|
||||
while (true) {
|
||||
|
||||
@@ -237,12 +242,13 @@ public class NetlistBuilder {
|
||||
|
||||
final int finalGroupId = groupId;
|
||||
|
||||
List<Area> areaList = new ArrayList<Area>();
|
||||
List<ContinuityArea> areaList = new ArrayList<ContinuityArea>();
|
||||
traverser.breadthFirst(nodeArr[i]).forEach(node -> {
|
||||
visited.add(node);
|
||||
if (node.getArea() != null) {
|
||||
areaList.add(node.getArea());
|
||||
groupTree.insert(node.getArea(), new ContinuityNode(node.getArea(), finalGroupId));
|
||||
groupTree.insert(node.getArea().getArea(),
|
||||
new ContinuityNode(node.getArea(), finalGroupId));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -257,7 +263,7 @@ public class NetlistBuilder {
|
||||
|
||||
/****
|
||||
* Build an {@link ImmutableGraph} containing the following nodes: project nodes, both ends of
|
||||
* each connection and one node per continuity areas. All vertices are added based on object
|
||||
* each connection and one node per continuity area. All vertices are added based on object
|
||||
* proximity or intersection.
|
||||
*
|
||||
* @param nodes
|
||||
@@ -266,45 +272,52 @@ public class NetlistBuilder {
|
||||
* @return
|
||||
*/
|
||||
private static ImmutableGraph<ProjectGraphNode> buildGraph(Collection<Node> nodes,
|
||||
Collection<Area> continuityAreas, Collection<Connection> connections) {
|
||||
Map<Point2D, List<ProjectGraphNode>> nodeMap = new HashMap<Point2D, List<ProjectGraphNode>>();
|
||||
Collection<ContinuityArea> continuityAreas, Collection<Connection> connections) {
|
||||
|
||||
RTree<ProjectGraphNode> nodeTree = new RTree<ProjectGraphNode>();
|
||||
Map<Point2D, List<ProjectGraphNode>> nodeMapByPoint =
|
||||
new HashMap<Point2D, List<ProjectGraphNode>>();
|
||||
|
||||
// RTree<ProjectGraphNode> nodeTree = new RTree<ProjectGraphNode>();
|
||||
RTree<ProjectGraphNode> areaTree = new RTree<ProjectGraphNode>();
|
||||
|
||||
Builder<ProjectGraphNode> builder = GraphBuilder.undirected().<ProjectGraphNode>immutable();
|
||||
|
||||
List<ProjectGraphNode> controlPointNodeList = new ArrayList<ProjectGraphNode>();
|
||||
|
||||
for (Node node : nodes) {
|
||||
Point2D p = snapToEps(node.getPoint2D(), eps);
|
||||
ProjectGraphNode graphNode = new ProjectGraphNode(p, node);
|
||||
builder.addNode(graphNode);
|
||||
nodeTree.insert(new float[] {(float) (p.getX() - eps), (float) (p.getY() - eps)},
|
||||
new float[] {eps * 2, eps * 2}, graphNode);
|
||||
nodeMap.computeIfAbsent(p, (point) -> new ArrayList<ProjectGraphNode>())
|
||||
// nodeTree.insert(new float[] {(float) (p.getX() - eps), (float) (p.getY() - eps)},
|
||||
// new float[] {eps * 2, eps * 2}, graphNode);
|
||||
nodeMapByPoint.computeIfAbsent(p, (point) -> new ArrayList<ProjectGraphNode>())
|
||||
.add(new ProjectGraphNode(p, node));
|
||||
controlPointNodeList.add(graphNode);
|
||||
}
|
||||
|
||||
for (Connection conn : connections) {
|
||||
Point2D p1 = snapToEps(conn.getP1(), eps);
|
||||
Point2D p2 = snapToEps(conn.getP2(), eps);
|
||||
|
||||
ProjectGraphNode graphNode1 = new ProjectGraphNode(p1);
|
||||
ProjectGraphNode graphNode2 = new ProjectGraphNode(p2);
|
||||
ProjectGraphNode graphNode1 = new ProjectGraphNode(p1, conn.getZIndex());
|
||||
ProjectGraphNode graphNode2 = new ProjectGraphNode(p2, conn.getZIndex());
|
||||
|
||||
nodeTree.insert(new float[] {(float) p1.getX() - eps, (float) p1.getY() - eps},
|
||||
new float[] {eps * 2, eps * 2}, graphNode1);
|
||||
nodeTree.insert(new float[] {(float) p2.getX() - eps, (float) p2.getY() - eps},
|
||||
new float[] {eps * 2, eps * 2}, graphNode2);
|
||||
// nodeTree.insert(new float[] {(float) p1.getX() - eps, (float) p1.getY() - eps},
|
||||
// new float[] {eps * 2, eps * 2}, graphNode1);
|
||||
// nodeTree.insert(new float[] {(float) p2.getX() - eps, (float) p2.getY() - eps},
|
||||
// new float[] {eps * 2, eps * 2}, graphNode2);
|
||||
|
||||
builder.addNode(graphNode1);
|
||||
builder.addNode(graphNode2);
|
||||
builder.putEdge(graphNode1, graphNode2);
|
||||
|
||||
nodeMap.computeIfAbsent(p1, (point) -> new ArrayList<ProjectGraphNode>()).add(graphNode1);
|
||||
nodeMap.computeIfAbsent(p2, (point) -> new ArrayList<ProjectGraphNode>()).add(graphNode2);
|
||||
nodeMapByPoint.computeIfAbsent(p1, (point) -> new ArrayList<ProjectGraphNode>())
|
||||
.add(graphNode1);
|
||||
nodeMapByPoint.computeIfAbsent(p2, (point) -> new ArrayList<ProjectGraphNode>())
|
||||
.add(graphNode2);
|
||||
}
|
||||
|
||||
for (Map.Entry<Point2D, List<ProjectGraphNode>> entry : nodeMap.entrySet()) {
|
||||
for (Map.Entry<Point2D, List<ProjectGraphNode>> entry : nodeMapByPoint.entrySet()) {
|
||||
ProjectGraphNode[] nodeArr = entry.getValue().toArray(new ProjectGraphNode[0]);
|
||||
for (int i = 0; i < nodeArr.length - 1; i++) {
|
||||
for (int j = i + 1; j < nodeArr.length; j++) {
|
||||
@@ -313,30 +326,36 @@ public class NetlistBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
for (Area area : continuityAreas) {
|
||||
for (ContinuityArea area : continuityAreas) {
|
||||
ProjectGraphNode areaNode = new ProjectGraphNode(area);
|
||||
builder.addNode(areaNode);
|
||||
|
||||
ProjectGraphNode[] nodeArr = nodeTree.search(area).stream()
|
||||
.filter(graphNode -> area.contains(graphNode.getPoint())
|
||||
|| area.intersects(graphNode.getPoint().getX() - eps / 2,
|
||||
graphNode.getPoint().getY() - eps / 2, eps, eps))
|
||||
.collect(Collectors.toList()).toArray(new ProjectGraphNode[0]);
|
||||
// List<ProjectGraphNode> candidateNodes = nodeTree.search(area.getArea()).stream()
|
||||
// .filter(graphNode -> area.getArea().contains(graphNode.getPoint())
|
||||
// || area.getArea().intersects(graphNode.getPoint().getX() - eps / 2,
|
||||
// graphNode.getPoint().getY() - eps / 2, eps, eps))
|
||||
// .collect(Collectors.toList());
|
||||
//
|
||||
// List<ProjectGraphNode> nodesAbove = candidateNodes.stream()
|
||||
// .filter(x -> x.getNode().getZIndex() > area.getZOrder())
|
||||
// .sorted(Comparator.comparing(x -> x.getNode().getZIndex(), Comparator.reverseOrder()))
|
||||
// .collect(Collectors.toList());
|
||||
//
|
||||
// for (ProjectGraphNode node : nodeArr) {
|
||||
// builder.putEdge(node, areaNode);
|
||||
// }
|
||||
|
||||
for (ProjectGraphNode node : nodeArr) {
|
||||
builder.putEdge(node, areaNode);
|
||||
}
|
||||
// for (int i = 0; i < nodeArr.length - 1; i++) {
|
||||
// for (int j = i + 1; j < nodeArr.length; j++) {
|
||||
// builder.putEdge(nodeArr[i], nodeArr[j]);
|
||||
// }
|
||||
// }
|
||||
|
||||
for (int i = 0; i < nodeArr.length - 1; i++) {
|
||||
for (int j = i + 1; j < nodeArr.length; j++) {
|
||||
builder.putEdge(nodeArr[i], nodeArr[j]);
|
||||
}
|
||||
}
|
||||
|
||||
areaTree.search(area).stream().filter(graphNode -> {
|
||||
if (graphNode.getArea() != null && graphNode.getArea() != area) {
|
||||
Area a = new Area(graphNode.getArea());
|
||||
a.intersect(area);
|
||||
areaTree.search(area.getArea()).stream().filter(graphNode -> {
|
||||
if (graphNode.getArea() != null && graphNode.getArea() != area
|
||||
&& graphNode.getArea().getLayerId() == area.getLayerId()) {
|
||||
Area a = new Area(graphNode.getArea().getArea());
|
||||
a.intersect(area.getArea());
|
||||
return !a.isEmpty();
|
||||
}
|
||||
return false;
|
||||
@@ -344,36 +363,68 @@ public class NetlistBuilder {
|
||||
builder.putEdge(graphNode, areaNode);
|
||||
});
|
||||
|
||||
areaTree.insert(area, areaNode);
|
||||
areaTree.insert(area.getArea(), areaNode);
|
||||
}
|
||||
|
||||
for (Map.Entry<Point2D, List<ProjectGraphNode>> entry : nodeMapByPoint.entrySet()) {
|
||||
|
||||
final Point2D point = entry.getKey();
|
||||
|
||||
List<ProjectGraphNode> candidateAreaNodes = areaTree.search(point, eps).stream()
|
||||
.filter(graphNode -> graphNode.getArea().getArea().contains(point)
|
||||
|| graphNode.getArea().getArea().intersects(point.getX() - eps / 2,
|
||||
point.getY() - eps / 2, eps, eps))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (candidateAreaNodes.isEmpty())
|
||||
continue;
|
||||
|
||||
for (ProjectGraphNode pointNode : entry.getValue()) {
|
||||
|
||||
List<ProjectGraphNode> areaNodesBelowPoint = candidateAreaNodes.stream()
|
||||
.filter(x -> x.getArea().getZIndex() < pointNode.getZIndex())
|
||||
.sorted(Comparator.comparing(x -> x.getArea().getZIndex(), Comparator.reverseOrder()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (areaNodesBelowPoint.isEmpty()) {
|
||||
builder.putEdge(pointNode, candidateAreaNodes.get(0));
|
||||
} else {
|
||||
builder.putEdge(pointNode, areaNodesBelowPoint.get(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "unlikely-arg-type"})
|
||||
private static List<Connection> getConnections(Project project, Map<ISwitch, Integer> switchPositions) {
|
||||
private static List<Connection> getConnections(Project project,
|
||||
Map<ISwitch, Integer> switchPositions) {
|
||||
Set<Connection> connections = new TreeSet<Connection>();
|
||||
|
||||
Map<String, List<IDIYComponent<?>>> commonNodeMap = new HashMap<String, List<IDIYComponent<?>>>();
|
||||
Map<String, List<IDIYComponent<?>>> commonNodeMap =
|
||||
new HashMap<String, List<IDIYComponent<?>>>();
|
||||
|
||||
for (IDIYComponent<?> c : project.getComponents()) {
|
||||
ComponentType type =
|
||||
ComponentProcessor.getInstance().extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) c.getClass());
|
||||
for (int z = 0; z < project.getComponents().size(); z++) {
|
||||
IDIYComponent<?> c = project.getComponents().get(z);
|
||||
ComponentType type = ComponentProcessor.getInstance()
|
||||
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) c.getClass());
|
||||
// handle direct connections
|
||||
if (c instanceof IContinuity) {
|
||||
for (int i = 0; i < c.getControlPointCount() - 1; i++)
|
||||
for (int j = i + 1; j < c.getControlPointCount(); j++)
|
||||
if (((IContinuity) c).arePointsConnected(i, j))
|
||||
connections.add(new Connection(c.getControlPoint(i), c.getControlPoint(j)));
|
||||
connections.add(new Connection(c.getControlPoint(i), c.getControlPoint(j), z));
|
||||
}
|
||||
// handle switches
|
||||
if (ISwitch.class.isAssignableFrom(type.getInstanceClass()) && switchPositions.containsKey(c)) {
|
||||
if (ISwitch.class.isAssignableFrom(type.getInstanceClass())
|
||||
&& switchPositions.containsKey(c)) {
|
||||
int position = switchPositions.get(c);
|
||||
ISwitch s = (ISwitch) c;
|
||||
for (int i = 0; i < c.getControlPointCount() - 1; i++)
|
||||
for (int j = i + 1; j < c.getControlPointCount(); j++)
|
||||
if (s.arePointsConnected(i, j, position))
|
||||
connections.add(new Connection(c.getControlPoint(i), c.getControlPoint(j)));
|
||||
connections.add(new Connection(c.getControlPoint(i), c.getControlPoint(j), z));
|
||||
}
|
||||
// handle common nodes
|
||||
if (ICommonNode.class.isAssignableFrom(type.getInstanceClass())) {
|
||||
@@ -387,7 +438,8 @@ public class NetlistBuilder {
|
||||
for (List<IDIYComponent<?>> commonPoints : commonNodeMap.values()) {
|
||||
IDIYComponent<?>[] commonPointArr = commonPoints.toArray(new IDIYComponent<?>[0]);
|
||||
for (int i = 0; i < commonPointArr.length - 1; i++) {
|
||||
connections.add(new Connection(commonPointArr[i].getControlPoint(0), commonPointArr[i + 1].getControlPoint(0)));
|
||||
connections.add(new Connection(commonPointArr[i].getControlPoint(0),
|
||||
commonPointArr[i + 1].getControlPoint(0), 0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,19 +451,22 @@ public class NetlistBuilder {
|
||||
Math.round(point.getY() / eps) * eps);
|
||||
}
|
||||
|
||||
private static class ProjectGraphNode {
|
||||
static class ProjectGraphNode {
|
||||
private Point2D point;
|
||||
private Node node;
|
||||
private Area area;
|
||||
private ContinuityArea area;
|
||||
private int zIndex;
|
||||
|
||||
public ProjectGraphNode(Area area) {
|
||||
public ProjectGraphNode(ContinuityArea area) {
|
||||
super();
|
||||
this.area = area;
|
||||
this.zIndex = area.getZIndex();
|
||||
}
|
||||
|
||||
public ProjectGraphNode(Point2D point) {
|
||||
public ProjectGraphNode(Point2D point, int zIndex) {
|
||||
super();
|
||||
this.point = point;
|
||||
this.zIndex = zIndex;
|
||||
this.node = null;
|
||||
}
|
||||
|
||||
@@ -419,17 +474,22 @@ public class NetlistBuilder {
|
||||
super();
|
||||
this.point = point;
|
||||
this.node = node;
|
||||
this.zIndex = node.getZIndex();
|
||||
}
|
||||
|
||||
public Point2D getPoint() {
|
||||
return point;
|
||||
}
|
||||
|
||||
public int getZIndex() {
|
||||
return zIndex;
|
||||
}
|
||||
|
||||
public Node getNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
public Area getArea() {
|
||||
public ContinuityArea getArea() {
|
||||
return area;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,11 +34,13 @@ public class Node implements Comparable<Node> {
|
||||
|
||||
private IDIYComponent<?> component;
|
||||
private int pointIndex;
|
||||
private int zIndex;
|
||||
|
||||
public Node(IDIYComponent<?> component, int pointIndex) {
|
||||
public Node(IDIYComponent<?> component, int pointIndex, int zIndex) {
|
||||
super();
|
||||
this.component = component;
|
||||
this.pointIndex = pointIndex;
|
||||
this.zIndex = zIndex;
|
||||
}
|
||||
|
||||
public IDIYComponent<?> getComponent() {
|
||||
@@ -49,6 +51,10 @@ public class Node implements Comparable<Node> {
|
||||
return pointIndex;
|
||||
}
|
||||
|
||||
public int getZIndex() {
|
||||
return zIndex;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
String[] section = component.getSectionNames(pointIndex);
|
||||
return (section == null || section.length > 1 ? "" : section[0] + ".") + component.getControlPointNodeName(pointIndex);
|
||||
|
||||
@@ -29,6 +29,7 @@ public class ComponentArea implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private int zOrder;
|
||||
private Area outlineArea;
|
||||
private Collection<Area> continuityPositiveAreas;
|
||||
private Collection<Area> continuityNegativeAreas;
|
||||
@@ -36,13 +37,18 @@ public class ComponentArea implements Serializable {
|
||||
public ComponentArea() {
|
||||
}
|
||||
|
||||
public ComponentArea(Area outlineArea, Collection<Area> continuityPositiveAreas, Collection<Area> continuityNegativeAreas) {
|
||||
public ComponentArea(int zOrder, Area outlineArea, Collection<Area> continuityPositiveAreas, Collection<Area> continuityNegativeAreas) {
|
||||
super();
|
||||
this.zOrder = zOrder;
|
||||
this.outlineArea = outlineArea;
|
||||
this.continuityPositiveAreas = continuityPositiveAreas;
|
||||
this.continuityNegativeAreas = continuityNegativeAreas;
|
||||
}
|
||||
|
||||
public int getZOrder() {
|
||||
return zOrder;
|
||||
}
|
||||
|
||||
public Area getOutlineArea() {
|
||||
return outlineArea;
|
||||
}
|
||||
|
||||
@@ -28,10 +28,12 @@ public class Connection implements Comparable<Connection> {
|
||||
|
||||
private Point2D p1;
|
||||
private Point2D p2;
|
||||
private int zIndex;
|
||||
|
||||
public Connection(Point2D p1, Point2D p2) {
|
||||
public Connection(Point2D p1, Point2D p2, int zIndex) {
|
||||
this.p1 = p1.getX() < p2.getX() || p1.getX() == p2.getX() && p1.getY() < p2.getY() ? p1 : p2;
|
||||
this.p2 = p1.getX() < p2.getX() || p1.getX() == p2.getX() && p1.getY() < p2.getY() ? p2 : p1;
|
||||
this.zIndex = zIndex;
|
||||
}
|
||||
|
||||
public Point2D getP1() {
|
||||
@@ -42,12 +44,17 @@ public class Connection implements Comparable<Connection> {
|
||||
return p2;
|
||||
}
|
||||
|
||||
public int getZIndex() {
|
||||
return zIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((p1 == null) ? 0 : p1.hashCode());
|
||||
result = prime * result + ((p2 == null) ? 0 : p2.hashCode());
|
||||
result = prime * result + zIndex;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -70,6 +77,8 @@ public class Connection implements Comparable<Connection> {
|
||||
return false;
|
||||
} else if (!p2.equals(other.p2))
|
||||
return false;
|
||||
if (zIndex != other.zIndex)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
*
|
||||
* 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.presenter;
|
||||
|
||||
import java.awt.geom.Area;
|
||||
import java.io.Serializable;
|
||||
|
||||
public class ContinuityArea implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private int zIndex;
|
||||
private int layerId;
|
||||
private Area area;
|
||||
|
||||
public ContinuityArea() {}
|
||||
|
||||
public ContinuityArea(int zIndex, int layerId, Area area) {
|
||||
super();
|
||||
this.zIndex = zIndex;
|
||||
this.layerId = layerId;
|
||||
this.area = area;
|
||||
}
|
||||
|
||||
public int getZIndex() {
|
||||
return zIndex;
|
||||
}
|
||||
|
||||
public Area getArea() {
|
||||
return area;
|
||||
}
|
||||
|
||||
public int getLayerId() {
|
||||
return layerId;
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.diylc.common.ComponentType;
|
||||
import org.diylc.core.ComponentForRender;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.Project;
|
||||
@@ -63,14 +64,14 @@ public class DrawingCache {
|
||||
* @param zoom
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void bulkPrepare(Map<IDIYComponent<?>, ComponentState> components, G2DWrapper g2d, boolean outlineMode, Project project, double zoom) {
|
||||
public void bulkPrepare(Collection<ComponentForRender> components, G2DWrapper g2d, boolean outlineMode, Project project, double zoom) {
|
||||
// run all renders in parallel to utilize all CPU cores
|
||||
components.entrySet().stream().parallel().forEach(x -> {
|
||||
components.stream().parallel().forEach(x -> {
|
||||
ComponentType type = ComponentProcessor.getInstance()
|
||||
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) x.getKey().getClass());
|
||||
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) x.getComponent().getClass());
|
||||
|
||||
if (type != null && type.getEnableCache()) {
|
||||
renderAndCache(x.getKey(), g2d, x.getValue(), outlineMode, project, zoom);
|
||||
renderAndCache(x.getComponent(), g2d, x.getState(), outlineMode, project, zoom, x.getZOrder());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -88,7 +89,7 @@ public class DrawingCache {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void draw(IDIYComponent<?> component, G2DWrapper g2d, ComponentState componentState,
|
||||
boolean outlineMode, Project project, double zoom, Rectangle2D visibleRect) {
|
||||
boolean outlineMode, Project project, double zoom, int zOrder, Rectangle2D visibleRect) {
|
||||
ComponentType type = ComponentProcessor.getInstance()
|
||||
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) component.getClass());
|
||||
|
||||
@@ -96,7 +97,7 @@ public class DrawingCache {
|
||||
// if we need to apply caching
|
||||
Point2D firstPoint = component.getControlPoint(0);
|
||||
|
||||
CacheValue value = renderAndCache(component, g2d, componentState, outlineMode, project, zoom);
|
||||
CacheValue value = renderAndCache(component, g2d, componentState, outlineMode, project, zoom, zOrder);
|
||||
|
||||
if (value == null) {
|
||||
return;
|
||||
@@ -175,7 +176,7 @@ public class DrawingCache {
|
||||
}
|
||||
|
||||
private CacheValue renderAndCache(IDIYComponent<?> component, G2DWrapper g2d, ComponentState componentState,
|
||||
boolean outlineMode, Project project, double zoom) {
|
||||
boolean outlineMode, Project project, double zoom, int zOrder) {
|
||||
// if we need to apply caching
|
||||
Point2D firstPoint = component.getControlPoint(0);
|
||||
|
||||
@@ -225,7 +226,7 @@ public class DrawingCache {
|
||||
G2DWrapper wrapper = new G2DWrapper(cg2d, zoom);
|
||||
|
||||
// initialize wrapper
|
||||
wrapper.startedDrawingComponent();
|
||||
wrapper.startedDrawingComponent(zOrder);
|
||||
|
||||
long componentStart = System.nanoTime();
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -52,9 +53,11 @@ import org.diylc.common.GridType;
|
||||
import org.diylc.common.IComponentFilter;
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.core.ComponentForRender;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IContinuity;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.ILayer;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.Theme;
|
||||
import org.diylc.core.VisibilityPolicy;
|
||||
@@ -136,7 +139,7 @@ public class DrawingManager {
|
||||
configManager.writeValue(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME);
|
||||
}
|
||||
|
||||
componentAreaMap = new HashMap<IDIYComponent<?>, ComponentArea>();
|
||||
componentAreaMap = new LinkedHashMap<IDIYComponent<?>, ComponentArea>();
|
||||
lastDrawnStateMap = new HashMap<IDIYComponent<?>, ComponentState>();
|
||||
String debugComponentAreasStr = System.getProperty(DEBUG_COMPONENT_AREAS);
|
||||
debugComponentAreas =
|
||||
@@ -252,9 +255,10 @@ public class DrawingManager {
|
||||
// g2dWrapper.resetTx();
|
||||
|
||||
// put components and their states in a map
|
||||
Map<IDIYComponent<?>, ComponentState> componentStateMap =
|
||||
new HashMap<IDIYComponent<?>, ComponentState>();
|
||||
for (IDIYComponent<?> component : project.getComponents()) {
|
||||
Map<IDIYComponent<?>, ComponentState> componentStateMap = new HashMap<IDIYComponent<?>, ComponentState>();
|
||||
List<ComponentForRender> componentForRenderList = new ArrayList<ComponentForRender>();
|
||||
for (int i = 0; i < project.getComponents().size(); i++) {
|
||||
IDIYComponent<?> component = project.getComponents().get(i);
|
||||
ComponentState state = ComponentState.NORMAL;
|
||||
if (drawOptions.contains(DrawOption.SELECTION) && selectedComponents.contains(component)) {
|
||||
if (dragInProgress) {
|
||||
@@ -264,17 +268,21 @@ public class DrawingManager {
|
||||
}
|
||||
}
|
||||
componentStateMap.put(component, state);
|
||||
componentForRenderList.add(new ComponentForRender(component, state, i));
|
||||
}
|
||||
|
||||
boolean outlineMode = drawOptions.contains(DrawOption.OUTLINE_MODE);
|
||||
|
||||
// give the cache a chance to prepare all the components in multiple threads
|
||||
if (drawOptions.contains(DrawOption.ENABLE_CACHING)) {
|
||||
DrawingCache.Instance.bulkPrepare(componentStateMap, g2dWrapper, outlineMode, project, zoom);
|
||||
DrawingCache.Instance.bulkPrepare(componentForRenderList, g2dWrapper, outlineMode, project, zoom);
|
||||
}
|
||||
|
||||
// componentAreaMap.clear();
|
||||
for (IDIYComponent<?> component : project.getComponents()) {
|
||||
|
||||
for (int i = 0; i < project.getComponents().size(); i++) {
|
||||
IDIYComponent<?> component = project.getComponents().get(i);
|
||||
|
||||
// Do not draw the component if it's filtered out.
|
||||
if (filter != null && !filter.testComponent(component)) {
|
||||
continue;
|
||||
@@ -285,7 +293,7 @@ public class DrawingManager {
|
||||
boolean trackArea = lastDrawnStateMap.get(component) != state;
|
||||
|
||||
synchronized (g2d) {
|
||||
g2dWrapper.startedDrawingComponent();
|
||||
g2dWrapper.startedDrawingComponent(i);
|
||||
if (!trackArea) {
|
||||
g2dWrapper.stopTracking();
|
||||
}
|
||||
@@ -300,7 +308,7 @@ public class DrawingManager {
|
||||
|
||||
if (drawOptions.contains(DrawOption.ENABLE_CACHING)) // go through the DrawingCache
|
||||
DrawingCache.Instance.draw(component, g2dWrapper, state,
|
||||
drawOptions.contains(DrawOption.OUTLINE_MODE), project, zoom, visibleRect);
|
||||
drawOptions.contains(DrawOption.OUTLINE_MODE), project, zoom, i, visibleRect);
|
||||
else // go straight to the wrapper
|
||||
component.draw(g2dWrapper, state, outlineMode, project, g2dWrapper);
|
||||
|
||||
@@ -386,7 +394,7 @@ public class DrawingManager {
|
||||
|
||||
// Draw component slot in a separate composite.
|
||||
if (componentSlot != null) {
|
||||
g2dWrapper.startedDrawingComponent();
|
||||
g2dWrapper.startedDrawingComponent(project.getComponents().size());
|
||||
g2dWrapper.setComposite(slotComposite);
|
||||
for (IDIYComponent<?> component : componentSlot) {
|
||||
try {
|
||||
@@ -684,77 +692,100 @@ public class DrawingManager {
|
||||
messageDispatcher.dispatchMessage(EventType.REPAINT);
|
||||
}
|
||||
|
||||
public void findContinuityAreaAtPoint(Project project, Point2D p) {
|
||||
public void findContinuityAreaAtPoint(Point2D p) {
|
||||
if (continuityGraphCache == null)
|
||||
continuityGraphCache = getContinuityGraph(project);
|
||||
continuityGraphCache = getContinuityGraph();
|
||||
|
||||
currentContinuityAreas = continuityGraphCache.findAreasFor(p);
|
||||
}
|
||||
|
||||
public List<Area> getContinuityAreas(Project project) {
|
||||
public List<ContinuityArea> getContinuityAreas() {
|
||||
// Find all individual continuity areas for all components
|
||||
List<Area> preliminaryAreas = new ArrayList<Area>();
|
||||
List<ContinuityArea> preliminaryAreas = new ArrayList<ContinuityArea>();
|
||||
List<Boolean> checkBreakout = new ArrayList<Boolean>();
|
||||
|
||||
for (IDIYComponent<?> c : project.getComponents()) {
|
||||
ComponentArea a = getComponentArea(c);
|
||||
for (Map.Entry<IDIYComponent<?>, ComponentArea> entry : this.componentAreaMap.entrySet()) {
|
||||
ComponentArea a = entry.getValue();
|
||||
|
||||
if (a == null || a.getOutlineArea() == null)
|
||||
continue;
|
||||
|
||||
IDIYComponent<?> component = entry.getKey();
|
||||
|
||||
int layerId;
|
||||
|
||||
if (component instanceof ILayer) {
|
||||
layerId = ((ILayer)component).getLayerId();
|
||||
} else {
|
||||
layerId = component.hashCode();
|
||||
}
|
||||
|
||||
Collection<Area> positiveAreas = a.getContinuityPositiveAreas();
|
||||
if (positiveAreas != null)
|
||||
if (positiveAreas != null) {
|
||||
for (Area a1 : positiveAreas) {
|
||||
preliminaryAreas.add(a1);
|
||||
preliminaryAreas.add(new ContinuityArea(a.getZOrder(), layerId, a1));
|
||||
checkBreakout.add(false);
|
||||
}
|
||||
}
|
||||
|
||||
Collection<Area> negativeAreas = a.getContinuityNegativeAreas();
|
||||
if (negativeAreas != null) {
|
||||
for (Area na : negativeAreas)
|
||||
for (Area na : negativeAreas) {
|
||||
for (int i = 0; i < preliminaryAreas.size(); i++) {
|
||||
Area a1 = preliminaryAreas.get(i);
|
||||
if (a1.intersects(na.getBounds2D())) {
|
||||
a1.subtract(na);
|
||||
ContinuityArea a1 = preliminaryAreas.get(i);
|
||||
if (a1.getLayerId() == layerId && a1.getArea().intersects(na.getBounds2D())) {
|
||||
a1.getArea().subtract(na);
|
||||
checkBreakout.set(i, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we need to break some areas out in case they are interrupted
|
||||
List<Area> areas = new ArrayList<Area>();
|
||||
List<ContinuityArea> areas = new ArrayList<ContinuityArea>();
|
||||
for (int i = 0; i < preliminaryAreas.size(); i++) {
|
||||
Area a = preliminaryAreas.get(i);
|
||||
if (checkBreakout.get(i))
|
||||
areas.addAll(AreaUtils.tryAreaBreakout(a));
|
||||
else
|
||||
ContinuityArea a = preliminaryAreas.get(i);
|
||||
if (checkBreakout.get(i)) {
|
||||
List<Area> breakoutAreas = AreaUtils.tryAreaBreakout(a.getArea());
|
||||
if (breakoutAreas.size() == 1) {
|
||||
areas.add(a);
|
||||
} else {
|
||||
areas.addAll(breakoutAreas.stream()
|
||||
.map(area -> new ContinuityArea(a.getZIndex(), a.getLayerId(), area))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
} else
|
||||
areas.add(a);
|
||||
}
|
||||
|
||||
return areas;
|
||||
}
|
||||
|
||||
public ContinuityGraph getContinuityGraph(Project project) {
|
||||
public ContinuityGraph getContinuityGraph() {
|
||||
Set<Connection> connections = new HashSet<Connection>();
|
||||
for (IDIYComponent<?> c : project.getComponents()) {
|
||||
int z = 0;
|
||||
for (IDIYComponent<?> c : this.componentAreaMap.keySet()) {
|
||||
if (c instanceof IContinuity) {
|
||||
for (int i = 0; i < c.getControlPointCount() - 1; i++)
|
||||
for (int j = i + 1; j < c.getControlPointCount(); j++)
|
||||
if (((IContinuity) c).arePointsConnected(i, j))
|
||||
connections.add(new Connection(c.getControlPoint(i), c.getControlPoint(j)));
|
||||
connections.add(new Connection(c.getControlPoint(i), c.getControlPoint(j), z));
|
||||
}
|
||||
z++;
|
||||
}
|
||||
|
||||
List<Area> areas = getContinuityAreas(project);
|
||||
List<ContinuityArea> areas = getContinuityAreas();
|
||||
|
||||
return NetlistBuilder.buildContinuityGraph(areas, connections);
|
||||
}
|
||||
|
||||
public List<Area> getContinuityAreaProximity(Project project, float threshold) {
|
||||
List<Area> continuityAreas = getContinuityAreas(project);
|
||||
public List<Area> getContinuityAreaProximity(float threshold) {
|
||||
List<ContinuityArea> continuityAreas = getContinuityAreas();
|
||||
Stroke s = ObjectCache.getInstance().fetchBasicStroke(threshold - 1); // value eyeballed for
|
||||
// approx good results
|
||||
List<Area> expanded = continuityAreas.parallelStream()
|
||||
.map((a) -> new Area(s.createStrokedShape(a))).collect(Collectors.toList());
|
||||
.map((a) -> new Area(s.createStrokedShape(a.getArea()))).collect(Collectors.toList());
|
||||
List<Area> intersections = new ArrayList<Area>();
|
||||
for (int i = 0; i < expanded.size() - 1; i++) {
|
||||
for (int j = i + 1; j < expanded.size(); j++) {
|
||||
|
||||
@@ -104,6 +104,7 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
|
||||
private Shape lastShape;
|
||||
|
||||
private double zoom;
|
||||
private int zOrder;
|
||||
|
||||
/**
|
||||
* Creates a wrapper around specified {@link Graphics2D} object.
|
||||
@@ -127,22 +128,25 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
|
||||
|
||||
/**
|
||||
* Clears out the current area and caches canvas settings.
|
||||
*
|
||||
* @param zOrder
|
||||
*/
|
||||
public void startedDrawingComponent() {
|
||||
drawingComponent = true;
|
||||
currentArea = new Area();
|
||||
continuityPositiveAreas = new HashMap<String, Area>();
|
||||
continuityNegativeAreas = new HashMap<String, Area>();
|
||||
public void startedDrawingComponent(int zOrder) {
|
||||
this.zOrder = zOrder;
|
||||
this.drawingComponent = true;
|
||||
this.currentArea = new Area();
|
||||
this.continuityPositiveAreas = new HashMap<String, Area>();
|
||||
this.continuityNegativeAreas = new HashMap<String, Area>();
|
||||
// trackingStacks.clear();
|
||||
continuityMarker = null;
|
||||
originalStroke = canvasGraphics.getStroke();
|
||||
originalColor = canvasGraphics.getColor();
|
||||
originalTx = canvasGraphics.getTransform();
|
||||
originalComposite = canvasGraphics.getComposite();
|
||||
originalFont = canvasGraphics.getFont();
|
||||
currentTx = new AffineTransform();
|
||||
initialTx = canvasGraphics.getTransform();
|
||||
lastShape = null;
|
||||
this.continuityMarker = null;
|
||||
this.originalStroke = canvasGraphics.getStroke();
|
||||
this.originalColor = canvasGraphics.getColor();
|
||||
this.originalTx = canvasGraphics.getTransform();
|
||||
this.originalComposite = canvasGraphics.getComposite();
|
||||
this.originalFont = canvasGraphics.getFont();
|
||||
this.currentTx = new AffineTransform();
|
||||
this.initialTx = canvasGraphics.getTransform();
|
||||
this.lastShape = null;
|
||||
startTracking();
|
||||
}
|
||||
|
||||
@@ -159,7 +163,8 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
|
||||
canvasGraphics.setComposite(originalComposite);
|
||||
canvasGraphics.setFont(originalFont);
|
||||
// Map<String, Integer> sorted = sortByComparator(trackingStacks, false);
|
||||
return new ComponentArea(currentArea, new ArrayList<Area>(continuityPositiveAreas.values()), new ArrayList<Area>(continuityNegativeAreas.values()));
|
||||
return new ComponentArea(zOrder,currentArea, new ArrayList<Area>(continuityPositiveAreas.values()),
|
||||
new ArrayList<Area>(continuityNegativeAreas.values()));
|
||||
}
|
||||
|
||||
// start - used for caching
|
||||
|
||||
@@ -680,7 +680,7 @@ public class Presenter implements IPlugInPort {
|
||||
projectFileManager.notifyFileChange();
|
||||
}
|
||||
} else if (configManager.readBoolean(HIGHLIGHT_CONTINUITY_AREA, false) || altDown) {
|
||||
drawingManager.findContinuityAreaAtPoint(currentProject, scaledPoint);
|
||||
drawingManager.findContinuityAreaAtPoint(scaledPoint);
|
||||
messageDispatcher.dispatchMessage(EventType.REPAINT);
|
||||
} else {
|
||||
List<IDIYComponent<?>> newSelection = new ArrayList<IDIYComponent<?>>(selectedComponents);
|
||||
@@ -2809,7 +2809,7 @@ public class Presenter implements IPlugInPort {
|
||||
|
||||
@Override
|
||||
public List<Netlist> extractNetlists(boolean includeSwitches) throws NetlistException {
|
||||
List<Area> continuityAreas = drawingManager.getContinuityAreas(currentProject);
|
||||
List<ContinuityArea> continuityAreas = drawingManager.getContinuityAreas();
|
||||
|
||||
return NetlistBuilder.extractNetlists(includeSwitches, currentProject, continuityAreas);
|
||||
}
|
||||
@@ -2874,11 +2874,12 @@ public class Presenter implements IPlugInPort {
|
||||
ComponentArea componentArea = drawingManager.getComponentArea(c);
|
||||
areas.put(c, componentArea);
|
||||
}
|
||||
return new Snapshot(currentProject.clone(), new HashSet<IDIYComponent<?>>(selectedComponents), areas, new HashSet<Area>(drawingManager.getContinuityAreas(currentProject)));
|
||||
return new Snapshot(currentProject.clone(), new HashSet<IDIYComponent<?>>(selectedComponents), areas,
|
||||
new HashSet<ContinuityArea>(drawingManager.getContinuityAreas()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Area> checkContinuityAreaProximity(Size threshold) {
|
||||
return drawingManager.getContinuityAreaProximity(this.currentProject, (float)threshold.convertToPixels());
|
||||
return drawingManager.getContinuityAreaProximity((float)threshold.convertToPixels());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4158,6 +4158,10 @@
|
||||
<changeType>BUG_FIX</changeType>
|
||||
<description>Fixed an issue that would cause capacitors to fail when creating, editing, moving or deleting</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Circuit analysis algorithm that supports netlist extraction, 'Highlight connected Areas' and 'Guitar Wiring Analyzer' features improved to take PCB trace layer and component z-order into account for better accuracy</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>NEW_FEATURE</changeType>
|
||||
<description>Added standard models in the drop down menu of the component toolbar</description>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package org.diylc.test;
|
||||
|
||||
import java.awt.geom.Area;
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.presenter.ComponentArea;
|
||||
import org.diylc.presenter.ContinuityArea;
|
||||
|
||||
public class Snapshot implements Serializable {
|
||||
|
||||
@@ -15,13 +15,13 @@ public class Snapshot implements Serializable {
|
||||
private Project project;
|
||||
private Set<IDIYComponent<?>> selection;
|
||||
private Map<IDIYComponent<?>, ComponentArea> areas;
|
||||
private Set<Area> continuityAreas;
|
||||
private Set<ContinuityArea> continuityAreas;
|
||||
|
||||
public Snapshot() {
|
||||
}
|
||||
|
||||
public Snapshot(Project project, Set<IDIYComponent<?>> selection,
|
||||
Map<IDIYComponent<?>, ComponentArea> areas, Set<Area> continuityAreas) {
|
||||
Map<IDIYComponent<?>, ComponentArea> areas, Set<ContinuityArea> continuityAreas) {
|
||||
super();
|
||||
this.project = project;
|
||||
this.selection = selection;
|
||||
@@ -41,7 +41,7 @@ public class Snapshot implements Serializable {
|
||||
return areas;
|
||||
}
|
||||
|
||||
public Set<Area> getContinuityAreas() {
|
||||
public Set<ContinuityArea> getContinuityAreas() {
|
||||
return continuityAreas;
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
@@ -30,6 +30,7 @@ import org.diylc.components.transform.AbstractBoardTransformer;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
import org.diylc.core.ILayer;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.annotations.BomPolicy;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
@@ -44,7 +45,7 @@ import org.diylc.utils.Constants;
|
||||
zOrder = IDIYComponent.BOARD, instanceNamePrefix = "Board", description = "Perforated board with solder pads",
|
||||
bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false, keywordPolicy = KeywordPolicy.SHOW_TAG,
|
||||
keywordTag = "Perf Board", transformer = AbstractBoardTransformer.class, enableCache = true)
|
||||
public class PerfBoard extends AbstractBoard {
|
||||
public class PerfBoard extends AbstractBoard implements ILayer {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -121,6 +122,11 @@ public class PerfBoard extends AbstractBoard {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLayerId() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawIcon(Graphics2D g2d, int width, int height) {
|
||||
int factor = 32 / width;
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.diylc.components.transform.VeroBoardTransformer;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
import org.diylc.core.ILayer;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
import org.diylc.core.annotations.EditableProperty;
|
||||
@@ -41,7 +42,7 @@ import org.diylc.utils.Constants;
|
||||
instanceNamePrefix = "Board",
|
||||
description = "Perforated FR4 board with copper strips connecting 3 holes in a row (aka TriPad Board)",
|
||||
keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, transformer = VeroBoardTransformer.class, enableCache = true)
|
||||
public class TriPadBoard extends AbstractVeroBoard {
|
||||
public class TriPadBoard extends AbstractVeroBoard implements ILayer {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -203,4 +204,9 @@ public class TriPadBoard extends AbstractVeroBoard {
|
||||
public String getControlPointNodeName(int index) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLayerId() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.diylc.components.transform.VeroBoardTransformer;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
import org.diylc.core.ILayer;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.annotations.BomPolicy;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
@@ -42,7 +43,7 @@ import org.diylc.utils.Constants;
|
||||
description = "Perforated FR4 board with copper strips connecting all holes in a row",
|
||||
bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false, keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME,
|
||||
transformer = VeroBoardTransformer.class, enableCache = true)
|
||||
public class VeroBoard extends AbstractVeroBoard {
|
||||
public class VeroBoard extends AbstractVeroBoard implements ILayer {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -110,7 +111,10 @@ public class VeroBoard extends AbstractVeroBoard {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getLayerId() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.diylc.components.transform.SimpleComponentTransformer;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.CreationMethod;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.ILayer;
|
||||
import org.diylc.core.VisibilityPolicy;
|
||||
import org.diylc.core.annotations.BomPolicy;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
@@ -40,7 +41,7 @@ import org.diylc.core.measures.SizeUnit;
|
||||
description = "Straight copper trace", zOrder = IDIYComponent.TRACE, bomPolicy = BomPolicy.NEVER_SHOW,
|
||||
autoEdit = false, keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "PCB",
|
||||
transformer = SimpleComponentTransformer.class)
|
||||
public class CopperTrace extends AbstractLeadedComponent<Void> {
|
||||
public class CopperTrace extends AbstractLeadedComponent<Void> implements ILayer {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -100,6 +101,11 @@ public class CopperTrace extends AbstractLeadedComponent<Void> {
|
||||
this.layer = layer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLayerId() {
|
||||
return getLayer().getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getLeadThickness() {
|
||||
return (float) getThickness().convertToPixels();
|
||||
|
||||
@@ -28,6 +28,7 @@ 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.ILayer;
|
||||
import org.diylc.core.annotations.BomPolicy;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
import org.diylc.core.annotations.EditableProperty;
|
||||
@@ -40,7 +41,7 @@ import org.diylc.core.measures.SizeUnit;
|
||||
zOrder = IDIYComponent.TRACE, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
|
||||
keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "PCB", transformer = SimpleComponentTransformer.class,
|
||||
enableCache = true)
|
||||
public class CurvedTrace extends AbstractCurvedComponent<Void> {
|
||||
public class CurvedTrace extends AbstractCurvedComponent<Void> implements ILayer {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -89,6 +90,11 @@ public class CurvedTrace extends AbstractCurvedComponent<Void> {
|
||||
this.layer = layer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLayerId() {
|
||||
return getLayer().getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void getValue() {
|
||||
return null;
|
||||
|
||||
@@ -32,6 +32,7 @@ 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.ILayer;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.VisibilityPolicy;
|
||||
import org.diylc.core.annotations.BomPolicy;
|
||||
@@ -43,7 +44,7 @@ import org.diylc.core.measures.SizeUnit;
|
||||
@ComponentDescriptor(name = "Ground Fill", author = "Branislav Stojkovic", category = "Connectivity",
|
||||
instanceNamePrefix = "GF", description = "Polygonal ground fill area", zOrder = IDIYComponent.TRACE,
|
||||
bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, transformer = SimpleComponentTransformer.class)
|
||||
public class GroundFill extends AbstractComponent<Void> {
|
||||
public class GroundFill extends AbstractComponent<Void> implements ILayer {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -149,6 +150,10 @@ public class GroundFill extends AbstractComponent<Void> {
|
||||
this.layer = layer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLayerId() {
|
||||
return getLayer().getId();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
|
||||
@@ -28,6 +28,7 @@ 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.ILayer;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.VisibilityPolicy;
|
||||
import org.diylc.core.annotations.BomPolicy;
|
||||
@@ -44,7 +45,7 @@ import org.diylc.utils.Constants;
|
||||
description = "Copper solder pad, round or square", instanceNamePrefix = "Pad",
|
||||
zOrder = IDIYComponent.TRACE + 0.1, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
|
||||
keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "PCB", transformer = SimpleComponentTransformer.class, enableCache = true)
|
||||
public class SolderPad extends AbstractComponent<Void> {
|
||||
public class SolderPad extends AbstractComponent<Void> implements ILayer {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -129,6 +130,11 @@ public class SolderPad extends AbstractComponent<Void> {
|
||||
this.layer = layer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLayerId() {
|
||||
return getLayer().getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return super.getName();
|
||||
|
||||
@@ -93,7 +93,7 @@ public class SpiceAnalyzer extends NetlistAnalyzer implements INetlistAnalyzer {
|
||||
if (c instanceof ISpiceMapper)
|
||||
pointIndex = ((ISpiceMapper)c).mapToSpiceNode(pointIndex);
|
||||
|
||||
int nodeIndex = find(new Node(c, pointIndex), groups);
|
||||
int nodeIndex = find(new Node(c, pointIndex, 0), groups);
|
||||
if (nodeIndex < 0)
|
||||
nodeIndex = unconnectedIndex++;
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user