mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-10 09:12:09 +10:00
Better "Expand Selection" logic. Works well with conductive components
like traces and wires and regular components like resistors and capacitors
This commit is contained in:
@@ -275,5 +275,22 @@ public class ComponentProcessor {
|
|||||||
}
|
}
|
||||||
componentTransformerMap.put(clazz.getName(), transformer);
|
componentTransformerMap.put(clazz.getName(), transformer);
|
||||||
return transformer;
|
return transformer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean hasStickyPoint(IDIYComponent<?> c) {
|
||||||
|
for (int i = 0; i < c.getControlPointCount(); i++)
|
||||||
|
if (c.isControlPointSticky(0))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int touchSensitivity = 5;
|
||||||
|
|
||||||
|
public static boolean componentPointsTouch(IDIYComponent<?> c1, IDIYComponent<?> c2) {
|
||||||
|
for (int i = 0; i < c1.getControlPointCount(); i++)
|
||||||
|
for (int j = 0; j < c2.getControlPointCount(); j++)
|
||||||
|
if (c1.isControlPointSticky(i) && c2.isControlPointSticky(j) && c1.getControlPoint(i).distance(c2.getControlPoint(j)) < touchSensitivity)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1939,63 +1939,141 @@ public class Presenter implements IPlugInPort {
|
|||||||
}
|
}
|
||||||
messageDispatcher.dispatchMessage(EventType.SELECTION_CHANGED, selectedComponents, controlPointMap.keySet());
|
messageDispatcher.dispatchMessage(EventType.SELECTION_CHANGED, selectedComponents, controlPointMap.keySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean useNetlistForExpandSelection = false;
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public void expandSelection(ExpansionMode expansionMode) {
|
public void expandSelection(ExpansionMode expansionMode) {
|
||||||
LOG.info(String.format("expandSelection(%s)", expansionMode));
|
LOG.info(String.format("expandSelection(%s)", expansionMode));
|
||||||
List<IDIYComponent<?>> newSelection = new ArrayList<IDIYComponent<?>>(this.selectedComponents);
|
List<IDIYComponent<?>> newSelection = new ArrayList<IDIYComponent<?>>(this.selectedComponents);
|
||||||
List<Netlist> netlists = extractNetlists(false);
|
// experimental mode using netlist to expand selection. Works fine but doesn't include any connectivity components
|
||||||
|
// like traces and wires, so it's not ideal
|
||||||
if (netlists == null)
|
if (useNetlistForExpandSelection) {
|
||||||
return;
|
List<Netlist> netlists = extractNetlists(false);
|
||||||
|
|
||||||
List<Set<IDIYComponent<?>>> allGroups = NetlistAnalyzer.extractComponentGroups(netlists);
|
if (netlists == null)
|
||||||
// Find control points of all selected components and all types
|
return;
|
||||||
Set<String> selectedNamePrefixes = new HashSet<String>();
|
|
||||||
if (expansionMode == ExpansionMode.SAME_TYPE) {
|
List<Set<IDIYComponent<?>>> allGroups = NetlistAnalyzer.extractComponentGroups(netlists);
|
||||||
for (IDIYComponent<?> component : getSelectedComponents()) {
|
// Find control points of all selected components and all types
|
||||||
selectedNamePrefixes.add(ComponentProcessor.getInstance()
|
Set<String> selectedNamePrefixes = new HashSet<String>();
|
||||||
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) component.getClass()).getNamePrefix());
|
if (expansionMode == ExpansionMode.SAME_TYPE) {
|
||||||
|
for (IDIYComponent<?> component : getSelectedComponents()) {
|
||||||
|
selectedNamePrefixes.add(ComponentProcessor.getInstance()
|
||||||
|
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) component.getClass()).getNamePrefix());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
// Now try to find components that intersect with at least one component
|
||||||
// Now try to find components that intersect with at least one component
|
// in the pool.
|
||||||
// in the pool.
|
for (IDIYComponent<?> component : getCurrentProject().getComponents()) {
|
||||||
for (IDIYComponent<?> component : getCurrentProject().getComponents()) {
|
// no need to consider it, it's already in the selection
|
||||||
// no need to consider it, it's already in the selection
|
if (newSelection.contains(component))
|
||||||
if (newSelection.contains(component))
|
continue;
|
||||||
continue;
|
// construct a list of component groups that contain the current component
|
||||||
// construct a list of component groups that contain the current component
|
List<Set<IDIYComponent<?>>> componentGroups = new ArrayList<Set<IDIYComponent<?>>>();
|
||||||
List<Set<IDIYComponent<?>>> componentGroups = new ArrayList<Set<IDIYComponent<?>>>();
|
for (Set<IDIYComponent<?>> e : allGroups)
|
||||||
for (Set<IDIYComponent<?>> e : allGroups)
|
if (e.contains(component))
|
||||||
if (e.contains(component))
|
componentGroups.add(e);
|
||||||
componentGroups.add(e);
|
if (componentGroups.isEmpty())
|
||||||
if (componentGroups.isEmpty())
|
continue;
|
||||||
continue;
|
// Skip already selected components or ones that cannot be stuck to
|
||||||
// Skip already selected components or ones that cannot be stuck to
|
// other components.
|
||||||
// other components.
|
boolean matches = false;
|
||||||
boolean matches = false;
|
outer: for (IDIYComponent<?> selectedComponent : this.selectedComponents) {
|
||||||
outer: for (IDIYComponent<?> selectedComponent : this.selectedComponents) {
|
// try to find the selectedComponent in one of the groups
|
||||||
// try to find the selectedComponent in one of the groups
|
for (Set<IDIYComponent<?>> s : componentGroups)
|
||||||
for (Set<IDIYComponent<?>> s : componentGroups)
|
if (s.contains(selectedComponent)) {
|
||||||
if (s.contains(selectedComponent)) {
|
matches = true;
|
||||||
matches = true;
|
break outer;
|
||||||
break outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (matches) {
|
|
||||||
switch (expansionMode) {
|
|
||||||
case ALL:
|
|
||||||
case IMMEDIATE:
|
|
||||||
newSelection.add(component);
|
|
||||||
break;
|
|
||||||
case SAME_TYPE:
|
|
||||||
if (selectedNamePrefixes.contains(ComponentProcessor.getInstance()
|
|
||||||
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) component.getClass()).getNamePrefix())) {
|
|
||||||
newSelection.add(component);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matches) {
|
||||||
|
switch (expansionMode) {
|
||||||
|
case ALL:
|
||||||
|
case IMMEDIATE:
|
||||||
|
newSelection.add(component);
|
||||||
|
break;
|
||||||
|
case SAME_TYPE:
|
||||||
|
if (selectedNamePrefixes.contains(ComponentProcessor.getInstance()
|
||||||
|
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) component.getClass()).getNamePrefix())) {
|
||||||
|
newSelection.add(component);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Set<String> selectedNamePrefixes = new HashSet<String>();
|
||||||
|
if (expansionMode == ExpansionMode.SAME_TYPE) {
|
||||||
|
// find prefixes of all selected components to bundle similar component types together
|
||||||
|
for (IDIYComponent<?> component : getSelectedComponents()) {
|
||||||
|
selectedNamePrefixes.add(ComponentProcessor.getInstance()
|
||||||
|
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) component.getClass()).getNamePrefix());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Now try to find components that intersect with at least one component
|
||||||
|
// in the pool.
|
||||||
|
for (IDIYComponent<?> component : getCurrentProject().getComponents()) {
|
||||||
|
// Skip already selected components or ones that cannot be stuck to
|
||||||
|
// other components.
|
||||||
|
ComponentArea area = drawingManager.getComponentArea(component);
|
||||||
|
if (newSelection.contains(component) || !(ComponentProcessor.hasStickyPoint(component) || (area != null
|
||||||
|
&& area.getContinuityPositiveAreas() == null)))
|
||||||
|
continue;
|
||||||
|
boolean matches = false;
|
||||||
|
for (IDIYComponent<?> selectedComponent : this.selectedComponents) {
|
||||||
|
ComponentArea selectedArea = drawingManager.getComponentArea(selectedComponent);
|
||||||
|
if (ComponentProcessor.componentPointsTouch(component, selectedComponent)) {
|
||||||
|
matches = true;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
if (selectedArea == null || selectedArea.getContinuityPositiveAreas() == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// do a rough check, if the outlines don't intersect there's no chance of a match
|
||||||
|
// so don't waste time doing the precise check
|
||||||
|
if (area.getOutlineArea() != null && selectedArea.getOutlineArea() != null &&
|
||||||
|
!area.getOutlineArea().getBounds().intersects(selectedArea.getOutlineArea().getBounds()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// create a unified continuity area for both components
|
||||||
|
Area area1 = new Area();
|
||||||
|
for (Area a : area.getContinuityPositiveAreas())
|
||||||
|
area1.add(a);
|
||||||
|
if (area.getContinuityNegativeAreas() != null)
|
||||||
|
for(Area a : area.getContinuityNegativeAreas())
|
||||||
|
area1.subtract(a);
|
||||||
|
|
||||||
|
Area area2 = new Area();
|
||||||
|
for (Area a : selectedArea.getContinuityPositiveAreas())
|
||||||
|
area2.add(a);
|
||||||
|
if (selectedArea.getContinuityNegativeAreas() != null)
|
||||||
|
for(Area a : selectedArea.getContinuityNegativeAreas())
|
||||||
|
area2.subtract(a);
|
||||||
|
|
||||||
|
// now check the intersection, if there's something we have a match
|
||||||
|
area1.intersect(area2);
|
||||||
|
if (!area1.isEmpty()) {
|
||||||
|
matches = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matches) {
|
||||||
|
switch (expansionMode) {
|
||||||
|
case ALL:
|
||||||
|
case IMMEDIATE:
|
||||||
|
newSelection.add(component);
|
||||||
|
break;
|
||||||
|
case SAME_TYPE:
|
||||||
|
if (selectedNamePrefixes.contains(ComponentProcessor.getInstance()
|
||||||
|
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) component.getClass()).getNamePrefix())) {
|
||||||
|
newSelection.add(component);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2781,6 +2781,10 @@
|
|||||||
<org.diylc.appframework.update.Change>
|
<org.diylc.appframework.update.Change>
|
||||||
<changeType>NEW_FEATURE</changeType>
|
<changeType>NEW_FEATURE</changeType>
|
||||||
<description>Added "P-0+o (Proto) Board" component by Kristian Blåsol</description>
|
<description>Added "P-0+o (Proto) Board" component by Kristian Blåsol</description>
|
||||||
|
</org.diylc.appframework.update.Change>
|
||||||
|
<org.diylc.appframework.update.Change>
|
||||||
|
<changeType>IMPROVEMENT</changeType>
|
||||||
|
<description>Better "Expand Selection" logic. Works well with conductive components like traces and wires and regular components like resistors and capacitors</description>
|
||||||
</org.diylc.appframework.update.Change>
|
</org.diylc.appframework.update.Change>
|
||||||
<org.diylc.appframework.update.Change>
|
<org.diylc.appframework.update.Change>
|
||||||
<changeType>BUG_FIX</changeType>
|
<changeType>BUG_FIX</changeType>
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user