Add ability to merge disjoint continuity areas

This commit is contained in:
bancika
2020-03-30 13:56:42 +02:00
parent 21fa33c74a
commit a37b1e49e3
8 changed files with 153 additions and 41 deletions
@@ -19,8 +19,8 @@
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.core;
package org.diylc.core;
/**
* Interface for tracking component drawing process. Components may use it to stop or restart
* tracking. Anything drawn while tracking is stopped will not be added to the mouse hot-spot area.
@@ -28,14 +28,41 @@ package org.diylc.core;
* @author Branislav Stojkovic
*/
public interface IDrawingObserver {
/**
* Notifies the observer that it should start tracking the drawing process.
*/
void stopTracking();
/**
* Notifies the observer that it should stop tracking the drawing process.
*/
void startTracking();
void stopTrackingContinuityArea();
/**
* Notifies the observer that it should start tracking conductive continuity areas.
*
* @param positive designates if the area should be additive or subtractive
*/
void startTrackingContinuityArea(boolean positive);
boolean isTrackingContinuityArea();
/**
* Notifies the observer that it should stop tracking conductive continuity areas.
*/
void stopTrackingContinuityArea();
/**
* Checks if we are tracking continuity ares.
*
* @return
*/
boolean isTrackingContinuityArea();
/**
* Allows us to connect multiple disjoint continuity areas by specifying the same continuity markers.
* By default it is set to null and does not connect disjoint areas.
*
* @param marker
*/
void setContinuityMarker(String marker);
}
@@ -22,15 +22,15 @@
package org.diylc.presenter;
import java.awt.geom.Area;
import java.util.List;
import java.util.Collection;
public class ComponentArea {
private Area outlineArea;
private List<Area> continuityPositiveAreas;
private List<Area> continuityNegativeAreas;
private Collection<Area> continuityPositiveAreas;
private Collection<Area> continuityNegativeAreas;
public ComponentArea(Area outlineArea, List<Area> continuityPositiveAreas, List<Area> continuityNegativeAreas) {
public ComponentArea(Area outlineArea, Collection<Area> continuityPositiveAreas, Collection<Area> continuityNegativeAreas) {
super();
this.outlineArea = outlineArea;
this.continuityPositiveAreas = continuityPositiveAreas;
@@ -41,11 +41,11 @@ public class ComponentArea {
return outlineArea;
}
public List<Area> getContinuityPositiveAreas() {
public Collection<Area> getContinuityPositiveAreas() {
return continuityPositiveAreas;
}
public List<Area> getContinuityNegativeAreas() {
public Collection<Area> getContinuityNegativeAreas() {
return continuityNegativeAreas;
}
}
}
@@ -532,13 +532,15 @@ public class DrawingManager {
if (a == null || a.getOutlineArea() == null)
continue;
if (a.getContinuityPositiveAreas() != null)
for (Area a1 : a.getContinuityPositiveAreas()) {
Collection<Area> positiveAreas = a.getContinuityPositiveAreas();
if (positiveAreas != null)
for (Area a1 : positiveAreas) {
preliminaryAreas.add(a1);
checkBreakout.add(false);
}
if (a.getContinuityNegativeAreas() != null) {
for (Area na : a.getContinuityNegativeAreas())
Collection<Area> negativeAreas = a.getContinuityNegativeAreas();
if (negativeAreas != null) {
for (Area na : negativeAreas)
for (int i = 0; i < preliminaryAreas.size(); i++) {
Area a1 = preliminaryAreas.get(i);
if (a1.intersects(na.getBounds2D())) {
@@ -546,17 +548,17 @@ public class DrawingManager {
checkBreakout.set(i, true);
}
}
}
}
}
// Check if we need to break some areas out in case they are interrupted
List<Area> areas = new ArrayList<Area>();
for (int i = 0; i < preliminaryAreas.size(); i++) {
Area a = preliminaryAreas.get(i);
// if (checkBreakout.get(i))
areas.addAll(tryBreakout(a));
// else
// areas.add(a);
if (checkBreakout.get(i))
areas.addAll(tryBreakout(a));
else
areas.add(a);
}
expandConnections(connections);
@@ -41,6 +41,7 @@ import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
@@ -49,10 +50,17 @@ import java.awt.image.BufferedImageOp;
import java.awt.image.ImageObserver;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.RenderableImage;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.AttributedCharacterIterator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.diylc.common.ObjectCache;
import org.diylc.common.ZoomableStroke;
@@ -70,12 +78,16 @@ import org.diylc.core.IDrawingObserver;
class G2DWrapper extends Graphics2D implements IDrawingObserver {
public static int LINE_SENSITIVITY_MARGIN = 2;
public static int CURVE_SENSITIVITY = 6;
public static int CURVE_SENSITIVITY = 6;
private boolean drawingComponent = false;
private boolean trackingAllowed = true;
private boolean trackingContinuityAllowed = false;
private boolean trackingContinuityPositive = true;
private HashMap<String, Integer> trackingStacks = new HashMap<String, Integer>();
private int uniqueCounter = 0;
private Graphics2D canvasGraphics;
private Stroke originalStroke;
@@ -86,11 +98,12 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
private AffineTransform currentTx;
private AffineTransform initialTx;
private Area currentArea;
private List<Area> continuityPositiveAreas;
private List<Area> continuityNegativeAreas;
private Map<String, Area> continuityPositiveAreas;
private Map<String, Area> continuityNegativeAreas;
private String continuityMarker;
private Shape lastShape;
private double zoom;
private double zoom;
/**
* Creates a wrapper around specified {@link Graphics2D} object.
@@ -102,8 +115,9 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
this.canvasGraphics = canvasGraphics;
this.zoom = zoom;
currentArea = new Area();
continuityPositiveAreas = new ArrayList<Area>();
continuityNegativeAreas = new ArrayList<Area>();
continuityPositiveAreas = new HashMap<String, Area>();
continuityNegativeAreas = new HashMap<String, Area>();
continuityMarker = null;
currentTx = new AffineTransform();
}
@@ -113,8 +127,10 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
public void startedDrawingComponent() {
drawingComponent = true;
currentArea = new Area();
continuityPositiveAreas = new ArrayList<Area>();
continuityNegativeAreas = new ArrayList<Area>();
continuityPositiveAreas = new HashMap<String, Area>();
continuityNegativeAreas = new HashMap<String, Area>();
// trackingStacks.clear();
continuityMarker = null;
originalStroke = canvasGraphics.getStroke();
originalColor = canvasGraphics.getColor();
originalTx = canvasGraphics.getTransform();
@@ -138,7 +154,8 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
canvasGraphics.setTransform(originalTx);
canvasGraphics.setComposite(originalComposite);
canvasGraphics.setFont(originalFont);
return new ComponentArea(currentArea, continuityPositiveAreas, continuityNegativeAreas);
// Map<String, Integer> sorted = sortByComparator(trackingStacks, false);
return new ComponentArea(currentArea, continuityPositiveAreas.values(), continuityNegativeAreas.values());
}
@Override
@@ -165,7 +182,12 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
@Override
public boolean isTrackingContinuityArea() {
return trackingContinuityAllowed;
}
}
@Override
public void setContinuityMarker(String marker) {
continuityMarker = marker;
}
/**
* Appends shape interior to the current component area.
@@ -183,17 +205,40 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
area.transform(currentTx);
if (trackingAllowed)
currentArea.add(area);
currentArea.add(area);
Map<String, Area> toAdd;
if (trackingContinuityAllowed) {
if (trackingContinuityPositive)
continuityPositiveAreas.add(area);
toAdd = continuityPositiveAreas;
else
continuityNegativeAreas.add(area);
toAdd = continuityNegativeAreas;
String marker = continuityMarker == null ? ("internalUnique" + uniqueCounter++) : continuityMarker;
if (continuityMarker == null) {
toAdd.put(marker, area);
// markStack();
} else {
Area current = toAdd.getOrDefault(marker, null);
if (current == null) {
toAdd.put(marker, area);
// markStack();
} else
current.add(area);
}
}
lastShape = s;
}
}
private void markStack() {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
new Throwable().printStackTrace(pw);
String stack = sw.toString();
Integer currentCount = trackingStacks.getOrDefault(stack, 0);
currentCount++;
trackingStacks.put(stack, currentCount);
}
/**
* Appends shape outline to the current component area.
@@ -202,7 +247,7 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
*/
private void appendShapeOutline(Shape s) {
// Do not add shape outline if the same shape has been filled recently.
if (!drawingComponent || !trackingAllowed || s.equals(lastShape)) {
if (!drawingComponent || (!trackingAllowed && !trackingContinuityAllowed) || s.equals(lastShape)) {
return;
}
Stroke stroke = getStroke();
@@ -553,8 +598,15 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
}
@Override
public void drawPolyline(int[] points, int[] points2, int points3) {
canvasGraphics.drawPolyline(points, points2, points3);
public void drawPolyline(int[] pointsX, int[] pointsY, int pointCount) {
canvasGraphics.drawPolyline(pointsX, pointsY, pointCount);
if (drawingComponent && (trackingAllowed || trackingContinuityAllowed) && pointCount > 1) {
Path2D path = new Path2D.Double();
path.moveTo(pointsX[0], pointsY[0]);
for (int i = 1; i < pointCount; i++)
path.lineTo(pointsX[i], pointsY[i]);
appendShapeOutline(path);
}
}
@Override
@@ -667,4 +719,30 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
public void setXORMode(Color c1) {
canvasGraphics.setXORMode(c1);
}
private static Map<String, Integer> sortByComparator(Map<String, Integer> unsortMap,
final boolean order) {
List<Entry<String, Integer>> list =
new LinkedList<Entry<String, Integer>>(unsortMap.entrySet());
// Sorting the list based on values
Collections.sort(list, new Comparator<Entry<String, Integer>>() {
public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
if (order) {
return o1.getValue().compareTo(o2.getValue());
} else {
return o2.getValue().compareTo(o1.getValue());
}
}
});
// Maintaining insertion order with the help of LinkedList
Map<String, Integer> sortedMap = new LinkedHashMap<String, Integer>();
for (Entry<String, Integer> entry : list) {
sortedMap.put(entry.getKey(), entry.getValue());
}
return sortedMap;
}
}
@@ -1946,6 +1946,10 @@ public class Presenter implements IPlugInPort {
LOG.info(String.format("expandSelection(%s)", expansionMode));
List<IDIYComponent<?>> newSelection = new ArrayList<IDIYComponent<?>>(this.selectedComponents);
List<Netlist> netlists = extractNetlists(false);
if (netlists == null)
return;
List<Set<IDIYComponent<?>>> allGroups = NetlistAnalyzer.extractComponentGroups(netlists);
// Find control points of all selected components and all types
Set<String> selectedNamePrefixes = new HashSet<String>();
Binary file not shown.
@@ -324,7 +324,8 @@ public class Breadboard extends AbstractComponent<Void> {
@Override
public Point getControlPoint(int index) {
if (index == 0)
return point;
return point;
// create a synthetic second control point for clipping check and to make sure that we cannot drag the right side of the board off the screen
double spacing = SPACING.convertToPixels();
int holeCount = getBreadboardSize() == BreadboardSize.Full ? 63 : 30;
// adjust the angle
Binary file not shown.