mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-10 17:22:09 +10:00
fixes for netlist
This commit is contained in:
@@ -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
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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<Summary> summarize(List<Netlist> netlists, Node preferredOutput) throws TreeException {
|
||||
Map<String, Summary> summaries = new HashMap<String, Summary>();
|
||||
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<Summary> res = new ArrayList<Summary>(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<Node>());
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
// protected Tree removeRedundantElements(Tree tree) {
|
||||
// List<Tree> 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<Tree> concurrentPaths, Tree currentPath,
|
||||
Set<Node> 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<Tree> newConcurrentPaths = new ArrayList<Tree>();
|
||||
|
||||
// Track processed connections to prevent duplicates from bidirectional links
|
||||
Set<String> processedConnections = new HashSet<String>();
|
||||
|
||||
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<Node> newVisited = new HashSet<Node>(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<Tree> paths, boolean backward) {
|
||||
// Skip if there are no paths or only one path
|
||||
if (paths == null || paths.size() <= 1) {
|
||||
return;
|
||||
}
|
||||
Map<Tree, Integer> uniques = new HashMap<Tree, Integer>();
|
||||
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<Tree> unmerged = new ArrayList<Tree>(paths);
|
||||
|
||||
for (Map.Entry<Tree, Integer> e : uniques.entrySet()) {
|
||||
if (e.getValue() > 1) {
|
||||
List<Tree> pathsToMerge = new ArrayList<Tree>();
|
||||
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<Tree>(), TreeConnectionType.Series);
|
||||
Tree jointFinish = new Tree(new ArrayList<Tree>(), 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<Tree>(), TreeConnectionType.Series);
|
||||
Tree parallelSection = new Tree(new ArrayList<Tree>(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<Tree> children1 = path1.getChildren();
|
||||
List<Tree> 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<Node> find(Set<String> typeNames, String nodeName, Netlist netlist) {
|
||||
List<Node> res = new ArrayList<Node>();
|
||||
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<Set<IDIYComponent<?>>> extractComponentGroups(List<Netlist> netlists) {
|
||||
List<Set<IDIYComponent<?>>> res = new ArrayList<Set<IDIYComponent<?>>>();
|
||||
for (Netlist n : netlists) {
|
||||
res.addAll(extractComponentGroups(n));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public static List<Set<IDIYComponent<?>>> extractComponentGroups(Netlist netlist) {
|
||||
List<Set<IDIYComponent<?>>> res = new ArrayList<Set<IDIYComponent<?>>>();
|
||||
for (Group g : netlist.getGroups()) {
|
||||
Set<IDIYComponent<?>> components = new HashSet<IDIYComponent<?>>();
|
||||
for (Node n : g.getNodes())
|
||||
components.add(n.getComponent());
|
||||
res.add(components);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
protected int find(Node node, List<Group> groups) {
|
||||
for (int i = 0; i < groups.size(); i++)
|
||||
if (groups.get(i).getNodes().contains(node))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
protected boolean intersect(List<Group> groups, Node node) {
|
||||
for (Group g : groups)
|
||||
if (g.getNodes().contains(node))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected Node intersect(List<Group> 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
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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<Summary> summarize(List<Netlist> netlists, Node preferredOutput)
|
||||
throws TreeException {
|
||||
Map<String, Summary> summaries = new HashMap<String, Summary>();
|
||||
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<Summary> res = new ArrayList<Summary>(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<Node>());
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
protected void connectNodes(Netlist netlist, Node nodeA, Node nodeB, List<Tree> concurrentPaths,
|
||||
Tree currentPath, Set<Node> 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<Node> pathVisited = new HashSet<>(visited);
|
||||
pathVisited.add(nodeA);
|
||||
|
||||
// First collect all immediate next nodes and their paths
|
||||
Map<Node, List<Tree>> 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<Tree> allPaths = new ArrayList<>();
|
||||
for (Map.Entry<Node, List<Tree>> entry : nextNodes.entrySet()) {
|
||||
for (Tree path : entry.getValue()) {
|
||||
List<Tree> 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<Tree> 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<Tree> 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<Tree> findCommonElements(List<Tree> paths, boolean fromStart, boolean backward) {
|
||||
if (paths.isEmpty())
|
||||
return new ArrayList<>();
|
||||
|
||||
List<Tree> 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<Node> find(Set<String> typeNames, String nodeName, Netlist netlist) {
|
||||
List<Node> res = new ArrayList<Node>();
|
||||
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<Set<IDIYComponent<?>>> extractComponentGroups(List<Netlist> netlists) {
|
||||
List<Set<IDIYComponent<?>>> res = new ArrayList<Set<IDIYComponent<?>>>();
|
||||
for (Netlist n : netlists) {
|
||||
res.addAll(extractComponentGroups(n));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public static List<Set<IDIYComponent<?>>> extractComponentGroups(Netlist netlist) {
|
||||
List<Set<IDIYComponent<?>>> res = new ArrayList<Set<IDIYComponent<?>>>();
|
||||
for (Group g : netlist.getGroups()) {
|
||||
Set<IDIYComponent<?>> components = new HashSet<IDIYComponent<?>>();
|
||||
for (Node n : g.getNodes())
|
||||
components.add(n.getComponent());
|
||||
res.add(components);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
protected int find(Node node, List<Group> groups) {
|
||||
for (int i = 0; i < groups.size(); i++)
|
||||
if (groups.get(i).getNodes().contains(node))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
protected boolean intersect(List<Group> groups, Node node) {
|
||||
for (Group g : groups)
|
||||
if (g.getNodes().contains(node))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected Node intersect(List<Group> groups, Group group) {
|
||||
for (Group g : groups)
|
||||
for (Node node : group.getNodes())
|
||||
if (g.getNodes().contains(node))
|
||||
return node;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
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<Tree> children;
|
||||
private TreeConnectionType connectionType;
|
||||
private TreeLeaf leaf;
|
||||
|
||||
public Tree(TreeConnectionType connectionType) {
|
||||
this.children = new ArrayList<Tree>();
|
||||
this.connectionType = connectionType;
|
||||
}
|
||||
|
||||
public Tree(TreeLeaf leaf) {
|
||||
this.leaf = leaf;
|
||||
}
|
||||
|
||||
public Tree(List<Tree> children, TreeConnectionType connectionType) {
|
||||
this.children = children;
|
||||
this.connectionType = connectionType;
|
||||
}
|
||||
|
||||
public List<Tree> 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<Tree> getOrderedChildren() {
|
||||
if (getConnectionType() == TreeConnectionType.Series)
|
||||
return children;
|
||||
List<Tree> ordered = new ArrayList<Tree>(children);
|
||||
Collections.sort(ordered, new Comparator<Tree>() {
|
||||
|
||||
@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<Tree> 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("<br>");
|
||||
}
|
||||
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("<br>", toAscii());
|
||||
}
|
||||
|
||||
private List<String> toAscii() {
|
||||
if (leaf != null) {
|
||||
return Arrays.asList(TreeAsciiUtil.generateString(TreeAsciiUtil.BOXH, 1) + " " + leaf.toHTML() + " " + TreeAsciiUtil.generateString(TreeAsciiUtil.BOXH, 1));
|
||||
}
|
||||
|
||||
List<Tree> children = getOrderedChildren();
|
||||
|
||||
List<List<String>> 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<Tree> newChildren = new ArrayList<Tree>();
|
||||
for (Tree t : children)
|
||||
newChildren.add((Tree) t.clone());
|
||||
return new Tree(newChildren, connectionType);
|
||||
}
|
||||
|
||||
public Tree filter(Set<String> types) {
|
||||
if (leaf != null) {
|
||||
if (types.contains(leaf.getComponent().getClass().getCanonicalName()))
|
||||
return new Tree(leaf);
|
||||
return null;
|
||||
}
|
||||
List<Tree> newChildren = new ArrayList<Tree>();
|
||||
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<IDIYComponent<?>> extractComponents(Set<String> types) {
|
||||
Set<IDIYComponent<?>> res = new HashSet<IDIYComponent<?>>();
|
||||
if (leaf != null && types.contains(leaf.getComponent().getClass().getCanonicalName())) {
|
||||
res.add(leaf.getComponent());
|
||||
} else if (children != null) {
|
||||
for (Tree t : children) {
|
||||
Set<IDIYComponent<?>> 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<Tree> 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<Tree> 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
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<Tree> children;
|
||||
private TreeConnectionType connectionType;
|
||||
private TreeLeaf leaf;
|
||||
|
||||
public Tree(TreeConnectionType connectionType) {
|
||||
this.children = new ArrayList<Tree>();
|
||||
this.connectionType = connectionType;
|
||||
}
|
||||
|
||||
public Tree(TreeLeaf leaf) {
|
||||
this.leaf = leaf;
|
||||
}
|
||||
|
||||
public Tree(List<Tree> children, TreeConnectionType connectionType) {
|
||||
this.children = children;
|
||||
this.connectionType = connectionType;
|
||||
}
|
||||
|
||||
public List<Tree> 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<Tree> getOrderedChildren() {
|
||||
if (getConnectionType() == TreeConnectionType.Series)
|
||||
return children;
|
||||
List<Tree> ordered = new ArrayList<Tree>(children);
|
||||
Collections.sort(ordered, new Comparator<Tree>() {
|
||||
|
||||
@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<Tree> 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("<br>");
|
||||
}
|
||||
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("<br>", toAscii());
|
||||
}
|
||||
|
||||
private List<String> toAscii() {
|
||||
if (leaf != null) {
|
||||
return Arrays.asList(TreeAsciiUtil.generateString(TreeAsciiUtil.BOXH,
|
||||
1) + " " + leaf.toHTML() + " " + TreeAsciiUtil.generateString(TreeAsciiUtil.BOXH, 1));
|
||||
}
|
||||
|
||||
List<Tree> children = getOrderedChildren();
|
||||
|
||||
List<List<String>> 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<Tree> newChildren = new ArrayList<Tree>();
|
||||
for (Tree t : children)
|
||||
newChildren.add((Tree) t.clone());
|
||||
return new Tree(newChildren, connectionType);
|
||||
}
|
||||
|
||||
public Tree filter(Set<String> types) {
|
||||
if (leaf != null) {
|
||||
if (types.contains(leaf.getComponent().getClass().getCanonicalName()))
|
||||
return new Tree(leaf);
|
||||
return null;
|
||||
}
|
||||
List<Tree> newChildren = new ArrayList<Tree>();
|
||||
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<IDIYComponent<?>> extractComponents(Set<String> types) {
|
||||
Set<IDIYComponent<?>> res = new HashSet<IDIYComponent<?>>();
|
||||
if (leaf != null && types.contains(leaf.getComponent().getClass().getCanonicalName())) {
|
||||
res.add(leaf.getComponent());
|
||||
} else if (children != null) {
|
||||
for (Tree t : children) {
|
||||
Set<IDIYComponent<?>> 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<Tree> 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<Tree> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Version> 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<Version> allVersions = (List<Version>) 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<Version> RECENT_VERSIONS = null;
|
||||
|
||||
public static final String DEFAULTS_KEY_PREFIX = "default.";
|
||||
|
||||
public static final List<IDIYComponent<?>> EMPTY_SELECTION = Collections.emptyList();
|
||||
@@ -1091,11 +1073,39 @@ public class Presenter implements IPlugInPort, IConfigListener {
|
||||
|
||||
@Override
|
||||
public VersionNumber getCurrentVersionNumber() {
|
||||
if (CURRENT_VERSION == null) {
|
||||
List<Version> 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<Version> getRecentUpdates() {
|
||||
return getRecentVersions();
|
||||
}
|
||||
|
||||
private static List<Version> 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<Version> allVersions = (List<Version>) 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -253,6 +253,10 @@
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Upgraded source code structure to modern standards and introduced Maven</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Improved robustness of series/parallel graph construction code used in circuit analysis</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>BUG_FIX</changeType>
|
||||
<description>Moving selected components with a mouse doesn't register file modification action and doesn't enable Undo action</description>
|
||||
|
||||
Reference in New Issue
Block a user