Highlight connected areas through copper traces, leads, jumpers, etc...

This commit is contained in:
Branislav Stojkovic
2018-12-16 00:52:15 +01:00
parent d506feac27
commit 58a4ff987f
25 changed files with 1685 additions and 1364 deletions
@@ -1,24 +1,20 @@
/*
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/>.
*/
*
* 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.common;
import javax.swing.Icon;
@@ -53,11 +49,12 @@ public class ComponentType {
private IComponentTransformer transformer;
private KeywordPolicy keywordPolicy;
private String keywordTag;
private boolean continuity;
public ComponentType(String name, String description, CreationMethod creationMethod, String category,
String namePrefix, String author, Icon icon, Class<? extends IDIYComponent<?>> instanceClass, double zOrder,
boolean flexibleZOrder, boolean stretchable, BomPolicy bomPolicy, boolean autoEdit, IComponentTransformer transformer,
KeywordPolicy keywordPolicy, String keywordTag) {
boolean flexibleZOrder, boolean stretchable, BomPolicy bomPolicy, boolean autoEdit,
IComponentTransformer transformer, KeywordPolicy keywordPolicy, String keywordTag, boolean continuity) {
super();
this.name = name;
this.description = description;
@@ -75,6 +72,7 @@ public class ComponentType {
this.transformer = transformer;
this.keywordPolicy = keywordPolicy;
this.keywordTag = keywordTag;
this.continuity = continuity;
}
public String getName() {
@@ -141,6 +139,10 @@ public class ComponentType {
return keywordTag;
}
public boolean isContinuity() {
return continuity;
}
@Override
public String toString() {
return name;
@@ -71,6 +71,7 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
public static final String RECENT_FILES_KEY = "recentFiles";
public static final String SHOW_RULERS_KEY = "showRulers";
public static final String SHOW_GRID_KEY = "showGrid";
public static final String HIGHLIGHT_CONTINUITY_AREA = "highlightContinuityArea";
public static final int DND_TOGGLE_STICKY = 0x1;
public static final int DND_TOGGLE_SNAP = 0x40000000;
@@ -61,7 +61,7 @@ public abstract class AbstractCurvedComponent<T> extends AbstractTransparentComp
* @param componentState
* @param theme
*/
protected abstract void drawCurve(CubicCurve2D curve, Graphics2D g2d, ComponentState componentState);
protected abstract void drawCurve(CubicCurve2D curve, Graphics2D g2d, ComponentState componentState, IDrawingObserver drawingObserver);
/**
* @return default color.
@@ -110,7 +110,7 @@ public abstract class AbstractCurvedComponent<T> extends AbstractTransparentComp
// g2d.setColor(color);
// g2d.setStroke(new BasicStroke(thickness - 2));
// g2d.draw(path);
drawCurve(curve, g2d, componentState);
drawCurve(curve, g2d, componentState, drawingObserver);
g2d.setComposite(oldComposite);
}
@@ -32,6 +32,7 @@ import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.util.Observable;
import org.diylc.appframework.miscutils.ConfigurationManager;
import org.diylc.common.Display;
@@ -86,6 +87,10 @@ public abstract class AbstractLeadedComponent<T> extends AbstractTransparentComp
}
}
protected boolean IsCopperArea() {
return false;
}
@Override
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
IDrawingObserver drawingObserver) {
@@ -93,7 +98,7 @@ public abstract class AbstractLeadedComponent<T> extends AbstractTransparentComp
Shape shape = getBodyShape();
// If there's no body, just draw the line connecting the ending points.
if (shape == null) {
drawLead(g2d, componentState);
drawLead(g2d, componentState, drawingObserver, IsCopperArea());
} else if (supportsStandingMode() && length.convertToPixels() > points[0].distance(points[1])) {
// When ending points are too close draw the component in standing
// mode.
@@ -124,7 +129,7 @@ public abstract class AbstractLeadedComponent<T> extends AbstractTransparentComp
g2d.setColor(finalBorderColor);
g2d.draw(body);
if (!outlineMode) {
drawLead(g2d, componentState);
drawLead(g2d, componentState, drawingObserver, false);
}
} else {
// Normal mode with component body in the center and two lead parts.
@@ -293,13 +298,18 @@ public abstract class AbstractLeadedComponent<T> extends AbstractTransparentComp
g2d.drawLine(points[1].x, points[1].y, endX, endY);
}
private void drawLead(Graphics2D g2d, ComponentState componentState) {
private void drawLead(Graphics2D g2d, ComponentState componentState, IDrawingObserver observer, boolean isCopperArea) {
if (isCopperArea)
observer.startTrackingContinuityArea(true);
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(getLeadThickness()));
Color leadColor =
shouldShadeLeads() ? getLeadColorForPainting(componentState).darker() : getLeadColorForPainting(componentState);
g2d.setColor(leadColor);
g2d.drawLine(points[0].x, points[0].y, points[1].x, points[1].y);
if (isCopperArea)
observer.stopTrackingContinuityArea();
if (shouldShadeLeads()) {
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(getLeadThickness() - 2));
leadColor = getLeadColorForPainting(componentState);
@@ -32,4 +32,8 @@ public interface IDrawingObserver {
void stopTracking();
void startTracking();
void stopTrackingContinuityArea();
void startTrackingContinuityArea(boolean positive);
}
@@ -118,4 +118,11 @@ public @interface ComponentDescriptor {
*/
String keywordTag() default "";
/**
* For components that show continuity between the two ending points, e.d. wires, jumpers, etc.
*
* @return
*/
boolean continuity() default false;
}
@@ -0,0 +1,51 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.presenter;
import java.awt.geom.Area;
import java.util.List;
public class ComponentArea {
private Area outlineArea;
private List<Area> continuityPositiveAreas;
private List<Area> continuityNegativeAreas;
public ComponentArea(Area outlineArea, List<Area> continuityPositiveAreas, List<Area> continuityNegativeAreas) {
super();
this.outlineArea = outlineArea;
this.continuityPositiveAreas = continuityPositiveAreas;
this.continuityNegativeAreas = continuityNegativeAreas;
}
public Area getOutlineArea() {
return outlineArea;
}
public List<Area> getContinuityPositiveAreas() {
return continuityPositiveAreas;
}
public List<Area> getContinuityNegativeAreas() {
return continuityNegativeAreas;
}
}
@@ -98,6 +98,7 @@ public class ComponentProcessor {
IComponentTransformer transformer;
KeywordPolicy keywordPolicy;
String keywordTag;
boolean continuity;
if (clazz.isAnnotationPresent(ComponentDescriptor.class)) {
ComponentDescriptor annotation = clazz.getAnnotation(ComponentDescriptor.class);
name = annotation.name();
@@ -114,6 +115,7 @@ public class ComponentProcessor {
transformer = getComponentTransformer(annotation.transformer());
keywordPolicy = annotation.keywordPolicy();
keywordTag = annotation.keywordTag();
continuity = annotation.continuity();
} else { // default
name = clazz.getSimpleName();
description = "";
@@ -129,6 +131,7 @@ public class ComponentProcessor {
transformer = null;
keywordPolicy = KeywordPolicy.NEVER_SHOW;
keywordTag = null;
continuity = false;
}
icon = null;
// Draw component icon.
@@ -148,7 +151,7 @@ public class ComponentProcessor {
}
ComponentType componentType =
new ComponentType(name, description, creationMethod, category, namePrefix, author, icon, clazz, zOrder,
flexibleZOrder, stretchable, bomPolicy, autoEdit, transformer, keywordPolicy, keywordTag);
flexibleZOrder, stretchable, bomPolicy, autoEdit, transformer, keywordPolicy, keywordTag, continuity);
componentTypeMap.put(clazz.getName(), componentType);
return componentType;
}
@@ -1,24 +1,20 @@
/*
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/>.
*/
*
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
*
* This file is part of DIYLC.
*
* DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with DIYLC. If not, see
* <http://www.gnu.org/licenses/>.
*/
package org.diylc.presenter;
import java.awt.AlphaComposite;
@@ -31,6 +27,8 @@ import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.Area;
import java.awt.geom.Path2D;
import java.awt.geom.PathIterator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -41,6 +39,7 @@ import java.util.Set;
import org.apache.log4j.Logger;
import org.diylc.appframework.miscutils.ConfigurationManager;
import org.diylc.appframework.simplemq.MessageDispatcher;
import org.diylc.common.ComponentType;
import org.diylc.common.DrawOption;
import org.diylc.common.EventType;
import org.diylc.common.GridType;
@@ -69,6 +68,7 @@ public class DrawingManager {
public static final String ZOOM_KEY = "zoom";
public static String DEBUG_COMPONENT_AREAS = "org.diylc.debugComponentAreas";
public static String DEBUG_CONTINUITY_AREAS = "org.diylc.debugContinuityAreas";
public static Color CONTROL_POINT_COLOR = Color.blue;
public static Color SELECTED_CONTROL_POINT_COLOR = Color.green;
@@ -77,11 +77,13 @@ public class DrawingManager {
Constants.DEFAULT_THEME);
// Keeps Area object of each drawn component.
private Map<IDIYComponent<?>, Area> componentAreaMap;
private Map<IDIYComponent<?>, ComponentArea> componentAreaMap;
// Maps components to the last state they are drawn in. Also, used to
// determine which components are invalidated when they are not in the map.
private Map<IDIYComponent<?>, ComponentState> lastDrawnStateMap;
private Area continuityArea;
private Composite slotComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f);
private Composite lockedComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f);
private List<IDIYComponent<?>> failedComponents = new ArrayList<IDIYComponent<?>>();
@@ -92,14 +94,18 @@ public class DrawingManager {
private MessageDispatcher<EventType> messageDispatcher;
private boolean debugComponentAreas;
private boolean debugContinuityAreas;
public DrawingManager(MessageDispatcher<EventType> messageDispatcher) {
super();
this.messageDispatcher = messageDispatcher;
componentAreaMap = new HashMap<IDIYComponent<?>, Area>();
componentAreaMap = new HashMap<IDIYComponent<?>, ComponentArea>();
lastDrawnStateMap = new HashMap<IDIYComponent<?>, ComponentState>();
String debugComponentAreasStr = System.getProperty(DEBUG_COMPONENT_AREAS);
debugComponentAreas = debugComponentAreasStr != null && debugComponentAreasStr.equalsIgnoreCase("true");
String debugContinuityAreasStr = System.getProperty(DEBUG_CONTINUITY_AREAS);
debugContinuityAreas = debugContinuityAreasStr != null && debugContinuityAreasStr.equalsIgnoreCase("true");
}
/**
@@ -230,8 +236,8 @@ public class DrawingManager {
LOG.error("Error drawing " + component.getName(), e);
failedComponents.add(component);
}
Area area = g2dWrapper.finishedDrawingComponent();
if (trackArea && area != null && !area.isEmpty()) {
ComponentArea area = g2dWrapper.finishedDrawingComponent();
if (trackArea && area != null && !area.getOutlineArea().isEmpty()) {
componentAreaMap.put(component, area);
lastDrawnStateMap.put(component, state);
}
@@ -330,11 +336,35 @@ public class DrawingManager {
if (debugComponentAreas) {
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
g2d.setColor(Color.red);
for (Area area : componentAreaMap.values()) {
g2d.draw(area);
for (ComponentArea area : componentAreaMap.values()) {
g2d.draw(area.getOutlineArea());
}
}
// Draw continuity area for test
if (debugContinuityAreas) {
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
g2d.setColor(Color.green);
for (ComponentArea area : componentAreaMap.values()) {
for (Area a : area.getContinuityPositiveAreas())
g2d.draw(a);
}
g2d.setColor(Color.blue);
for (ComponentArea area : componentAreaMap.values()) {
for (Area a : area.getContinuityNegativeAreas())
g2d.draw(a);
}
}
if (continuityArea != null && (ConfigurationManager.getInstance().readBoolean(IPlugInPort.HIGHLIGHT_CONTINUITY_AREA, false)))
{
Composite oldComposite = g2d.getComposite();
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
g2d.setColor(Color.green);
g2d.fill(continuityArea);
g2d.setComposite(oldComposite);
}
return failedComponents;
}
@@ -353,7 +383,7 @@ public class DrawingManager {
lastDrawnStateMap.remove(component);
}
public Area getComponentArea(IDIYComponent<?> component) {
public ComponentArea getComponentArea(IDIYComponent<?> component) {
return componentAreaMap.get(component);
}
@@ -365,8 +395,8 @@ public class DrawingManager {
public List<IDIYComponent<?>> findComponentsAt(Point point, Project project) {
List<IDIYComponent<?>> components = new ArrayList<IDIYComponent<?>>();
for (int i = 0; i < project.getComponents().size(); i++) {
Area area = componentAreaMap.get(project.getComponents().get(i));
if (area != null && area.contains(point)) {
ComponentArea area = componentAreaMap.get(project.getComponents().get(i));
if (area != null && area.getOutlineArea().contains(point)) {
components.add(0, project.getComponents().get(i));
}
}
@@ -400,4 +430,162 @@ public class DrawingManager {
ConfigurationManager.getInstance().writeValue(IPlugInPort.THEME_KEY, theme);
messageDispatcher.dispatchMessage(EventType.REPAINT);
}
@SuppressWarnings("unchecked")
public void findContinuityAreaAtPoint(Project project, Point p) {
// Find all individual continuity areas for all components
List<Area> preliminaryAreas = new ArrayList<Area>();
List<Boolean> checkBreakout = new ArrayList<Boolean>();
List<Connection> connections = new ArrayList<Connection>();
for (IDIYComponent<?> c : project.getComponents()) {
ComponentArea a = getComponentArea(c);
ComponentType type =
ComponentProcessor.getInstance().extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) c.getClass());
if (type.isContinuity()) {
connections.add(new Connection(c.getControlPoint(0), c.getControlPoint(c.getControlPointCount() - 1)));
}
if (a == null || a.getOutlineArea() == null)
continue;
if (a.getContinuityPositiveAreas() != null)
for (Area a1 : a.getContinuityPositiveAreas()) {
preliminaryAreas.add(a1);
checkBreakout.add(false);
}
if (a.getContinuityNegativeAreas() != null) {
for (Area na : a.getContinuityNegativeAreas())
for (int i = 0; i < preliminaryAreas.size(); i++) {
Area a1 = preliminaryAreas.get(i);
if (a1.intersects(na.getBounds2D())) {
a1.subtract(na);
checkBreakout.set(i, true);
}
}
}
}
// Check if we need to break some areas out in case they are interrupted
List<Area> areas = new ArrayList<Area>();
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);
}
crunchAreas(areas, connections);
for (Area a : areas) {
if (a.contains(p)) {
continuityArea = a;
return;
}
}
continuityArea = null;
}
private boolean crunchAreas(List<Area> areas, List<Connection> connections) {
boolean isChanged = false;
List<Area> newAreas = new ArrayList<Area>();
List<Boolean> consumed = new ArrayList<Boolean>();
for (int i = 0; i < areas.size(); i++) {
consumed.add(false);
}
for (int i = 0; i < areas.size(); i++) {
for (int j = i + 1; j < areas.size(); j++) {
if (consumed.get(j))
continue;
Area a1 = areas.get(i);
Area a2 = areas.get(j);
Area intersection = new Area(a1);
intersection.intersect(a2);
// if the two areas intersect, make a union and consume the second area
if (!intersection.isEmpty()) {
a1.add(a2);
consumed.set(j, true);
} else { // maybe there's a connection between them
for (Connection p : connections) {
if ((a1.contains(p.pointA) && a2.contains(p.pointB)) || (a1.contains(p.pointB) && a2.contains(p.pointA))) {
a1.add(a2);
consumed.set(j, true);
break;
}
}
}
}
}
for (int i = 0; i < areas.size(); i++)
if (!consumed.get(i))
newAreas.add(areas.get(i));
else
isChanged = true;
if (isChanged) {
areas.clear();
areas.addAll(newAreas);
crunchAreas(areas, connections);
}
return isChanged;
}
private List<Area> tryBreakout(Area a) {
List<Area> toReturn = new ArrayList<Area>();
Path2D p = null;
PathIterator pathIterator = a.getPathIterator(null);
while (!pathIterator.isDone()) {
double[] coord = new double[6];
int type = pathIterator.currentSegment(coord);
switch (type) {
case PathIterator.SEG_MOVETO:
if (p != null) {
Area partArea = new Area(p);
toReturn.add(partArea);
}
p = new Path2D.Double();
p.moveTo(coord[0], coord[1]);
break;
case PathIterator.SEG_LINETO:
p.lineTo(coord[0], coord[1]);
break;
case PathIterator.SEG_CUBICTO:
p.curveTo(coord[0], coord[1], coord[2], coord[3], coord[4], coord[5]);
break;
case PathIterator.SEG_QUADTO:
p.quadTo(coord[0], coord[1], coord[2], coord[3]);
break;
}
pathIterator.next();
}
if (p != null) {
Area partArea = new Area(p);
toReturn.add(partArea);
}
return toReturn;
}
class Connection {
private Point pointA;
private Point pointB;
public Connection(Point pointA, Point pointB) {
super();
this.pointA = pointA;
this.pointB = pointB;
}
public Point getPointA() {
return pointA;
}
public Point getPointB() {
return pointB;
}
}
}
@@ -1,24 +1,20 @@
/*
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/>.
*/
*
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
*
* This file is part of DIYLC.
*
* DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with DIYLC. If not, see
* <http://www.gnu.org/licenses/>.
*/
package org.diylc.presenter;
import java.awt.BasicStroke;
@@ -57,6 +53,8 @@ import java.awt.image.ImageObserver;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.RenderableImage;
import java.text.AttributedCharacterIterator;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.diylc.common.ObjectCache;
@@ -78,6 +76,8 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
private boolean drawingComponent = false;
private boolean trackingAllowed = true;
private boolean trackingContinuityAllowed = false;
private boolean trackingContinuityPositive = true;
private Graphics2D canvasGraphics;
private Stroke originalStroke;
@@ -88,6 +88,8 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
private AffineTransform currentTx;
private AffineTransform initialTx;
private Area currentArea;
private List<Area> currentContinuityPositiveAreas;
private List<Area> currentContinuityNegativeAreas;
private Shape lastShape;
private double zoom;
@@ -102,6 +104,8 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
this.canvasGraphics = canvasGraphics;
this.zoom = zoom;
currentArea = new Area();
currentContinuityPositiveAreas = new ArrayList<Area>();
currentContinuityNegativeAreas = new ArrayList<Area>();
currentTx = new AffineTransform();
}
@@ -111,6 +115,8 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
public void startedDrawingComponent() {
drawingComponent = true;
currentArea = new Area();
currentContinuityPositiveAreas = new ArrayList<Area>();
currentContinuityNegativeAreas = new ArrayList<Area>();
originalStroke = canvasGraphics.getStroke();
originalColor = canvasGraphics.getColor();
originalTx = canvasGraphics.getTransform();
@@ -127,14 +133,14 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
*
* @return
*/
public Area finishedDrawingComponent() {
public ComponentArea finishedDrawingComponent() {
drawingComponent = false;
canvasGraphics.setStroke(originalStroke);
canvasGraphics.setColor(originalColor);
canvasGraphics.setTransform(originalTx);
canvasGraphics.setComposite(originalComposite);
canvasGraphics.setFont(originalFont);
return currentArea;
return new ComponentArea(currentArea, currentContinuityPositiveAreas, currentContinuityNegativeAreas);
}
@Override
@@ -147,13 +153,25 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
this.trackingAllowed = false;
}
@Override
public void startTrackingContinuityArea(boolean positive) {
this.trackingContinuityAllowed = true;
this.trackingContinuityPositive = positive;
}
@Override
public void stopTrackingContinuityArea() {
this.trackingContinuityAllowed = false;
}
/**
* Appends shape interior to the current component area.
*
* @param s
*/
private void appendShape(Shape s) {
if (!drawingComponent || !trackingAllowed) {
if (!drawingComponent || (!trackingAllowed && !trackingContinuityAllowed)) {
return;
}
Rectangle2D bounds = s.getBounds2D();
@@ -161,7 +179,16 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
if (bounds.getWidth() > 1 && bounds.getHeight() > 1) {
Area area = new Area(s);
area.transform(currentTx);
currentArea.add(area);
if (trackingAllowed)
currentArea.add(area);
if (trackingContinuityAllowed) {
if (trackingContinuityPositive)
currentContinuityPositiveAreas.add(area);
else
currentContinuityNegativeAreas.add(area);
}
lastShape = s;
}
}
@@ -580,7 +607,7 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
@Override
public void drawLine(int x1, int y1, int x2, int y2) {
canvasGraphics.drawLine(x1, y1, x2, y2);
if (drawingComponent && trackingAllowed) {
if (drawingComponent && (trackingAllowed || trackingContinuityAllowed)) {
appendShapeOutline(new Line2D.Double(x1, y1, x2, y2));
}
}
@@ -588,7 +615,7 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
@Override
public void drawOval(int x, int y, int width, int height) {
canvasGraphics.drawOval(x, y, width, height);
if (drawingComponent && trackingAllowed) {
if (drawingComponent && (trackingAllowed || trackingContinuityAllowed)) {
appendShapeOutline(new Ellipse2D.Double(x, y, width, height));
}
}
@@ -596,7 +623,7 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
@Override
public void drawPolygon(int[] points, int[] points2, int points3) {
canvasGraphics.drawPolygon(points, points2, points3);
if (drawingComponent && trackingAllowed) {
if (drawingComponent && (trackingAllowed || trackingContinuityAllowed)) {
appendShapeOutline(new Polygon(points, points2, points3));
}
}
@@ -609,7 +636,7 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
@Override
public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
canvasGraphics.drawRoundRect(x, y, width, height, arcWidth, arcHeight);
if (drawingComponent && trackingAllowed) {
if (drawingComponent && (trackingAllowed || trackingContinuityAllowed)) {
appendShapeOutline(new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight));
}
}
@@ -617,7 +644,7 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
@Override
public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
canvasGraphics.fillArc(x, y, width, height, startAngle, arcAngle);
if (drawingComponent && trackingAllowed) {
if (drawingComponent && (trackingAllowed || trackingContinuityAllowed)) {
appendShape(new Arc2D.Double(x, y, width, height, startAngle, arcAngle, Arc2D.PIE));
}
}
@@ -625,7 +652,7 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
@Override
public void fillOval(int x, int y, int width, int height) {
canvasGraphics.fillOval(x, y, width, height);
if (drawingComponent && trackingAllowed) {
if (drawingComponent && (trackingAllowed || trackingContinuityAllowed)) {
appendShape(new Ellipse2D.Double(x, y, width, height));
}
}
@@ -633,7 +660,7 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
@Override
public void fillPolygon(int[] points, int[] points2, int points3) {
canvasGraphics.fillPolygon(points, points2, points3);
if (drawingComponent && trackingAllowed) {
if (drawingComponent && (trackingAllowed || trackingContinuityAllowed)) {
appendShape(new Polygon(points, points2, points3));
}
}
@@ -641,7 +668,7 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
@Override
public void drawRect(int x, int y, int width, int height) {
canvasGraphics.drawRect(x, y, width, height);
if (drawingComponent && trackingAllowed) {
if (drawingComponent && (trackingAllowed || trackingContinuityAllowed)) {
appendShapeOutline(new Rectangle(x, y, width, height));
}
}
@@ -649,7 +676,7 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
@Override
public void fillRect(int x, int y, int width, int height) {
canvasGraphics.fillRect(x, y, width, height);
if (drawingComponent && trackingAllowed) {
if (drawingComponent && (trackingAllowed || trackingContinuityAllowed)) {
appendShape(new Rectangle(x, y, width, height));
}
}
@@ -657,7 +684,7 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
@Override
public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
canvasGraphics.fillRoundRect(x, y, width, height, arcWidth, arcHeight);
if (drawingComponent && trackingAllowed) {
if (drawingComponent && (trackingAllowed || trackingContinuityAllowed)) {
appendShape(new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight));
}
}
@@ -63,7 +63,7 @@ public class InstantiationManager {
private static final ComponentType clipboardType = new ComponentType("Clipboard contents",
"Components from the clipboard", CreationMethod.SINGLE_CLICK, "Multi", "", "", null, null, 0, false, false, null,
false, null, KeywordPolicy.NEVER_SHOW, null);
false, null, KeywordPolicy.NEVER_SHOW, null, false);
public InstantiationManager() {}
@@ -212,8 +212,8 @@ public class Presenter implements IPlugInPort {
}
for (IDIYComponent<?> component : currentProject.getComponents()) {
if (!isComponentLocked(component) && isComponentVisible(component)) {
Area area = drawingManager.getComponentArea(component);
if (area != null && area.contains(scaledPoint)) {
ComponentArea area = drawingManager.getComponentArea(component);
if (area != null && area.getOutlineArea() != null && area.getOutlineArea().contains(scaledPoint)) {
return Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
}
}
@@ -600,6 +600,9 @@ public class Presenter implements IPlugInPort {
+ componentTypeSlot.getName());
projectFileManager.notifyFileChange();
}
} else if (ConfigurationManager.getInstance().readBoolean(HIGHLIGHT_CONTINUITY_AREA, false)) {
drawingManager.findContinuityAreaAtPoint(currentProject, scaledPoint);
messageDispatcher.dispatchMessage(EventType.REPAINT);
} else {
List<IDIYComponent<?>> newSelection = new ArrayList<IDIYComponent<?>>(selectedComponents);
List<IDIYComponent<?>> components = findComponentsAtScaled(scaledPoint);
@@ -867,11 +870,11 @@ public class Presenter implements IPlugInPort {
Area totalArea = new Area();
for (IDIYComponent<?> c : selectedComponents) {
Area compArea = drawingManager.getComponentArea(c);
if (compArea != null)
totalArea.add(compArea);
ComponentArea compArea = drawingManager.getComponentArea(c);
if (compArea != null && compArea.getOutlineArea() != null)
totalArea.add(compArea.getOutlineArea());
else
LOG.info("Area is null");
LOG.debug("Area is null");
}
if (drawingManager.getZoomLevel() != 1 && applyZoom) {
totalArea
@@ -1397,8 +1400,8 @@ public class Presenter implements IPlugInPort {
List<IDIYComponent<?>> newSelection = new ArrayList<IDIYComponent<?>>();
for (IDIYComponent<?> component : currentProject.getComponents()) {
if (!isComponentLocked(component) && isComponentVisible(component)) {
Area area = drawingManager.getComponentArea(component);
if ((area != null) && (selectionRect != null) && area.intersects(selectionRect)) {
ComponentArea area = drawingManager.getComponentArea(component);
if ((area != null && area.getOutlineArea() != null) && (selectionRect != null) && area.getOutlineArea().intersects(selectionRect)) {
newSelection.addAll(findAllGroupedComponents(component));
}
}
@@ -1801,16 +1804,16 @@ public class Presenter implements IPlugInPort {
for (IDIYComponent<?> component : getCurrentProject().getComponents()) {
// Skip already selected components or ones that cannot be stuck to
// other components.
Area area = drawingManager.getComponentArea(component);
if (newSelection.contains(component) || !component.isControlPointSticky(0) || area == null)
ComponentArea area = drawingManager.getComponentArea(component);
if (newSelection.contains(component) || !component.isControlPointSticky(0) || area == null || area.getOutlineArea() == null)
continue;
boolean matches = false;
for (IDIYComponent<?> selectedComponent : this.selectedComponents) {
Area selectedArea = drawingManager.getComponentArea(selectedComponent);
if (selectedArea == null)
ComponentArea selectedArea = drawingManager.getComponentArea(selectedComponent);
if (selectedArea == null || selectedArea.getOutlineArea() == null)
continue;
Area intersection = new Area(area);
intersection.intersect(selectedArea);
Area intersection = new Area(area.getOutlineArea());
intersection.intersect(selectedArea.getOutlineArea());
if (!intersection.isEmpty()) {
matches = true;
break;
Binary file not shown.
@@ -377,7 +377,9 @@ public class TerminalStrip extends AbstractTransparentComponent<String> {
g2d.draw(mainArea);
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : TERMINAL_COLOR);
drawingObserver.startTrackingContinuityArea(true);
g2d.fill(terminalArea);
drawingObserver.stopTrackingContinuityArea();
Color finalTerminalBorderColor;
if (outlineMode) {
@@ -95,8 +95,10 @@ public class TriPadBoard extends AbstractBoard {
}
g2d.setColor(stripColor);
drawingObserver.startTrackingContinuityArea(true);
g2d.fillRect(p.x + spacing - stripSize / 2, p.y - stripSize / 2, spacing * (spacesToDraw - 1) + stripSize,
stripSize);
drawingObserver.stopTrackingContinuityArea();
g2d.setColor(stripColor.darker());
g2d.drawRect(p.x + spacing - stripSize / 2, p.y - stripSize / 2, spacing * (spacesToDraw - 1) + stripSize,
@@ -131,8 +133,10 @@ public class TriPadBoard extends AbstractBoard {
}
g2d.setColor(stripColor);
drawingObserver.startTrackingContinuityArea(true);
g2d.fillRect(p.x - stripSize / 2, p.y + spacing - stripSize / 2, stripSize, spacing * (spacesToDraw - 1)
+ stripSize);
drawingObserver.stopTrackingContinuityArea();
g2d.setColor(stripColor.darker());
g2d.drawRect(p.x - stripSize / 2, p.y + spacing - stripSize / 2, stripSize, spacing * (spacesToDraw - 1)
+ stripSize);
@@ -85,7 +85,9 @@ public class VeroBoard extends AbstractBoard {
p.x = firstPoint.x;
p.y += spacing;
g2d.setColor(stripColor);
drawingObserver.startTrackingContinuityArea(true);
g2d.fillRect(p.x + spacing / 2, p.y - stripSize / 2, secondPoint.x - spacing - p.x, stripSize);
drawingObserver.stopTrackingContinuityArea();
g2d.setColor(stripColor.darker());
g2d.drawRect(p.x + spacing / 2, p.y - stripSize / 2, secondPoint.x - spacing - p.x, stripSize);
while (p.x < secondPoint.x - spacing - holeSize) {
@@ -101,7 +103,9 @@ public class VeroBoard extends AbstractBoard {
p.x += spacing;
p.y = firstPoint.y;
g2d.setColor(stripColor);
drawingObserver.startTrackingContinuityArea(true);
g2d.fillRect(p.x - stripSize / 2, p.y + spacing / 2, stripSize, secondPoint.y - spacing - p.y);
drawingObserver.stopTrackingContinuityArea();
g2d.setColor(stripColor.darker());
g2d.drawRect(p.x - stripSize / 2, p.y + spacing / 2, stripSize, secondPoint.y - spacing - p.y);
while (p.y < secondPoint.y - spacing - holeSize) {
@@ -31,6 +31,7 @@ import org.diylc.common.PCBLayer;
import org.diylc.components.AbstractCurvedComponent;
import org.diylc.core.ComponentState;
import org.diylc.core.IDIYComponent;
import org.diylc.core.IDrawingObserver;
import org.diylc.core.annotations.BomPolicy;
import org.diylc.core.annotations.ComponentDescriptor;
import org.diylc.core.annotations.EditableProperty;
@@ -58,14 +59,16 @@ public class CurvedTrace extends AbstractCurvedComponent<Void> {
}
@Override
protected void drawCurve(CubicCurve2D curve, Graphics2D g2d, ComponentState componentState) {
protected void drawCurve(CubicCurve2D curve, Graphics2D g2d, ComponentState componentState, IDrawingObserver drawingObserver) {
float thickness = (float) size.convertToPixels();
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(thickness));
Color curveColor =
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
: color;
g2d.setColor(curveColor);
drawingObserver.startTrackingContinuityArea(true);
g2d.draw(curve);
drawingObserver.stopTrackingContinuityArea();
}
@EditableProperty(name = "Width")
@@ -30,6 +30,7 @@ import org.diylc.common.SimpleComponentTransformer;
import org.diylc.components.AbstractCurvedComponent;
import org.diylc.core.ComponentState;
import org.diylc.core.IDIYComponent;
import org.diylc.core.IDrawingObserver;
import org.diylc.core.annotations.BomPolicy;
import org.diylc.core.annotations.ComponentDescriptor;
import org.diylc.core.annotations.EditableProperty;
@@ -38,7 +39,7 @@ import org.diylc.utils.Constants;
@ComponentDescriptor(name = "Hookup Wire", author = "Branislav Stojkovic", category = "Connectivity",
instanceNamePrefix = "W", description = "Flexible wire with two control points", zOrder = IDIYComponent.COMPONENT,
flexibleZOrder = true, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
transformer = SimpleComponentTransformer.class)
transformer = SimpleComponentTransformer.class, continuity = true)
public class HookupWire extends AbstractCurvedComponent<Void> {
private static final long serialVersionUID = 1L;
@@ -54,7 +55,7 @@ public class HookupWire extends AbstractCurvedComponent<Void> {
}
@Override
protected void drawCurve(CubicCurve2D curve, Graphics2D g2d, ComponentState componentState) {
protected void drawCurve(CubicCurve2D curve, Graphics2D g2d, ComponentState componentState, IDrawingObserver drawingObserver) {
int thickness =
(int) (Math.pow(Math.E, -1.12436 - 0.11594 * gauge.getValue()) * Constants.PIXELS_PER_INCH * (1 + 2 * INSULATION_THICKNESS_PCT));
Color curveColor =
@@ -40,7 +40,7 @@ import org.diylc.core.measures.Size;
@ComponentDescriptor(name = "Jumper", author = "Branislav Stojkovic", category = "Connectivity",
creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "J", description = "",
zOrder = IDIYComponent.COMPONENT, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
transformer = SimpleComponentTransformer.class)
transformer = SimpleComponentTransformer.class, continuity = true)
public class Jumper extends AbstractLeadedComponent<Void> {
private static final long serialVersionUID = 1L;
@@ -78,11 +78,15 @@ public class TraceCut extends AbstractComponent<Void> {
int holeSpacing = getClosestOdd(getHoleSpacing().convertToPixels());
g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
: boardColor);
drawingObserver.startTrackingContinuityArea(false);
g2d.fillRect(point.x - holeSpacing / 2 - cutWidth / 2, point.y - size / 2 - 1, cutWidth, size + 2);
drawingObserver.stopTrackingContinuityArea();
} else {
g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
: boardColor);
drawingObserver.startTrackingContinuityArea(false);
g2d.fillRoundRect(point.x - size / 2, point.y - size / 2, size, size, size, size);
drawingObserver.stopTrackingContinuityArea();
g2d.setColor(Constants.CANVAS_COLOR);
int holeSize = getClosestOdd((int) HOLE_SIZE.convertToPixels());
+1 -1
View File
@@ -11,5 +11,5 @@
<stringAttribute key="org.eclipse.debug.core.source_locator_memento" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;sourceLookupDirector&gt;&#13;&#10;&lt;sourceContainers duplicates=&quot;false&quot;&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;Library&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;DIYLC&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;diylc-core&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;javaProject name=&amp;quot;diylc-library&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#13;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;default/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.debug.core.containerType.default&quot;/&gt;&#13;&#10;&lt;/sourceContainers&gt;&#13;&#10;&lt;/sourceLookupDirector&gt;&#13;&#10;"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.diylc.DIYLCStarter"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="diylc-swing"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-splash:splash.png -Xms256m -Xmx512m -Dorg.diylc.scriptRun=true -Ddorg.diylc.debugComponentAreas=true"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-splash:splash.png -Xms256m -Xmx512m -Dorg.diylc.scriptRun=true -Ddorg.diylc.debugContinuityAreas=true"/>
</launchConfiguration>
Binary file not shown.
Binary file not shown.
@@ -100,6 +100,9 @@ public class ConfigPlugin implements IPlugIn {
swingUI.injectMenuAction(
ActionFactory.getInstance()
.createConfigAction(plugInPort, "Sticky Points", IPlugInPort.STICKY_POINTS_KEY, true), CONFIG_MENU);
swingUI.injectMenuAction(
ActionFactory.getInstance()
.createConfigAction(plugInPort, "Highlighted Connected Areas", IPlugInPort.HIGHLIGHT_CONTINUITY_AREA, false), CONFIG_MENU);
File themeDir = new File("themes");
if (themeDir.exists()) {
+4
View File
@@ -1874,6 +1874,10 @@
<releaseDate>2018-12-11 00:00:00.000 CET</releaseDate>
<name></name>
<changes>
<org.diylc.appframework.update.Change>
<changeType>NEW_FEATURE</changeType>
<description>Highlight connected areas through copper traces, leads, jumpers, etc...</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>NEW_FEATURE</changeType>
<description>Holding "shift" key switches mouse wheel scrolling function from vertical to horizontal</description>