diff --git a/diylc/diylc-core/src/main/java/org/diylc/netlist/NetlistAnalyzer.java b/diylc/diylc-core/src/main/java/org/diylc/netlist/NetlistAnalyzer.java index 0ccd8c2d..64fd22f3 100644 --- a/diylc/diylc-core/src/main/java/org/diylc/netlist/NetlistAnalyzer.java +++ b/diylc/diylc-core/src/main/java/org/diylc/netlist/NetlistAnalyzer.java @@ -1,381 +1,281 @@ -/* - * - * 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 - * . - */ -package org.diylc.netlist; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.diylc.core.IDIYComponent; - -public abstract class NetlistAnalyzer { - - public NetlistAnalyzer() {} - - public List summarize(List netlists, Node preferredOutput) throws TreeException { - Map summaries = new HashMap(); - for (Netlist n : netlists) { - Summary s = summarize(n, preferredOutput); - if (summaries.containsKey(s.getSummary())) - summaries.get(s.getSummary()).append(n); - else - summaries.put(s.getSummary(), s); - } - - List res = new ArrayList(summaries.values()); - Collections.sort(res); - return res; - } - - protected abstract Summary summarize(Netlist netlist, Node preferredOutput) throws TreeException; - - public Tree constructTreeBetween(Netlist netlist, Node nodeA, Node nodeB) { - Tree tree = new Tree(TreeConnectionType.Parallel); - connectNodes(netlist, nodeA, nodeB, tree.getChildren(), new Tree(TreeConnectionType.Series), new HashSet()); - - return tree; - } - -// protected Tree removeRedundantElements(Tree tree) { -// List children = tree.getChildren() -// .stream() -// .map(t -> removeRedundantElements(t)) -// .collect(Collectors.toList()); -// if (children.size() == 1) { -// Tree first = children.get(0); -// return first; -// } -// } - - protected void connectNodes(Netlist netlist, Node nodeA, Node nodeB, List concurrentPaths, Tree currentPath, - Set visited) { - if (nodeA == nodeB) { - concurrentPaths.add(currentPath); - return; - } - - Group groupA = findGroup(netlist, nodeA); - - if (groupA == null) - return; - - if (groupA.getNodes().contains(nodeB)) { - concurrentPaths.add(currentPath); - return; - } - - // Only mark the current node as visited to allow proper path exploration - visited.add(nodeA); - - List newConcurrentPaths = new ArrayList(); - - // Track processed connections to prevent duplicates from bidirectional links - Set processedConnections = new HashSet(); - - for (Node n : groupA.getNodes()) { - IDIYComponent c = n.getComponent(); - for (int i = 0; i < c.getControlPointCount(); i++) { - int targetPoint = i; - int sourcePoint = n.getPointIndex(); - - // Skip self-connections - if (targetPoint == sourcePoint) continue; - - // Check if there's a connection between these points - if (c.getInternalLinkName(targetPoint, sourcePoint) != null) { - // Create a unique identifier for this connection regardless of direction - String connectionId = c.getName() + "_" + - Math.min(sourcePoint, targetPoint) + "_" + - Math.max(sourcePoint, targetPoint); - - // Skip if we've already processed this connection (prevents duplicate branches) - if (processedConnections.contains(connectionId)) continue; - processedConnections.add(connectionId); - TreeLeaf l = new TreeLeaf(c, targetPoint, sourcePoint); - Node newNodeA = new Node(c, targetPoint, n.getZIndex()); - if (!visited.contains(newNodeA)) { - // visited.add(n); - Tree newCurrentPath = null; - try { - newCurrentPath = (Tree) currentPath.clone(); - } catch (CloneNotSupportedException e) { - } - Tree newItem = new Tree(l); - if (!newCurrentPath.getChildren().contains(newItem)) - newCurrentPath.getChildren().add(newItem); - // if (!currentPath.contains(l)) - // newCurrentPath.add(l); - Set newVisited = new HashSet(visited); - connectNodes(netlist, newNodeA, nodeB, newConcurrentPaths, newCurrentPath, newVisited); - } - } - } - } - - if (newConcurrentPaths.size() == 0) - return; - - if (newConcurrentPaths.size() == 1) { - if (newConcurrentPaths.get(0).getConnectionType() == TreeConnectionType.Series) { - currentPath.getChildren().clear(); - currentPath.getChildren().addAll(newConcurrentPaths.get(0).getChildren()); - } else { - currentPath.getChildren().add(newConcurrentPaths.get(0)); - } - concurrentPaths.add(currentPath); - return; - } - - mergePaths(newConcurrentPaths, false); - concurrentPaths.addAll(newConcurrentPaths); - } - - /** - * Merges paths that share common elements, taking into account bidirectional connections. - * - * @param paths List of paths to merge - * @param backward Direction for merging (forward/backward) - */ - protected void mergePaths(List paths, boolean backward) { - // Skip if there are no paths or only one path - if (paths == null || paths.size() <= 1) { - return; - } - Map uniques = new HashMap(); - for (Tree t : paths) { - if (t.getConnectionType() != TreeConnectionType.Series) - continue; - Tree key = t.getChildren().get(backward ? t.getChildren().size() - 1 : 0); - Integer count = uniques.get(key); - uniques.put(key, count == null ? 1 : count + 1); - } - - List unmerged = new ArrayList(paths); - - for (Map.Entry e : uniques.entrySet()) { - if (e.getValue() > 1) { - List pathsToMerge = new ArrayList(); - for (Tree t : paths) { - Tree key = t.getChildren().get(backward ? t.getChildren().size() - 1 : 0); - if (key.equals(e.getKey())) - pathsToMerge.add(t); - } - unmerged.removeAll(pathsToMerge); - - Tree jointStart = new Tree(new ArrayList(), TreeConnectionType.Series); - Tree jointFinish = new Tree(new ArrayList(), TreeConnectionType.Series); - - Tree unique = e.getKey(); - - for (int i = 0; i < pathsToMerge.get(0).getChildren().size(); i++) { - boolean canMerge = true; - unique = pathsToMerge.get(0).getChildren().get(backward ? pathsToMerge.get(0).getChildren().size() - i - 1 : i); - for (Tree t : pathsToMerge) { - if (t.getChildren().size() <= i || !t.getChildren().get(backward ? t.getChildren().size() - i - 1 : i).equals(unique)) { - canMerge = false; - break; - } - } - if (canMerge) - (backward ? jointFinish : jointStart).getChildren().add(unique); - else - break; - } - - for (int i = 0; i < pathsToMerge.get(0).getChildren().size(); i++) { - boolean canMerge = true; - unique = pathsToMerge.get(0).getChildren().get(backward ? i : pathsToMerge.get(0).getChildren().size() - i - 1); - for (Tree t : pathsToMerge) { - // Fix: Correct index calculation to check the proper element in each path - if (t.getChildren().size() <= i || !t.getChildren().get(backward ? i : t.getChildren().size() - i - 1).equals(unique)) { - canMerge = false; - break; - } - } - if (canMerge) - (backward ? jointStart : jointFinish).getChildren().add(unique); - else - break; - } - - if (!jointStart.getChildren().isEmpty() || !jointFinish.getChildren().isEmpty()) { - Tree mergedTree = new Tree(new ArrayList(), TreeConnectionType.Series); - Tree parallelSection = new Tree(new ArrayList(pathsToMerge), TreeConnectionType.Parallel); - if (!jointStart.getChildren().isEmpty()) { - mergedTree.getChildren().add(jointStart); - for (Tree t : parallelSection.getChildren()) { - t.trimChildrenLeft(jointStart.getChildren().size()); - } - } - mergedTree.getChildren().add(parallelSection); - if (!jointFinish.getChildren().isEmpty()) { - mergedTree.getChildren().add(jointFinish); - for (Tree t : parallelSection.getChildren()) { - t.trimChildrenRight(jointFinish.getChildren().size()); - } - } - paths.removeAll(pathsToMerge); - paths.add(mergedTree); - } - } - } - - // try in the opposite direction for paths we haven't merged - if (!backward && !unmerged.isEmpty()) { - paths.removeAll(unmerged); - mergePaths(unmerged, true); - paths.addAll(unmerged); - } - } - - /** - * Creates a unique identifier for a connection between two points - * that is the same regardless of the direction of connection. - * This helps prevent duplicate paths in bidirectional connections. - * - * @param component The component containing the connection - * @param point1 First point index - * @param point2 Second point index - * @return A direction-agnostic connection identifier - */ - protected String createBidirectionalConnectionId(IDIYComponent component, int point1, int point2) { - if (component == null) return null; - - // Always use min/max to ensure the same ID regardless of direction - int minPoint = Math.min(point1, point2); - int maxPoint = Math.max(point1, point2); - - return component.getName() + "_" + minPoint + "_" + maxPoint; - } - - /** - * Compares two tree paths to check if they represent the same physical connection path - * but possibly in reverse directions. This helps identify paths that should be merged - * due to bidirectional connections. - * - * @param path1 First path to compare - * @param path2 Second path to compare - * @return true if the paths represent the same physical connection (possibly in reverse order) - */ - protected boolean arePathsEquivalent(Tree path1, Tree path2) { - if (path1 == null || path2 == null) return false; - if (path1 == path2) return true; - - // Different connection types can't be equivalent - if (path1.getConnectionType() != path2.getConnectionType()) return false; - - // Must have same number of elements - List children1 = path1.getChildren(); - List children2 = path2.getChildren(); - if (children1.size() != children2.size()) return false; - - // Simple path with no children - if (children1.isEmpty()) return true; - - // Check forward direction (standard comparison) - boolean forwardMatch = true; - for (int i = 0; i < children1.size(); i++) { - if (!children1.get(i).equals(children2.get(i))) { - forwardMatch = false; - break; - } - } - - if (forwardMatch) return true; - - // Check reverse direction (bidirectional check) - boolean reverseMatch = true; - for (int i = 0; i < children1.size(); i++) { - if (!children1.get(i).equals(children2.get(children2.size() - 1 - i))) { - reverseMatch = false; - break; - } - } - - return reverseMatch; - } - - protected Group findGroup(Netlist netlist, Node node) { - for (Group g : netlist.getGroups()) - if (g.getNodes().contains(node)) - return g; - return null; - } - - protected List find(Set typeNames, String nodeName, Netlist netlist) { - List res = new ArrayList(); - for (Group g : netlist.getGroups()) { - for (Node n : g.getNodes()) { - if (typeNames.contains(n.getComponent().getClass().getCanonicalName()) - && (nodeName == null || n.getDisplayName().equalsIgnoreCase(nodeName))) { - res.add(n); - } - } - } - return res; - } - - protected String extractName(IDIYComponent c) { - return c.getName() + " " + (c.getValueForDisplay() == null ? "" : c.getValueForDisplay()); - } - - public static List>> extractComponentGroups(List netlists) { - List>> res = new ArrayList>>(); - for (Netlist n : netlists) { - res.addAll(extractComponentGroups(n)); - } - return res; - } - - public static List>> extractComponentGroups(Netlist netlist) { - List>> res = new ArrayList>>(); - for (Group g : netlist.getGroups()) { - Set> components = new HashSet>(); - for (Node n : g.getNodes()) - components.add(n.getComponent()); - res.add(components); - } - return res; - } - - protected int find(Node node, List groups) { - for (int i = 0; i < groups.size(); i++) - if (groups.get(i).getNodes().contains(node)) - return i; - return -1; - } - - protected boolean intersect(List groups, Node node) { - for (Group g : groups) - if (g.getNodes().contains(node)) - return true; - return false; - } - - protected Node intersect(List groups, Group group) { - for (Group g : groups) - for (Node node : group.getNodes()) - if (g.getNodes().contains(node)) - return node; - return null; - } -} +/* + * + * 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 + * . + */ +package org.diylc.netlist; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.diylc.core.IDIYComponent; + +public abstract class NetlistAnalyzer { + + public NetlistAnalyzer() { + } + + public List summarize(List netlists, Node preferredOutput) + throws TreeException { + Map summaries = new HashMap(); + for (Netlist n : netlists) { + Summary s = summarize(n, preferredOutput); + if (summaries.containsKey(s.getSummary())) + summaries.get(s.getSummary()).append(n); + else + summaries.put(s.getSummary(), s); + } + + List res = new ArrayList(summaries.values()); + Collections.sort(res); + return res; + } + + protected abstract Summary summarize(Netlist netlist, Node preferredOutput) throws TreeException; + + public Tree constructTreeBetween(Netlist netlist, Node nodeA, Node nodeB) { + Tree tree = new Tree(TreeConnectionType.Parallel); + connectNodes(netlist, nodeA, nodeB, tree.getChildren(), new Tree(TreeConnectionType.Series), + new HashSet()); + + return tree; + } + + protected void connectNodes(Netlist netlist, Node nodeA, Node nodeB, List concurrentPaths, + Tree currentPath, Set visited) { + if (nodeA == nodeB) { + concurrentPaths.add(currentPath); + return; + } + + Group groupA = findGroup(netlist, nodeA); + if (groupA == null) + return; + + if (groupA.getNodes().contains(nodeB)) { + concurrentPaths.add(currentPath); + return; + } + + Set pathVisited = new HashSet<>(visited); + pathVisited.add(nodeA); + + // First collect all immediate next nodes and their paths + Map> nextNodes = new HashMap<>(); + for (Node n : groupA.getNodes()) { + if (pathVisited.contains(n)) + continue; + + IDIYComponent c = n.getComponent(); + for (int i = 0; i < c.getControlPointCount(); i++) { + int targetPoint = i; + int sourcePoint = n.getPointIndex(); + + if (targetPoint == sourcePoint) + continue; + + if (c.getInternalLinkName(targetPoint, sourcePoint) != null) { + Node newNodeA = new Node(c, targetPoint, n.getZIndex()); + if (pathVisited.contains(newNodeA)) + continue; + + try { + Tree newPath = (Tree) currentPath.clone(); + TreeLeaf leaf = new TreeLeaf(c, targetPoint, sourcePoint); + Tree newItem = new Tree(leaf); + + if (!newPath.getChildren().contains(newItem)) { + newPath.getChildren().add(newItem); + nextNodes.computeIfAbsent(newNodeA, k -> new ArrayList<>()).add(newPath); + } + } catch (CloneNotSupportedException e) { + // Skip this path if clone fails + } + } + } + } + + // Now explore each next node + List allPaths = new ArrayList<>(); + for (Map.Entry> entry : nextNodes.entrySet()) { + for (Tree path : entry.getValue()) { + List branchPaths = new ArrayList<>(); + connectNodes(netlist, entry.getKey(), nodeB, branchPaths, path, pathVisited); + allPaths.addAll(branchPaths); + } + } + + if (allPaths.isEmpty()) + return; + + if (allPaths.size() > 1) { + // Find common prefix among all paths + List commonPrefix = findCommonElements(allPaths, true, false); + + // Create a new tree for the merged result + Tree mergedTree = new Tree(TreeConnectionType.Series); + + // Add common prefix elements + for (Tree prefixElement : commonPrefix) { + mergedTree.getChildren().add(prefixElement); + } + + // Extract unique parts + List uniqueParts = new ArrayList<>(); + for (Tree path : allPaths) { + Tree uniquePart = extractUniquePart(path, commonPrefix.size(), 0); + if (uniquePart != null) { + if (uniquePart.getChildren().size() == 1) { + uniqueParts.add(uniquePart.getChildren().get(0)); + } else { + uniqueParts.add(uniquePart); + } + } + } + + // Create parallel section for unique parts + if (!uniqueParts.isEmpty()) { + Tree parallelSection = new Tree(TreeConnectionType.Parallel); + parallelSection.getChildren().addAll(uniqueParts); + + // Add parallel section to series container + Tree parallelContainer = new Tree(TreeConnectionType.Series); + parallelContainer.getChildren().add(parallelSection); + mergedTree.getChildren().add(parallelContainer); + } + + concurrentPaths.add(mergedTree); + } else { + concurrentPaths.add(allPaths.get(0)); + } + } + + private List findCommonElements(List paths, boolean fromStart, boolean backward) { + if (paths.isEmpty()) + return new ArrayList<>(); + + List common = new ArrayList<>(); + Tree template = paths.get(0); + int maxLength = template.getChildren().size(); + + for (int i = 0; i < maxLength; i++) { + int index = fromStart ? + (backward ? template.getChildren().size() - i - 1 : i) : + (backward ? i : template.getChildren().size() - i - 1); + + if (index < 0 || index >= template.getChildren().size()) + break; + + Tree element = template.getChildren().get(index); + boolean isCommon = true; + + for (int j = 1; j < paths.size(); j++) { + Tree current = paths.get(j); + if (current.getChildren().size() <= i || index >= current.getChildren() + .size() || !current.getChildren().get(index).equals(element)) { + isCommon = false; + break; + } + } + + if (isCommon) { + common.add(element); + } else { + break; + } + } + + return common; + } + + private Tree extractUniquePart(Tree path, int prefixSize, int suffixSize) { + if (path.getChildren().size() <= prefixSize + suffixSize) + return null; + + Tree uniquePart = new Tree(TreeConnectionType.Series); + for (int i = prefixSize; i < path.getChildren().size() - suffixSize; i++) { + uniquePart.getChildren().add(path.getChildren().get(i)); + } + + return uniquePart.getChildren().isEmpty() ? null : uniquePart; + } + + protected Group findGroup(Netlist netlist, Node node) { + for (Group g : netlist.getGroups()) + if (g.getNodes().contains(node)) + return g; + return null; + } + + protected List find(Set typeNames, String nodeName, Netlist netlist) { + List res = new ArrayList(); + for (Group g : netlist.getGroups()) { + for (Node n : g.getNodes()) { + if (typeNames.contains(n.getComponent().getClass() + .getCanonicalName()) && (nodeName == null || n.getDisplayName() + .equalsIgnoreCase(nodeName))) { + res.add(n); + } + } + } + return res; + } + + public static List>> extractComponentGroups(List netlists) { + List>> res = new ArrayList>>(); + for (Netlist n : netlists) { + res.addAll(extractComponentGroups(n)); + } + return res; + } + + public static List>> extractComponentGroups(Netlist netlist) { + List>> res = new ArrayList>>(); + for (Group g : netlist.getGroups()) { + Set> components = new HashSet>(); + for (Node n : g.getNodes()) + components.add(n.getComponent()); + res.add(components); + } + return res; + } + + protected int find(Node node, List groups) { + for (int i = 0; i < groups.size(); i++) + if (groups.get(i).getNodes().contains(node)) + return i; + return -1; + } + + protected boolean intersect(List groups, Node node) { + for (Group g : groups) + if (g.getNodes().contains(node)) + return true; + return false; + } + + protected Node intersect(List groups, Group group) { + for (Group g : groups) + for (Node node : group.getNodes()) + if (g.getNodes().contains(node)) + return node; + return null; + } +} diff --git a/diylc/diylc-core/src/main/java/org/diylc/netlist/Tree.java b/diylc/diylc-core/src/main/java/org/diylc/netlist/Tree.java index f9ee373a..71cebbd5 100644 --- a/diylc/diylc-core/src/main/java/org/diylc/netlist/Tree.java +++ b/diylc/diylc-core/src/main/java/org/diylc/netlist/Tree.java @@ -1,332 +1,343 @@ -/* - - 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 . - -*/ -package org.diylc.netlist; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import org.diylc.core.IDIYComponent; - -public class Tree { - - private List children; - private TreeConnectionType connectionType; - private TreeLeaf leaf; - - public Tree(TreeConnectionType connectionType) { - this.children = new ArrayList(); - this.connectionType = connectionType; - } - - public Tree(TreeLeaf leaf) { - this.leaf = leaf; - } - - public Tree(List children, TreeConnectionType connectionType) { - this.children = children; - this.connectionType = connectionType; - } - - public List getChildren() { - return children; - } - - public void trimChildrenLeft(int count) { - children = children.subList(count, children.size()); - } - - public void trimChildrenRight(int count) { - children = children.subList(0, children.size() - count); - } - - public TreeConnectionType getConnectionType() { - return connectionType; - } - - public TreeLeaf getLeaf() { - return leaf; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((children == null) ? 0 : children.hashCode()); - result = prime * result + ((connectionType == null) ? 0 : connectionType.hashCode()); - result = prime * result + ((leaf == null) ? 0 : leaf.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Tree other = (Tree) obj; - if (children == null) { - if (other.children != null) - return false; - } else if (!children.equals(other.children)) - return false; - if (connectionType != other.connectionType) - return false; - if (leaf == null) { - if (other.leaf != null) - return false; - } else if (!leaf.equals(other.leaf)) - return false; - return true; - } - - private List getOrderedChildren() { - if (getConnectionType() == TreeConnectionType.Series) - return children; - List ordered = new ArrayList(children); - Collections.sort(ordered, new Comparator() { - - @Override - public int compare(Tree o1, Tree o2) { - return o1.toString().compareToIgnoreCase(o2.toString()); - }}); - return ordered; - } - - @Override - public String toString() { - if (leaf != null) - return leaf.toString(); - - StringBuilder sb = new StringBuilder("("); - boolean first = true; - for(Tree child : getOrderedChildren()) { - if (!first) - sb.append(" " ).append(connectionType).append(" "); - first = false; - sb.append(child); - } - sb.append(")"); - return sb.toString(); - } - - public String toHTML(int depth) { - if (leaf != null) - return leaf.toHTML(); - - List children = getOrderedChildren(); - - StringBuilder sb = new StringBuilder(); - if (depth > 0 && children.size() > 1) - sb.append("("); - boolean first = true; - for(Tree child : children) { - if (!first) { - sb.append(" ").append(connectionType.toHTML()).append(" "); - if (depth == 0) - sb.append("
"); - } - first = false; - sb.append(child.toHTML(depth + children.size() > 1 ? 1 : 0)); - } - if (depth > 0 && children.size() > 1) - sb.append(")"); - return sb.toString(); - } - - public String toAsciiString() { - return String.join("
", toAscii()); - } - - private List toAscii() { - if (leaf != null) { - return Arrays.asList(TreeAsciiUtil.generateString(TreeAsciiUtil.BOXH, 1) + " " + leaf.toHTML() + " " + TreeAsciiUtil.generateString(TreeAsciiUtil.BOXH, 1)); - } - - List children = getOrderedChildren(); - - List> childrenAscii = - children.stream().map(c -> c.toAscii()).collect(Collectors.toList()); - - if (TreeConnectionType.Series.equals(connectionType)) { - return TreeAsciiUtil.concatenateMultiLineSerial(TreeAsciiUtil.generateString(TreeAsciiUtil.BOXH, 1), childrenAscii); - } else { - return TreeAsciiUtil.concatenateMultiLineParallel(childrenAscii); - } - } - - @Override - protected Object clone() throws CloneNotSupportedException { - if (leaf != null) - return new Tree(leaf); - List newChildren = new ArrayList(); - for (Tree t : children) - newChildren.add((Tree) t.clone()); - return new Tree(newChildren, connectionType); - } - - public Tree filter(Set types) { - if (leaf != null) { - if (types.contains(leaf.getComponent().getClass().getCanonicalName())) - return new Tree(leaf); - return null; - } - List newChildren = new ArrayList(); - for (Tree t : children) { - Tree child = t.filter(types); - if (child != null) - newChildren.add(child); - } - if (newChildren.isEmpty()) - return null; - return new Tree(newChildren, connectionType); - } - - public void walk(ITreeWalker walker) { - if (leaf != null) { - walker.visit(leaf); - } else { - for (Tree t : children) { - walker.visit(t); - t.walk(walker); - } - } - } - - public Set> extractComponents(Set types) { - Set> res = new HashSet>(); - if (leaf != null && types.contains(leaf.getComponent().getClass().getCanonicalName())) { - res.add(leaf.getComponent()); - } else if (children != null) { - for (Tree t : children) { - Set> childRes = t.extractComponents(types); - if (childRes != null) - res.addAll(childRes); - } - } - return res; - } - - public Tree locate(TreeLeaf l, boolean forceDirection) { - if (leaf != null && leaf.equals(l, forceDirection)) - return this; - if (children != null) { - for (Tree t : children) { - Tree childL = t.locate(l, forceDirection); - if (childL != null) { -// if (t.getLeaf() != null) -// return this; - return childL; - } - } - } - return null; - } - - public Tree findCommonParent(Tree t1, Tree t2) { - if (t1 == null) - return t2; - if (t2 == null) - return t1; - - if (children == null) - return null; - - if (!this.contains(t1) || !this.contains(t2)) - return null; - - Tree p1 = this; - Tree p2 = this; - for (Tree c : children) { - if (c.contains(t1)) - p1 = c; - if (c.contains(t2)) - p2 = c; - } - - if (p1 != p2 || p1 == this || p2 == this) - return this; - - return p1.findCommonParent(t1, t2); - } - - public Tree findCommonParent(List t) { - if (t.contains(null)) - { - while(t.contains(null)) - t.remove(null); - return findCommonParent(t); - } - - if (t.size() == 0) - return null; - if (t.size() == 1) - return t.get(0); - if (t.size() == 2) - return findCommonParent(t.get(0), t.get(1)); - - List remainder = t.subList(1, t.size()); - return findCommonParent(t.get(0), findCommonParent(remainder)); - } - - public Tree findParent(Tree t) { - if (children == null) - return null; - if (children.contains(t)) - return this; - for (Tree c : children) - { - Tree p = c.findParent(t); - if (p != null) - return p; - } - return null; - } - - public boolean contains(Tree t) { - if (this == t) - return true; - - if (children == null) - return false; - if (children.contains(t)) - return true; - for (Tree c : children) - if (c.contains(t)) - return true; - return false; - } - - public interface ITreeWalker { - - void visit(Tree t); - - void visit(TreeLeaf l); - } -} +/* + + 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 . + +*/ +package org.diylc.netlist; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import org.diylc.core.IDIYComponent; + +public class Tree { + + private List children; + private TreeConnectionType connectionType; + private TreeLeaf leaf; + + public Tree(TreeConnectionType connectionType) { + this.children = new ArrayList(); + this.connectionType = connectionType; + } + + public Tree(TreeLeaf leaf) { + this.leaf = leaf; + } + + public Tree(List children, TreeConnectionType connectionType) { + this.children = children; + this.connectionType = connectionType; + } + + public List getChildren() { + return children; + } + + public void trimChildrenLeft(int count) { + children = children.subList(count, children.size()); + } + + public void trimChildrenRight(int count) { + children = children.subList(0, children.size() - count); + } + + public TreeConnectionType getConnectionType() { + return connectionType; + } + + public TreeLeaf getLeaf() { + return leaf; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((children == null) ? 0 : children.hashCode()); + result = prime * result + ((connectionType == null) ? 0 : connectionType.hashCode()); + result = prime * result + ((leaf == null) ? 0 : leaf.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Tree other = (Tree) obj; + if (children == null) { + if (other.children != null) + return false; + } else if (!children.equals(other.children)) + return false; + if (connectionType != other.connectionType) + return false; + if (leaf == null) { + if (other.leaf != null) + return false; + } else if (!leaf.equals(other.leaf)) + return false; + return true; + } + + private List getOrderedChildren() { + if (getConnectionType() == TreeConnectionType.Series) + return children; + List ordered = new ArrayList(children); + Collections.sort(ordered, new Comparator() { + + @Override + public int compare(Tree o1, Tree o2) { + return o1.toString().compareToIgnoreCase(o2.toString()); + } + }); + return ordered; + } + + @Override + public String toString() { + if (leaf != null) + return leaf.toString(); + + // If we only have one child, no need for parentheses + if (children.size() == 1) + return children.get(0).toString(); + + StringBuilder sb = new StringBuilder("("); + boolean first = true; + for (Tree child : getOrderedChildren()) { + if (!first) + sb.append(" ").append(connectionType).append(" "); + first = false; + // Only include child's parentheses if it has multiple children with a different connection type + String childStr = child.toString(); + if (child.children != null && child.children.size() > 1 && child.connectionType != connectionType) { + sb.append(childStr); + } else { + sb.append(childStr.replaceAll("^\\((.*)\\)$", "$1")); + } + } + sb.append(")"); + return sb.toString(); + } + + public String toHTML(int depth) { + if (leaf != null) + return leaf.toHTML(); + + List children = getOrderedChildren(); + + StringBuilder sb = new StringBuilder(); + if (depth > 0 && children.size() > 1) + sb.append("("); + boolean first = true; + for (Tree child : children) { + if (!first) { + sb.append(" ").append(connectionType.toHTML()).append(" "); + if (depth == 0) + sb.append("
"); + } + first = false; + sb.append(child.toHTML(depth + children.size() > 1 ? 1 : 0)); + } + if (depth > 0 && children.size() > 1) + sb.append(")"); + return sb.toString(); + } + + public String toAsciiString() { + return String.join("
", toAscii()); + } + + private List toAscii() { + if (leaf != null) { + return Arrays.asList(TreeAsciiUtil.generateString(TreeAsciiUtil.BOXH, + 1) + " " + leaf.toHTML() + " " + TreeAsciiUtil.generateString(TreeAsciiUtil.BOXH, 1)); + } + + List children = getOrderedChildren(); + + List> childrenAscii = + children.stream().map(c -> c.toAscii()).collect(Collectors.toList()); + + if (TreeConnectionType.Series.equals(connectionType)) { + return TreeAsciiUtil.concatenateMultiLineSerial( + TreeAsciiUtil.generateString(TreeAsciiUtil.BOXH, 1), childrenAscii); + } else { + return TreeAsciiUtil.concatenateMultiLineParallel(childrenAscii); + } + } + + @Override + protected Object clone() throws CloneNotSupportedException { + if (leaf != null) + return new Tree(leaf); + List newChildren = new ArrayList(); + for (Tree t : children) + newChildren.add((Tree) t.clone()); + return new Tree(newChildren, connectionType); + } + + public Tree filter(Set types) { + if (leaf != null) { + if (types.contains(leaf.getComponent().getClass().getCanonicalName())) + return new Tree(leaf); + return null; + } + List newChildren = new ArrayList(); + for (Tree t : children) { + Tree child = t.filter(types); + if (child != null) + newChildren.add(child); + } + if (newChildren.isEmpty()) + return null; + return new Tree(newChildren, connectionType); + } + + public void walk(ITreeWalker walker) { + if (leaf != null) { + walker.visit(leaf); + } else { + for (Tree t : children) { + walker.visit(t); + t.walk(walker); + } + } + } + + public Set> extractComponents(Set types) { + Set> res = new HashSet>(); + if (leaf != null && types.contains(leaf.getComponent().getClass().getCanonicalName())) { + res.add(leaf.getComponent()); + } else if (children != null) { + for (Tree t : children) { + Set> childRes = t.extractComponents(types); + if (childRes != null) + res.addAll(childRes); + } + } + return res; + } + + public Tree locate(TreeLeaf l, boolean forceDirection) { + if (leaf != null && leaf.equals(l, forceDirection)) + return this; + if (children != null) { + for (Tree t : children) { + Tree childL = t.locate(l, forceDirection); + if (childL != null) { + // if (t.getLeaf() != null) + // return this; + return childL; + } + } + } + return null; + } + + public Tree findCommonParent(Tree t1, Tree t2) { + if (t1 == null) + return t2; + if (t2 == null) + return t1; + + if (children == null) + return null; + + if (!this.contains(t1) || !this.contains(t2)) + return null; + + Tree p1 = this; + Tree p2 = this; + for (Tree c : children) { + if (c.contains(t1)) + p1 = c; + if (c.contains(t2)) + p2 = c; + } + + if (p1 != p2 || p1 == this || p2 == this) + return this; + + return p1.findCommonParent(t1, t2); + } + + public Tree findCommonParent(List t) { + if (t.contains(null)) { + while (t.contains(null)) + t.remove(null); + return findCommonParent(t); + } + + if (t.size() == 0) + return null; + if (t.size() == 1) + return t.get(0); + if (t.size() == 2) + return findCommonParent(t.get(0), t.get(1)); + + List remainder = t.subList(1, t.size()); + return findCommonParent(t.get(0), findCommonParent(remainder)); + } + + public Tree findParent(Tree t) { + if (children == null) + return null; + if (children.contains(t)) + return this; + for (Tree c : children) { + Tree p = c.findParent(t); + if (p != null) + return p; + } + return null; + } + + public boolean contains(Tree t) { + if (this == t) + return true; + + if (children == null) + return false; + if (children.contains(t)) + return true; + for (Tree c : children) + if (c.contains(t)) + return true; + return false; + } + + public interface ITreeWalker { + + void visit(Tree t); + + void visit(TreeLeaf l); + } +} diff --git a/diylc/diylc-core/src/main/java/org/diylc/presenter/Presenter.java b/diylc/diylc-core/src/main/java/org/diylc/presenter/Presenter.java index 2ca5013c..a1f57634 100644 --- a/diylc/diylc-core/src/main/java/org/diylc/presenter/Presenter.java +++ b/diylc/diylc-core/src/main/java/org/diylc/presenter/Presenter.java @@ -137,27 +137,9 @@ public class Presenter implements IPlugInPort, IConfigListener { private static final Logger LOG = Logger.getLogger(Presenter.class); - public static VersionNumber CURRENT_VERSION = new VersionNumber(4, 0, 0); - public static List RECENT_VERSIONS = null; - // Read the latest version from the local update.xml file - static { - try { - BufferedInputStream in = new BufferedInputStream(Presenter.class.getResourceAsStream("/update.xml")); - XStream xStream = new XStream(new DomDriver()); - xStream.addPermission(AnyTypePermission.ANY); - @SuppressWarnings("unchecked") - List allVersions = (List) xStream.fromXML(in); - CURRENT_VERSION = allVersions.get(allVersions.size() - 1).getVersionNumber(); - LOG.info("Current DIYLC version: " + CURRENT_VERSION); - RECENT_VERSIONS = allVersions.stream() - .sorted(Comparator.comparing(x -> ((Version)x).getVersionNumber()).reversed()) - .limit(10) - .collect(Collectors.toList()); - in.close(); - } catch (Exception e) { - LOG.error("Could not find version number, using default", e); - } - } + public static VersionNumber CURRENT_VERSION = null; + private static List RECENT_VERSIONS = null; + public static final String DEFAULTS_KEY_PREFIX = "default."; public static final List> EMPTY_SELECTION = Collections.emptyList(); @@ -1091,11 +1073,39 @@ public class Presenter implements IPlugInPort, IConfigListener { @Override public VersionNumber getCurrentVersionNumber() { + if (CURRENT_VERSION == null) { + List recentUpdates = getRecentUpdates(); + CURRENT_VERSION = recentUpdates.stream() + .findFirst().map(v -> v.getVersionNumber()) + .orElse(new VersionNumber(5, 0, 0)); + LOG.info("Current DIYLC version: " + CURRENT_VERSION); + } return CURRENT_VERSION; } @Override public List getRecentUpdates() { + return getRecentVersions(); + } + + private static List getRecentVersions() { + if (RECENT_VERSIONS == null) { + try { + BufferedInputStream in = + new BufferedInputStream(Presenter.class.getResourceAsStream("/update.xml")); + XStream xStream = new XStream(new DomDriver()); + xStream.addPermission(AnyTypePermission.ANY); + @SuppressWarnings("unchecked") + List allVersions = (List) xStream.fromXML(in); + RECENT_VERSIONS = allVersions.stream() + .sorted(Comparator.comparing(x -> ((Version) x).getVersionNumber()).reversed()) + .limit(10).collect(Collectors.toList()); + in.close(); + } catch (Exception e) { + LOG.error("Could not load recent versions", e); + RECENT_VERSIONS = new ArrayList<>(); + } + } return RECENT_VERSIONS; } diff --git a/diylc/diylc-core/src/main/resources/update.xml b/diylc/diylc-core/src/main/resources/update.xml index bf1618fb..4d285908 100644 --- a/diylc/diylc-core/src/main/resources/update.xml +++ b/diylc/diylc-core/src/main/resources/update.xml @@ -253,6 +253,10 @@ IMPROVEMENT Upgraded source code structure to modern standards and introduced Maven + + IMPROVEMENT + Improved robustness of series/parallel graph construction code used in circuit analysis + BUG_FIX Moving selected components with a mouse doesn't register file modification action and doesn't enable Undo action diff --git a/diylc/diylc-library/src/test/java/org/diylc/netlist/GuitarNetlistAnalyzerTests.java b/diylc/diylc-library/src/test/java/org/diylc/netlist/GuitarNetlistAnalyzerTests.java index df74ee37..0ef96c6f 100644 --- a/diylc/diylc-library/src/test/java/org/diylc/netlist/GuitarNetlistAnalyzerTests.java +++ b/diylc/diylc-library/src/test/java/org/diylc/netlist/GuitarNetlistAnalyzerTests.java @@ -1,291 +1,291 @@ -///* -// * -// * 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 -// * . -// * -// */ -//package org.diylc.netlist; -// -//import static org.junit.Assert.assertEquals; -//import java.util.Arrays; -// -//import org.junit.Test; -// -//import org.diylc.components.electromechanical.OpenJack1_4; -//import org.diylc.components.guitar.HumbuckerPickup; -//import org.diylc.components.guitar.SingleCoilPickup; -//import org.diylc.components.passive.PotentiometerPanel; -//import org.diylc.components.passive.RadialCeramicDiskCapacitor; -//import org.diylc.netlist.Group; -//import org.diylc.netlist.GuitarDiagramAnalyzer; -//import org.diylc.netlist.Netlist; -//import org.diylc.netlist.Tree; -//import org.diylc.netlist.TreeException; -// -//public class GuitarNetlistAnalyzerTests { -// -// @Test -// public void testOneSinglePickup() throws TreeException { -// OpenJack1_4 jack = new OpenJack1_4(); -// SingleCoilPickup pickup = new SingleCoilPickup(); -// pickup.setName("Pickup"); -// Netlist netlist = new Netlist(Arrays.asList(jack, pickup)); -// Group tipGroup = new Group().connect(jack, 0).connect(pickup, 1); -// Group sleeveGroup = new Group().connect(jack, 1).connect(pickup, 2); -// netlist.add(tipGroup).add(sleeveGroup); -// Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist); -// String s = tree.toString(); -// assertEquals("((Pickup.North<-))", s); -// } -// -// @Test -// public void testOneSinglePickupVolPot() throws TreeException { -// OpenJack1_4 jack = new OpenJack1_4(); -// SingleCoilPickup pickup = new SingleCoilPickup(); -// pickup.setName("Pickup"); -// PotentiometerPanel vol = new PotentiometerPanel(); -// vol.setName("Volume"); -// Netlist netlist = new Netlist(Arrays.asList(jack, pickup, vol)); -// Group hotGroup = new Group().connect(pickup, 1).connect(vol, 0); -// Group tipGroup = new Group().connect(jack, 0).connect(vol, 1); -// Group sleeveGroup = new Group().connect(jack, 1).connect(pickup, 2).connect(vol, 2); -// netlist.add(tipGroup).add(tipGroup).add(sleeveGroup).add(hotGroup); -// Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist); -// String s = tree.toString(); -// assertEquals("((Volume.1-2 + Pickup.North<-) || (Volume.2-3))", s); -// } -// -// @Test -// public void testOneSinglePickupVolTonePot() throws TreeException { -// OpenJack1_4 jack = new OpenJack1_4(); -// SingleCoilPickup pickup = new SingleCoilPickup(); -// pickup.setName("Pickup"); -// PotentiometerPanel vol = new PotentiometerPanel(); -// vol.setName("Volume"); -// PotentiometerPanel tone = new PotentiometerPanel(); -// tone.setName("Tone"); -// RadialCeramicDiskCapacitor cap = new RadialCeramicDiskCapacitor(); -// cap.setName("Cap"); -// Netlist netlist = new Netlist(Arrays.asList(jack, pickup, vol, tone, cap)); -// Group hotGroup = new Group().connect(pickup, 1).connect(vol, 0).connect(tone, 2); -// Group tipGroup = new Group().connect(jack, 0).connect(vol, 1); -// Group sleeveGroup = -// new Group().connect(jack, 1).connect(pickup, 2).connect(vol, 2).connect(cap, 0); -// Group toneGroup = new Group().connect(tone, 1).connect(cap, 1); -// netlist.add(tipGroup).add(tipGroup).add(sleeveGroup).add(hotGroup).add(toneGroup); -// Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist); -// String s = tree.toString(); -// assertEquals("(((Volume.1-2) + ((Pickup.North<-) || (Tone.2-3 + Cap))) || (Volume.2-3))", s); -// } -// -// @Test -// public void testTwoSinglePickupsMasterVolSeparateTone() throws TreeException { -// OpenJack1_4 jack = new OpenJack1_4(); -// SingleCoilPickup pickup1 = new SingleCoilPickup(); -// pickup1.setName("Pickup1"); -// SingleCoilPickup pickup2 = new SingleCoilPickup(); -// pickup2.setName("Pickup2"); -// PotentiometerPanel vol = new PotentiometerPanel(); -// vol.setName("Volume"); -// PotentiometerPanel tone1 = new PotentiometerPanel(); -// tone1.setName("Tone1"); -// PotentiometerPanel tone2 = new PotentiometerPanel(); -// tone2.setName("Tone2"); -// RadialCeramicDiskCapacitor cap1 = new RadialCeramicDiskCapacitor(); -// cap1.setName("Cap1"); -// RadialCeramicDiskCapacitor cap2 = new RadialCeramicDiskCapacitor(); -// cap2.setName("Cap2"); -// Netlist netlist = -// new Netlist(Arrays.asList(jack, pickup1, pickup2, vol, tone1, tone2, cap1, cap2)); -// Group hotGroup = new Group().connect(pickup1, 1).connect(vol, 0).connect(tone1, 2) -// .connect(pickup2, 1).connect(tone2, 2); -// Group tipGroup = new Group().connect(jack, 0).connect(vol, 1); -// Group sleeveGroup = new Group().connect(jack, 1).connect(pickup1, 2).connect(pickup2, 2) -// .connect(vol, 2).connect(cap1, 0).connect(cap2, 0); -// Group tone1Group = new Group().connect(tone1, 1).connect(cap1, 1); -// Group tone2Group = new Group().connect(tone2, 1).connect(cap2, 1); -// netlist.add(tipGroup).add(tipGroup).add(sleeveGroup).add(hotGroup).add(tone1Group) -// .add(tone2Group); -// Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist); -// String s = tree.toString(); -// assertEquals( -// "(((Volume.1-2) + ((Pickup1.North<-) || (Pickup2.North<-) || (Tone1.2-3 + Cap1) || (Tone2.2-3 + Cap2))) || (Volume.2-3))", -// s); -// } -// -// @Test -// public void testOneSinglePickupReverse() throws TreeException { -// OpenJack1_4 jack = new OpenJack1_4(); -// SingleCoilPickup pickup = new SingleCoilPickup(); -// pickup.setName("Pickup"); -// Netlist netlist = new Netlist(Arrays.asList(jack, pickup)); -// Group tipGroup = new Group().connect(jack, 0).connect(pickup, 2); -// Group sleeveGroup = new Group().connect(jack, 1).connect(pickup, 1); -// netlist.add(tipGroup).add(sleeveGroup); -// Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist); -// String s = tree.toString(); -// assertEquals("((Pickup.North->))", s); -// } -// -// @Test -// public void testOneHumbuckerSeries() throws TreeException { -// OpenJack1_4 jack = new OpenJack1_4(); -// HumbuckerPickup pickup = new HumbuckerPickup(); -// pickup.setName("Pickup"); -// Netlist netlist = new Netlist(Arrays.asList(jack, pickup)); -// Group tipGroup = new Group().connect(jack, 0).connect(pickup, 0); -// Group coilTapGroup = new Group().connect(pickup, 1).connect(pickup, 2); -// Group sleeveGroup = new Group().connect(jack, 1).connect(pickup, 3); -// netlist.add(tipGroup).add(coilTapGroup).add(sleeveGroup); -// Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist); -// String s = tree.toString(); -// assertEquals("((Pickup.North<- + Pickup.South<-))", s); -// } -// -// @Test -// public void testOneHumbuckerSeriesReverse() throws TreeException { -// OpenJack1_4 jack = new OpenJack1_4(); -// HumbuckerPickup pickup = new HumbuckerPickup(); -// pickup.setName("Pickup"); -// Netlist netlist = new Netlist(Arrays.asList(jack, pickup)); -// Group tipGroup = new Group().connect(jack, 0).connect(pickup, 3); -// Group coilTapGroup = new Group().connect(pickup, 1).connect(pickup, 2); -// Group sleeveGroup = new Group().connect(jack, 1).connect(pickup, 0); -// netlist.add(tipGroup).add(coilTapGroup).add(sleeveGroup); -// Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist); -// String s = tree.toString(); -// assertEquals("((Pickup.South-> + Pickup.North->))", s); -// } -// -// @Test -// public void testOneHumbuckerParallel() throws TreeException { -// OpenJack1_4 jack = new OpenJack1_4(); -// HumbuckerPickup pickup = new HumbuckerPickup(); -// pickup.setName("Pickup"); -// Netlist netlist = new Netlist(Arrays.asList(jack, pickup)); -// Group tipGroup = new Group().connect(jack, 0).connect(pickup, 0).connect(pickup, 2); -// Group sleeveGroup = new Group().connect(jack, 1).connect(pickup, 1).connect(pickup, 3); -// netlist.add(tipGroup).add(sleeveGroup); -// Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist); -// String s = tree.toString(); -// assertEquals("((Pickup.North<-) || (Pickup.South<-))", s); -// } -// -// @Test -// public void testOneHumbuckerParallelOutOfPhase() throws TreeException { -// OpenJack1_4 jack = new OpenJack1_4(); -// HumbuckerPickup pickup = new HumbuckerPickup(); -// pickup.setName("Pickup"); -// Netlist netlist = new Netlist(Arrays.asList(jack, pickup)); -// Group tipGroup = new Group().connect(jack, 0).connect(pickup, 0).connect(pickup, 3); -// Group sleeveGroup = new Group().connect(jack, 1).connect(pickup, 1).connect(pickup, 2); -// netlist.add(tipGroup).add(sleeveGroup); -// Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist); -// String s = tree.toString(); -// assertEquals("((Pickup.North<-) || (Pickup.South->))", s); -// } -// -// @Test -// public void testTwoHumbuckersSeries() throws TreeException { -// OpenJack1_4 jack = new OpenJack1_4(); -// HumbuckerPickup pickup1 = new HumbuckerPickup(); -// pickup1.setName("Pickup1"); -// HumbuckerPickup pickup2 = new HumbuckerPickup(); -// pickup2.setName("Pickup2"); -// Netlist netlist = new Netlist(Arrays.asList(jack, pickup1, pickup2)); -// Group tipGroup = new Group().connect(jack, 0).connect(pickup1, 0); -// Group coilTapGroup1 = new Group().connect(pickup1, 1).connect(pickup1, 2); -// Group coilTapGroup2 = new Group().connect(pickup2, 1).connect(pickup2, 2); -// Group joinGroup = new Group().connect(pickup1, 3).connect(pickup2, 0); -// Group sleeveGroup = new Group().connect(jack, 1).connect(pickup2, 3); -// netlist.add(tipGroup).add(coilTapGroup1).add(coilTapGroup2).add(joinGroup).add(sleeveGroup); -// Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist); -// String s = tree.toString(); -// assertEquals("((Pickup1.North<- + Pickup1.South<- + Pickup2.North<- + Pickup2.South<-))", s); -// } -// -// @Test -// public void testTwoHumbuckersParallel() throws TreeException { -// OpenJack1_4 jack = new OpenJack1_4(); -// HumbuckerPickup pickup1 = new HumbuckerPickup(); -// pickup1.setName("Pickup1"); -// HumbuckerPickup pickup2 = new HumbuckerPickup(); -// pickup2.setName("Pickup2"); -// Netlist netlist = new Netlist(Arrays.asList(jack, pickup1, pickup2)); -// Group tipGroup = new Group().connect(jack, 0).connect(pickup1, 0).connect(pickup2, 0); -// Group coilTapGroup1 = new Group().connect(pickup1, 1).connect(pickup1, 2); -// Group coilTapGroup2 = new Group().connect(pickup2, 1).connect(pickup2, 2); -// Group sleeveGroup = new Group().connect(jack, 1).connect(pickup1, 3).connect(pickup2, 3); -// netlist.add(tipGroup).add(coilTapGroup1).add(coilTapGroup2).add(sleeveGroup); -// Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist); -// String s = tree.toString(); -// assertEquals("((Pickup1.North<- + Pickup1.South<-) || (Pickup2.North<- + Pickup2.South<-))", s); -// } -// -// @Test -// public void testTwoHumbuckersParallelOutOfPhase() throws TreeException { -// OpenJack1_4 jack = new OpenJack1_4(); -// HumbuckerPickup pickup1 = new HumbuckerPickup(); -// pickup1.setName("Pickup1"); -// HumbuckerPickup pickup2 = new HumbuckerPickup(); -// pickup2.setName("Pickup2"); -// Netlist netlist = new Netlist(Arrays.asList(jack, pickup1, pickup2)); -// Group tipGroup = new Group().connect(jack, 0).connect(pickup1, 0).connect(pickup2, 3); -// Group coilTapGroup1 = new Group().connect(pickup1, 1).connect(pickup1, 2); -// Group coilTapGroup2 = new Group().connect(pickup2, 1).connect(pickup2, 2); -// Group sleeveGroup = new Group().connect(jack, 1).connect(pickup1, 3).connect(pickup2, 0); -// netlist.add(tipGroup).add(coilTapGroup1).add(coilTapGroup2).add(sleeveGroup); -// Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist); -// String s = tree.toString(); -// assertEquals("((Pickup1.North<- + Pickup1.South<-) || (Pickup2.South-> + Pickup2.North->))", s); -// } -// -// @Test -// public void testTwoHumbuckersMasterVolSeparateTone() throws TreeException { -// OpenJack1_4 jack = new OpenJack1_4(); -// HumbuckerPickup pickup1 = new HumbuckerPickup(); -// pickup1.setName("Pickup1"); -// HumbuckerPickup pickup2 = new HumbuckerPickup(); -// pickup2.setName("Pickup2"); -// PotentiometerPanel vol = new PotentiometerPanel(); -// vol.setName("Volume"); -// PotentiometerPanel tone1 = new PotentiometerPanel(); -// tone1.setName("Tone1"); -// PotentiometerPanel tone2 = new PotentiometerPanel(); -// tone2.setName("Tone2"); -// RadialCeramicDiskCapacitor cap1 = new RadialCeramicDiskCapacitor(); -// cap1.setName("Cap1"); -// RadialCeramicDiskCapacitor cap2 = new RadialCeramicDiskCapacitor(); -// cap2.setName("Cap2"); -// Netlist netlist = -// new Netlist(Arrays.asList(jack, pickup1, pickup2, vol, tone1, tone2, cap1, cap2)); -// Group hotGroup = new Group().connect(pickup1, 0).connect(vol, 0).connect(tone1, 2) -// .connect(pickup2, 0).connect(tone2, 2); -// Group tipGroup = new Group().connect(jack, 0).connect(vol, 1); -// Group sleeveGroup = new Group().connect(jack, 1).connect(pickup1, 3).connect(pickup2, 3) -// .connect(vol, 2).connect(cap1, 0).connect(cap2, 0); -// Group tone1Group = new Group().connect(tone1, 1).connect(cap1, 1); -// Group tone2Group = new Group().connect(tone2, 1).connect(cap2, 1); -// Group coilTap1 = new Group().connect(pickup1, 1).connect(pickup1, 2); -// Group coilTap2 = new Group().connect(pickup2, 1).connect(pickup2, 2); -// netlist.add(tipGroup).add(tipGroup).add(sleeveGroup).add(hotGroup).add(tone1Group) -// .add(tone2Group).add(coilTap1).add(coilTap2); -// Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist); -// String s = tree.toString(); -// assertEquals( -// "(((Volume.1-2) + ((Pickup1.North<- + Pickup1.South<-) || (Pickup2.North<- + Pickup2.South<-) || (Tone1.2-3 + Cap1) || (Tone2.2-3 + Cap2))) || (Volume.2-3))", -// s); -// } -//} +/* + * + * 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 + * . + * + */ +package org.diylc.netlist; + +import static org.junit.Assert.assertEquals; +import java.util.Arrays; + +import org.junit.Test; + +import org.diylc.components.electromechanical.OpenJack1_4; +import org.diylc.components.guitar.HumbuckerPickup; +import org.diylc.components.guitar.SingleCoilPickup; +import org.diylc.components.passive.PotentiometerPanel; +import org.diylc.components.passive.RadialCeramicDiskCapacitor; +import org.diylc.netlist.Group; +import org.diylc.netlist.GuitarDiagramAnalyzer; +import org.diylc.netlist.Netlist; +import org.diylc.netlist.Tree; +import org.diylc.netlist.TreeException; + +public class GuitarNetlistAnalyzerTests { + + @Test + public void testOneSinglePickup() throws TreeException { + OpenJack1_4 jack = new OpenJack1_4(); + SingleCoilPickup pickup = new SingleCoilPickup(); + pickup.setName("Pickup"); + Netlist netlist = new Netlist(Arrays.asList(jack, pickup)); + Group tipGroup = new Group().connect(jack, 0).connect(pickup, 1); + Group sleeveGroup = new Group().connect(jack, 1).connect(pickup, 2); + netlist.add(tipGroup).add(sleeveGroup); + Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist); + String s = tree.toString(); + assertEquals("Pickup.North<-", s); + } + + @Test + public void testOneSinglePickupVolPot() throws TreeException { + OpenJack1_4 jack = new OpenJack1_4(); + SingleCoilPickup pickup = new SingleCoilPickup(); + pickup.setName("Pickup"); + PotentiometerPanel vol = new PotentiometerPanel(); + vol.setName("Volume"); + Netlist netlist = new Netlist(Arrays.asList(jack, pickup, vol)); + Group hotGroup = new Group().connect(pickup, 1).connect(vol, 0); + Group tipGroup = new Group().connect(jack, 0).connect(vol, 1); + Group sleeveGroup = new Group().connect(jack, 1).connect(pickup, 2).connect(vol, 2); + netlist.add(tipGroup).add(tipGroup).add(sleeveGroup).add(hotGroup); + Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist); + String s = tree.toString(); + assertEquals("((Volume.1-2 + Pickup.North<-) || Volume.2-3)", s); + } + + @Test + public void testOneSinglePickupVolTonePot() throws TreeException { + OpenJack1_4 jack = new OpenJack1_4(); + SingleCoilPickup pickup = new SingleCoilPickup(); + pickup.setName("Pickup"); + PotentiometerPanel vol = new PotentiometerPanel(); + vol.setName("Volume"); + PotentiometerPanel tone = new PotentiometerPanel(); + tone.setName("Tone"); + RadialCeramicDiskCapacitor cap = new RadialCeramicDiskCapacitor(); + cap.setName("Cap"); + Netlist netlist = new Netlist(Arrays.asList(jack, pickup, vol, tone, cap)); + Group hotGroup = new Group().connect(pickup, 1).connect(vol, 0).connect(tone, 2); + Group tipGroup = new Group().connect(jack, 0).connect(vol, 1); + Group sleeveGroup = + new Group().connect(jack, 1).connect(pickup, 2).connect(vol, 2).connect(cap, 0); + Group toneGroup = new Group().connect(tone, 1).connect(cap, 1); + netlist.add(tipGroup).add(tipGroup).add(sleeveGroup).add(hotGroup).add(toneGroup); + Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist); + String s = tree.toString(); + assertEquals("((Volume.1-2 + (Tone.2-3 + Cap) || Pickup.North<-) || Volume.2-3)", s); + } + + @Test + public void testTwoSinglePickupsMasterVolSeparateTone() throws TreeException { + OpenJack1_4 jack = new OpenJack1_4(); + SingleCoilPickup pickup1 = new SingleCoilPickup(); + pickup1.setName("Pickup1"); + SingleCoilPickup pickup2 = new SingleCoilPickup(); + pickup2.setName("Pickup2"); + PotentiometerPanel vol = new PotentiometerPanel(); + vol.setName("Volume"); + PotentiometerPanel tone1 = new PotentiometerPanel(); + tone1.setName("Tone1"); + PotentiometerPanel tone2 = new PotentiometerPanel(); + tone2.setName("Tone2"); + RadialCeramicDiskCapacitor cap1 = new RadialCeramicDiskCapacitor(); + cap1.setName("Cap1"); + RadialCeramicDiskCapacitor cap2 = new RadialCeramicDiskCapacitor(); + cap2.setName("Cap2"); + Netlist netlist = + new Netlist(Arrays.asList(jack, pickup1, pickup2, vol, tone1, tone2, cap1, cap2)); + Group hotGroup = new Group().connect(pickup1, 1).connect(vol, 0).connect(tone1, 2) + .connect(pickup2, 1).connect(tone2, 2); + Group tipGroup = new Group().connect(jack, 0).connect(vol, 1); + Group sleeveGroup = new Group().connect(jack, 1).connect(pickup1, 2).connect(pickup2, 2) + .connect(vol, 2).connect(cap1, 0).connect(cap2, 0); + Group tone1Group = new Group().connect(tone1, 1).connect(cap1, 1); + Group tone2Group = new Group().connect(tone2, 1).connect(cap2, 1); + netlist.add(tipGroup).add(tipGroup).add(sleeveGroup).add(hotGroup).add(tone1Group) + .add(tone2Group); + Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist); + String s = tree.toString(); + assertEquals( + "((Volume.1-2 + (Tone1.2-3 + Cap1) || (Tone2.2-3 + Cap2) || Pickup1.North<- || Pickup2.North<-) || Volume.2-3)", + s); + } + + @Test + public void testOneSinglePickupReverse() throws TreeException { + OpenJack1_4 jack = new OpenJack1_4(); + SingleCoilPickup pickup = new SingleCoilPickup(); + pickup.setName("Pickup"); + Netlist netlist = new Netlist(Arrays.asList(jack, pickup)); + Group tipGroup = new Group().connect(jack, 0).connect(pickup, 2); + Group sleeveGroup = new Group().connect(jack, 1).connect(pickup, 1); + netlist.add(tipGroup).add(sleeveGroup); + Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist); + String s = tree.toString(); + assertEquals("Pickup.North->", s); + } + + @Test + public void testOneHumbuckerSeries() throws TreeException { + OpenJack1_4 jack = new OpenJack1_4(); + HumbuckerPickup pickup = new HumbuckerPickup(); + pickup.setName("Pickup"); + Netlist netlist = new Netlist(Arrays.asList(jack, pickup)); + Group tipGroup = new Group().connect(jack, 0).connect(pickup, 0); + Group coilTapGroup = new Group().connect(pickup, 1).connect(pickup, 2); + Group sleeveGroup = new Group().connect(jack, 1).connect(pickup, 3); + netlist.add(tipGroup).add(coilTapGroup).add(sleeveGroup); + Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist); + String s = tree.toString(); + assertEquals("(Pickup.North<- + Pickup.South<-)", s); + } + + @Test + public void testOneHumbuckerSeriesReverse() throws TreeException { + OpenJack1_4 jack = new OpenJack1_4(); + HumbuckerPickup pickup = new HumbuckerPickup(); + pickup.setName("Pickup"); + Netlist netlist = new Netlist(Arrays.asList(jack, pickup)); + Group tipGroup = new Group().connect(jack, 0).connect(pickup, 3); + Group coilTapGroup = new Group().connect(pickup, 1).connect(pickup, 2); + Group sleeveGroup = new Group().connect(jack, 1).connect(pickup, 0); + netlist.add(tipGroup).add(coilTapGroup).add(sleeveGroup); + Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist); + String s = tree.toString(); + assertEquals("(Pickup.South-> + Pickup.North->)", s); + } + + @Test + public void testOneHumbuckerParallel() throws TreeException { + OpenJack1_4 jack = new OpenJack1_4(); + HumbuckerPickup pickup = new HumbuckerPickup(); + pickup.setName("Pickup"); + Netlist netlist = new Netlist(Arrays.asList(jack, pickup)); + Group tipGroup = new Group().connect(jack, 0).connect(pickup, 0).connect(pickup, 2); + Group sleeveGroup = new Group().connect(jack, 1).connect(pickup, 1).connect(pickup, 3); + netlist.add(tipGroup).add(sleeveGroup); + Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist); + String s = tree.toString(); + assertEquals("(Pickup.North<- || Pickup.South<-)", s); + } + + @Test + public void testOneHumbuckerParallelOutOfPhase() throws TreeException { + OpenJack1_4 jack = new OpenJack1_4(); + HumbuckerPickup pickup = new HumbuckerPickup(); + pickup.setName("Pickup"); + Netlist netlist = new Netlist(Arrays.asList(jack, pickup)); + Group tipGroup = new Group().connect(jack, 0).connect(pickup, 0).connect(pickup, 3); + Group sleeveGroup = new Group().connect(jack, 1).connect(pickup, 1).connect(pickup, 2); + netlist.add(tipGroup).add(sleeveGroup); + Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist); + String s = tree.toString(); + assertEquals("(Pickup.North<- || Pickup.South->)", s); + } + + @Test + public void testTwoHumbuckersSeries() throws TreeException { + OpenJack1_4 jack = new OpenJack1_4(); + HumbuckerPickup pickup1 = new HumbuckerPickup(); + pickup1.setName("Pickup1"); + HumbuckerPickup pickup2 = new HumbuckerPickup(); + pickup2.setName("Pickup2"); + Netlist netlist = new Netlist(Arrays.asList(jack, pickup1, pickup2)); + Group tipGroup = new Group().connect(jack, 0).connect(pickup1, 0); + Group coilTapGroup1 = new Group().connect(pickup1, 1).connect(pickup1, 2); + Group coilTapGroup2 = new Group().connect(pickup2, 1).connect(pickup2, 2); + Group joinGroup = new Group().connect(pickup1, 3).connect(pickup2, 0); + Group sleeveGroup = new Group().connect(jack, 1).connect(pickup2, 3); + netlist.add(tipGroup).add(coilTapGroup1).add(coilTapGroup2).add(joinGroup).add(sleeveGroup); + Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist); + String s = tree.toString(); + assertEquals("(Pickup1.North<- + Pickup1.South<- + Pickup2.North<- + Pickup2.South<-)", s); + } + + @Test + public void testTwoHumbuckersParallel() throws TreeException { + OpenJack1_4 jack = new OpenJack1_4(); + HumbuckerPickup pickup1 = new HumbuckerPickup(); + pickup1.setName("Pickup1"); + HumbuckerPickup pickup2 = new HumbuckerPickup(); + pickup2.setName("Pickup2"); + Netlist netlist = new Netlist(Arrays.asList(jack, pickup1, pickup2)); + Group tipGroup = new Group().connect(jack, 0).connect(pickup1, 0).connect(pickup2, 0); + Group coilTapGroup1 = new Group().connect(pickup1, 1).connect(pickup1, 2); + Group coilTapGroup2 = new Group().connect(pickup2, 1).connect(pickup2, 2); + Group sleeveGroup = new Group().connect(jack, 1).connect(pickup1, 3).connect(pickup2, 3); + netlist.add(tipGroup).add(coilTapGroup1).add(coilTapGroup2).add(sleeveGroup); + Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist); + String s = tree.toString(); + assertEquals("((Pickup1.North<- + Pickup1.South<-) || (Pickup2.North<- + Pickup2.South<-))", s); + } + + @Test + public void testTwoHumbuckersParallelOutOfPhase() throws TreeException { + OpenJack1_4 jack = new OpenJack1_4(); + HumbuckerPickup pickup1 = new HumbuckerPickup(); + pickup1.setName("Pickup1"); + HumbuckerPickup pickup2 = new HumbuckerPickup(); + pickup2.setName("Pickup2"); + Netlist netlist = new Netlist(Arrays.asList(jack, pickup1, pickup2)); + Group tipGroup = new Group().connect(jack, 0).connect(pickup1, 0).connect(pickup2, 3); + Group coilTapGroup1 = new Group().connect(pickup1, 1).connect(pickup1, 2); + Group coilTapGroup2 = new Group().connect(pickup2, 1).connect(pickup2, 2); + Group sleeveGroup = new Group().connect(jack, 1).connect(pickup1, 3).connect(pickup2, 0); + netlist.add(tipGroup).add(coilTapGroup1).add(coilTapGroup2).add(sleeveGroup); + Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist); + String s = tree.toString(); + assertEquals("((Pickup1.North<- + Pickup1.South<-) || (Pickup2.South-> + Pickup2.North->))", s); + } + + @Test + public void testTwoHumbuckersMasterVolSeparateTone() throws TreeException { + OpenJack1_4 jack = new OpenJack1_4(); + HumbuckerPickup pickup1 = new HumbuckerPickup(); + pickup1.setName("Pickup1"); + HumbuckerPickup pickup2 = new HumbuckerPickup(); + pickup2.setName("Pickup2"); + PotentiometerPanel vol = new PotentiometerPanel(); + vol.setName("Volume"); + PotentiometerPanel tone1 = new PotentiometerPanel(); + tone1.setName("Tone1"); + PotentiometerPanel tone2 = new PotentiometerPanel(); + tone2.setName("Tone2"); + RadialCeramicDiskCapacitor cap1 = new RadialCeramicDiskCapacitor(); + cap1.setName("Cap1"); + RadialCeramicDiskCapacitor cap2 = new RadialCeramicDiskCapacitor(); + cap2.setName("Cap2"); + Netlist netlist = + new Netlist(Arrays.asList(jack, pickup1, pickup2, vol, tone1, tone2, cap1, cap2)); + Group hotGroup = new Group().connect(pickup1, 0).connect(vol, 0).connect(tone1, 2) + .connect(pickup2, 0).connect(tone2, 2); + Group tipGroup = new Group().connect(jack, 0).connect(vol, 1); + Group sleeveGroup = new Group().connect(jack, 1).connect(pickup1, 3).connect(pickup2, 3) + .connect(vol, 2).connect(cap1, 0).connect(cap2, 0); + Group tone1Group = new Group().connect(tone1, 1).connect(cap1, 1); + Group tone2Group = new Group().connect(tone2, 1).connect(cap2, 1); + Group coilTap1 = new Group().connect(pickup1, 1).connect(pickup1, 2); + Group coilTap2 = new Group().connect(pickup2, 1).connect(pickup2, 2); + netlist.add(tipGroup).add(tipGroup).add(sleeveGroup).add(hotGroup).add(tone1Group) + .add(tone2Group).add(coilTap1).add(coilTap2); + Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist); + String s = tree.toString(); + assertEquals( + "((Volume.1-2 + (Pickup1.North<- + Pickup1.South<-) || (Pickup2.North<- + Pickup2.South<-) || (Tone1.2-3 + Cap1) || (Tone2.2-3 + Cap2)) || Volume.2-3)", + s); + } +}