generalize caching

This commit is contained in:
bancika
2020-04-06 21:47:07 +02:00
parent 7b3326a5cd
commit e29bdf5f62
17 changed files with 305 additions and 51 deletions
@@ -251,5 +251,10 @@ public abstract class AbstractComponent<T> implements IDIYComponent<T> {
@Override @Override
public boolean canPointMoveFreely(int pointIndex) { public boolean canPointMoveFreely(int pointIndex) {
return true; return true;
}
@Override
public Rectangle2D getCachingBounds() {
return null;
} }
} }
@@ -25,6 +25,7 @@ import java.awt.Point;
import java.awt.geom.CubicCurve2D; import java.awt.geom.CubicCurve2D;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.diylc.appframework.miscutils.ConfigurationManager; import org.diylc.appframework.miscutils.ConfigurationManager;
@@ -360,6 +361,28 @@ public abstract class AbstractCurvedComponent<T> extends AbstractTransparentComp
return null; return null;
} }
} }
@Override
public Rectangle2D getCachingBounds() {
int minX = Integer.MAX_VALUE;
int maxX = Integer.MIN_VALUE;
int minY = Integer.MAX_VALUE;
int maxY = Integer.MIN_VALUE;
int margin = 50; // hard coded, replace with something meaningful
for (int i = 0; i < getControlPointCount(); i++) {
Point p = getControlPoint(i);
if (p.x < minX)
minX = p.x;
if (p.x > maxX)
maxX = p.x;
if (p.y < minY)
minY = p.y;
if (p.y > maxY)
maxY = p.y;
}
return new Rectangle2D.Double(minX - margin, minY - margin, maxX - minX + 2 * margin, maxY - minY + 2 * margin);
}
public enum PointCount { public enum PointCount {
TWO(2), THREE(3), FOUR(4), FIVE(5), SEVEN(7); TWO(2), THREE(3), FOUR(4), FIVE(5), SEVEN(7);
@@ -22,7 +22,8 @@
package org.diylc.core; package org.diylc.core;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Point; import java.awt.Point;
import java.awt.geom.Rectangle2D;
import java.io.Serializable; import java.io.Serializable;
import org.diylc.core.annotations.ComponentDescriptor; import org.diylc.core.annotations.ComponentDescriptor;
@@ -189,5 +190,11 @@ public interface IDIYComponent<T> extends Serializable, Cloneable {
* @param other * @param other
* @return * @return
*/ */
boolean equalsTo(IDIYComponent<?> other); boolean equalsTo(IDIYComponent<?> other);
/**
* Used only if {@link ComponentDescriptor#enableCache()} is set to true.
* @return
*/
Rectangle2D getCachingBounds();
} }
@@ -0,0 +1,44 @@
/*
*
* 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.util.concurrent.TimeUnit;
public class Counter {
private int count;
private long nanotime;
public int getCount() {
return count;
}
public long getNanoTime() {
return nanotime;
}
public void add(long nanotime) {
count++;
this.nanotime += nanotime;
}
@Override
public String toString() {
return String.format("%dx %dms", count, TimeUnit.MILLISECONDS.convert(nanotime, TimeUnit.NANOSECONDS));
}
}
@@ -19,15 +19,19 @@ package org.diylc.presenter;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Point; import java.awt.Point;
import java.awt.geom.Area;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.diylc.common.ComponentType; import org.diylc.common.ComponentType;
import org.diylc.core.ComponentState; import org.diylc.core.ComponentState;
import org.diylc.core.IDIYComponent; import org.diylc.core.IDIYComponent;
import org.diylc.core.Project; import org.diylc.core.Project;
import org.diylc.utils.Pair;
/** /**
* A layer that injects itself between the provided {@link G2DWrapper} instance and the underlying * A layer that injects itself between the provided {@link G2DWrapper} instance and the underlying
@@ -39,8 +43,9 @@ import org.diylc.core.Project;
*/ */
public class DrawingCache { public class DrawingCache {
private Map<IDIYComponent<?>, CacheValue> imageCache = private Map<IDIYComponent<?>, CacheValue> imageCache = new HashMap<IDIYComponent<?>, CacheValue>();
new HashMap<IDIYComponent<?>, CacheValue>();
private Map<String, Pair<Counter, Counter>> renderStatsByType = new HashMap<String, Pair<Counter, Counter>>();
private static final Logger LOG = Logger.getLogger(DrawingCache.class); private static final Logger LOG = Logger.getLogger(DrawingCache.class);
@@ -55,7 +60,6 @@ public class DrawingCache {
if (type.getEnableCache()) { if (type.getEnableCache()) {
// if we need to apply caching // if we need to apply caching
Point firstPoint = component.getControlPoint(0); Point firstPoint = component.getControlPoint(0);
Point lastPoint = component.getControlPoint(component.getControlPointCount() - 1);
// cache hit! // cache hit!
CacheValue value = null; CacheValue value = null;
@@ -66,14 +70,22 @@ public class DrawingCache {
if (value == null || !value.getComponent().equalsTo(component) if (value == null || !value.getComponent().equalsTo(component)
|| value.getState() != componentState || value.getZoom() != zoom) { || value.getState() != componentState || value.getZoom() != zoom) {
LOG.trace("Rendering " + component.getName() + " for cache."); LOG.trace("Rendering " + component.getName() + " for cache.");
int width = (int) (Math.abs(firstPoint.x - lastPoint.x) * zoom) + 2; Rectangle2D rect = component.getCachingBounds();
int height = (int) (Math.abs(firstPoint.y - lastPoint.y) * zoom) + 2; int width = (int)Math.round(rect.getWidth() * zoom);
int height = (int)Math.round(rect.getHeight() * zoom);
// calculate the position of the first point relative to the caching bounds
int dx = (int) (firstPoint.x - rect.getX());
int dy = (int) (firstPoint.y - rect.getY());
// create image
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
// create graphics
Graphics2D cg2d = image.createGraphics(); Graphics2D cg2d = image.createGraphics();
// copy over rendering settings // copy over rendering settings so our cached image has the same features
cg2d.setRenderingHints(g2d.getRenderingHints()); cg2d.setRenderingHints(g2d.getRenderingHints());
// set clip bounds to the whole image
cg2d.setClip(0, 0, width, height); cg2d.setClip(0, 0, width, height);
// apply zoom // apply zoom
@@ -81,24 +93,41 @@ public class DrawingCache {
cg2d.scale(zoom, zoom); cg2d.scale(zoom, zoom);
} }
// translate to make the top-left corner of the component match (0, 0) // translate to make the top-left corner of the component match (0, 0)
cg2d.translate(-firstPoint.x, -firstPoint.y); cg2d.translate(-firstPoint.x + dx, -firstPoint.y + dy);
// wrap the graphics so we can track // wrap the graphics so we can track
G2DWrapper wrapper = new G2DWrapper(cg2d, zoom); G2DWrapper wrapper = new G2DWrapper(cg2d, zoom);
// initialize wrapper
wrapper.startedDrawingComponent(); wrapper.startedDrawingComponent();
if (!trackArea) { if (!trackArea) {
wrapper.stopTracking(); wrapper.stopTracking();
} }
long componentStart = System.nanoTime();
// now draw the component to the buffer image // now draw the component to the buffer image
component.draw(wrapper, componentState, outlineMode, project, wrapper); component.draw(wrapper, componentState, outlineMode, project, wrapper);
long componentEnd = System.nanoTime();
Pair<Counter, Counter> stats;
String key = component.getClass().getCanonicalName().replace("org.diylc.components.", "");
if (renderStatsByType.containsKey(key)) {
stats = renderStatsByType.get(key);
} else {
stats = new Pair<Counter, Counter>(new Counter(), new Counter());
renderStatsByType.put(key, stats);
}
stats.getFirst().add(componentEnd - componentStart);
// finalize wrapper
wrapper.finishedDrawingComponent(); wrapper.finishedDrawingComponent();
cg2d.dispose(); cg2d.dispose();
// File outputfile = new File("d:\\image_" + component.getName() + ".png"); // output cached drawings to separate files
// File outputfile = new File("d:\\tmp\\image_" + component.getName() + ".png");
// try { // try {
// ImageIO.write(image, "png", outputfile); // ImageIO.write(image, "png", outputfile);
// } catch (IOException e) { // } catch (IOException e) {
@@ -106,10 +135,13 @@ public class DrawingCache {
// e.printStackTrace(); // e.printStackTrace();
// } // }
value = new CacheValue(component, image, wrapper, componentState, zoom); // add to the cache
value = new CacheValue(component, image, wrapper.getCurrentArea(), wrapper.getContinuityPositiveAreas(),
wrapper.getContinuityNegativeAreas(), componentState, zoom, dx, dy);
imageCache.put(component, value); imageCache.put(component, value);
} }
long componentStart = System.nanoTime();
// temporarily scale the graphic to compensate for the zoom, since we are rendering an image with the zoom appled // temporarily scale the graphic to compensate for the zoom, since we are rendering an image with the zoom appled
if (Math.abs(1.0 - zoom) > 1e-4) { if (Math.abs(1.0 - zoom) > 1e-4) {
@@ -117,21 +149,45 @@ public class DrawingCache {
} }
try { try {
// draw cached image // draw cached image
g2d.getCanvasGraphics().drawImage(value.getImage(), (int) (firstPoint.x * zoom), g2d.getCanvasGraphics().drawImage(value.getImage(), (int) ((firstPoint.x - value.getDx()) * zoom),
(int) (firstPoint.y * zoom), null); (int) ((firstPoint.y - value.getDy())* zoom), null);
} finally { } finally {
if (Math.abs(1.0 - zoom) > 1e-4) { if (Math.abs(1.0 - zoom) > 1e-4) {
g2d.getCanvasGraphics().scale(zoom, zoom); g2d.getCanvasGraphics().scale(zoom, zoom);
} }
} }
long componentEnd = System.nanoTime();
Pair<Counter, Counter> stats;
String key = component.getClass().getCanonicalName().replace("org.diylc.components.", "");
if (renderStatsByType.containsKey(key)) {
stats = renderStatsByType.get(key);
} else {
stats = new Pair<Counter, Counter>(new Counter(), new Counter());
renderStatsByType.put(key, stats);
}
stats.getSecond().add(componentEnd - componentStart);
// copy over tracking area from the cache // copy over tracking area from the cache
g2d.merge(value.getWrapper()); g2d.merge(value.getCurrentArea(), value.getContinuityPositiveAreas(), value.getContinuityNegativeAreas());
} else { } else {
// no caching, just draw as usual // no caching, just draw as usual
component.draw(g2d, componentState, outlineMode, project, g2d); component.draw(g2d, componentState, outlineMode, project, g2d);
} }
} }
public void logStats() {
int totalSizeMB = imageCache.values().stream().map(x -> x.image.getData().getDataBuffer().getSize()).reduce(0, Integer::sum) * 4 / 1024 / 1024; // 4 bytes per pixel
LOG.debug(String.format("Render cache contains %d elements, approx size is %d MB", imageCache.size(), totalSizeMB));
String mapAsString = renderStatsByType.entrySet().stream().sorted((e1, e2) -> -Long.compare(e1.getValue().getFirst().getNanoTime() + e1.getValue().getSecond().getNanoTime(),
e2.getValue().getFirst().getNanoTime() + e2.getValue().getSecond().getNanoTime()))
.map(e -> e.getKey() + ": render: " + e.getValue().getFirst() + ", paste: " + e.getValue().getSecond())
.collect(Collectors.joining("; ", "{", "}"));
LOG.debug("Cache render distribution stats: " + mapAsString);
}
public void clear() { public void clear() {
imageCache.clear(); imageCache.clear();
@@ -140,12 +196,17 @@ public class DrawingCache {
private class CacheValue { private class CacheValue {
IDIYComponent<?> component; IDIYComponent<?> component;
BufferedImage image; BufferedImage image;
G2DWrapper wrapper; Area currentArea;
Map<String, Area> continuityPositiveAreas;
Map<String, Area> continuityNegativeAreas;
ComponentState state; ComponentState state;
double zoom; double zoom;
int dx;
int dy;
public CacheValue(IDIYComponent<?> component, BufferedImage image, G2DWrapper wrapper, public CacheValue(IDIYComponent<?> component, BufferedImage image, Area currentArea,
ComponentState state, double zoom) { Map<String, Area> continuityPositiveAreas, Map<String, Area> continuityNegativeAreas,
ComponentState state, double zoom, int dx, int dy) {
super(); super();
// take a copy of the component, so we can check if it changed in the meantime // take a copy of the component, so we can check if it changed in the meantime
try { try {
@@ -153,9 +214,13 @@ public class DrawingCache {
} catch (CloneNotSupportedException e) { } catch (CloneNotSupportedException e) {
} }
this.image = image; this.image = image;
this.wrapper = wrapper; this.currentArea = currentArea;
this.continuityPositiveAreas = continuityPositiveAreas;
this.continuityNegativeAreas = continuityNegativeAreas;
this.state = state; this.state = state;
this.zoom = zoom; this.zoom = zoom;
this.dx = dx;
this.dy = dy;
} }
public IDIYComponent<?> getComponent() { public IDIYComponent<?> getComponent() {
@@ -166,8 +231,16 @@ public class DrawingCache {
return image; return image;
} }
public G2DWrapper getWrapper() { public Area getCurrentArea() {
return wrapper; return currentArea;
}
public Map<String, Area> getContinuityPositiveAreas() {
return continuityPositiveAreas;
}
public Map<String, Area> getContinuityNegativeAreas() {
return continuityNegativeAreas;
} }
public ComponentState getState() { public ComponentState getState() {
@@ -177,6 +250,14 @@ public class DrawingCache {
public double getZoom() { public double getZoom() {
return zoom; return zoom;
} }
public int getDx() {
return dx;
}
public int getDy() {
return dy;
}
@Override @Override
public String toString() { public String toString() {
@@ -58,7 +58,6 @@ import org.diylc.core.Project;
import org.diylc.core.Theme; import org.diylc.core.Theme;
import org.diylc.core.VisibilityPolicy; import org.diylc.core.VisibilityPolicy;
import org.diylc.utils.Constants; import org.diylc.utils.Constants;
import org.diylc.utils.Pair;
/** /**
* Utility that deals with painting {@link Project} on the {@link Graphics2D} and keeps areas taken * Utility that deals with painting {@link Project} on the {@link Graphics2D} and keeps areas taken
@@ -109,7 +108,7 @@ public class DrawingManager {
private boolean debugContinuityAreas; private boolean debugContinuityAreas;
// rendering stats // rendering stats
private Map<String, Pair<Integer, Long>> renderStatsByType = new HashMap<String, Pair<Integer, Long>>(); private Map<String, Counter> renderStatsByType = new HashMap<String, Counter>();
private long lastStatsReportedTime = System.currentTimeMillis(); private long lastStatsReportedTime = System.currentTimeMillis();
private long statReportFrequencyMs = 1000 * 60; private long statReportFrequencyMs = 1000 * 60;
@@ -305,26 +304,15 @@ public class DrawingManager {
} finally { } finally {
// record render stats // record render stats
long componentEnd = System.nanoTime(); long componentEnd = System.nanoTime();
Pair<Integer, Long> stats = null; Counter stats = null;
String key = component.getClass().getCanonicalName(); String key = component.getClass().getCanonicalName().replace("org.diylc.components.", "");
if (renderStatsByType.containsKey(key)) { if (renderStatsByType.containsKey(key)) {
stats = renderStatsByType.get(key); stats = renderStatsByType.get(key);
stats.setFirst(stats.getFirst() + 1);
stats.setSecond(stats.getSecond() + (componentEnd - componentStart));
} else { } else {
stats = new Pair<Integer, Long>(1, componentEnd - componentStart); stats = new Counter();
renderStatsByType.put(key, stats); renderStatsByType.put(key, stats);
} }
stats.add(componentEnd - componentStart);
// log render time stats periodically
if (System.currentTimeMillis() - lastStatsReportedTime > statReportFrequencyMs) {
lastStatsReportedTime = System.currentTimeMillis();
String mapAsString = renderStatsByType.entrySet().stream().sorted((e1, e2) -> -e1.getValue().getSecond().compareTo(e2.getValue().getSecond()))
.map(e -> e.getKey() + "=" + e.getValue().getFirst() + "x " +
TimeUnit.MILLISECONDS.convert( e.getValue().getSecond(), TimeUnit.NANOSECONDS) + "ms ")
.collect(Collectors.joining(", ", "{", "}"));
LOG.debug("Render stats: " + mapAsString);
}
} }
ComponentArea area = g2dWrapper.finishedDrawingComponent(); ComponentArea area = g2dWrapper.finishedDrawingComponent();
if (trackArea && area != null && !area.getOutlineArea().isEmpty()) { if (trackArea && area != null && !area.getOutlineArea().isEmpty()) {
@@ -469,9 +457,23 @@ public class DrawingManager {
long ms = TimeUnit.MILLISECONDS.convert(end - start, TimeUnit.NANOSECONDS); long ms = TimeUnit.MILLISECONDS.convert(end - start, TimeUnit.NANOSECONDS);
LOG.trace(String.format("Render time = %d ms", ms)); LOG.trace(String.format("Render time = %d ms", ms));
logStats();
return failedComponents; return failedComponents;
} }
public void logStats() {
// log render time stats periodically
if (System.currentTimeMillis() - lastStatsReportedTime > statReportFrequencyMs) {
lastStatsReportedTime = System.currentTimeMillis();
String mapAsString = renderStatsByType.entrySet().stream().sorted((e1, e2) -> -Long.compare(e1.getValue().getNanoTime(), e2.getValue().getNanoTime()))
.map(e -> e.toString())
.collect(Collectors.joining("; ", "{", "}"));
LOG.debug("Render stats: " + mapAsString);
DrawingCache.Instance.logStats();
}
}
public double getZoomLevel() { public double getZoomLevel() {
return zoomLevel; return zoomLevel;
@@ -162,10 +162,26 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
return new ComponentArea(currentArea, continuityPositiveAreas.values(), continuityNegativeAreas.values()); return new ComponentArea(currentArea, continuityPositiveAreas.values(), continuityNegativeAreas.values());
} }
public void merge(G2DWrapper wrapper) { // start - used for caching
currentArea = wrapper.currentArea;
continuityPositiveAreas = wrapper.continuityPositiveAreas; public Area getCurrentArea() {
continuityNegativeAreas = wrapper.continuityNegativeAreas; return currentArea;
}
public Map<String, Area> getContinuityPositiveAreas() {
return continuityPositiveAreas;
}
public Map<String, Area> getContinuityNegativeAreas() {
return continuityNegativeAreas;
}
// end - used for caching
public void merge(Area currentArea, Map<String, Area> continuityPositiveAreas, Map<String, Area> continuityNegativeAreas) {
this.currentArea = currentArea;
this.continuityPositiveAreas = continuityPositiveAreas;
this.continuityNegativeAreas = continuityNegativeAreas;
} }
@Override @Override
@@ -668,6 +668,28 @@ public abstract class AbstractLeadedComponent<T> extends AbstractTransparentComp
return null; return null;
return Integer.toString(index + 1); return Integer.toString(index + 1);
} }
@Override
public Rectangle2D getCachingBounds() {
int minX = Integer.MAX_VALUE;
int maxX = Integer.MIN_VALUE;
int minY = Integer.MAX_VALUE;
int maxY = Integer.MIN_VALUE;
int margin = (int) Math.max(Math.max(getWidth().convertToPixels(), getLength().convertToPixels()), getLeadThickness());
for (int i = 0; i < getControlPointCount(); i++) {
Point p = getControlPoint(i);
if (p.x < minX)
minX = p.x;
if (p.x > maxX)
maxX = p.x;
if (p.y < minY)
minY = p.y;
if (p.y > maxY)
maxY = p.y;
}
return new Rectangle2D.Double(minX - margin, minY - margin, maxX - minX + 2 * margin, maxY - minY + 2 * margin);
}
public enum LabelOriantation { public enum LabelOriantation {
Directional, Horizontal Directional, Horizontal
@@ -26,6 +26,7 @@ import java.awt.Color;
import java.awt.Composite; import java.awt.Composite;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Point; import java.awt.Point;
import java.awt.geom.Rectangle2D;
import org.diylc.awt.StringUtils; import org.diylc.awt.StringUtils;
import org.diylc.common.HorizontalAlignment; import org.diylc.common.HorizontalAlignment;
@@ -332,6 +333,12 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
public void setMode(BoardSizingMode mode) { public void setMode(BoardSizingMode mode) {
this.mode = mode; this.mode = mode;
} }
@Override
public Rectangle2D getCachingBounds() {
Point finalSecondPoint = getFinalSecondPoint();
return new Rectangle2D.Double(firstPoint.x, firstPoint.y, finalSecondPoint.x - firstPoint.x + 1, finalSecondPoint.y - firstPoint.y + 1);
}
public static enum CoordinateType { public static enum CoordinateType {
Letters, Numbers Letters, Numbers
@@ -39,7 +39,8 @@ import org.diylc.core.measures.SizeUnit;
@ComponentDescriptor(name = "Curved Trace", author = "Branislav Stojkovic", category = "Connectivity", @ComponentDescriptor(name = "Curved Trace", author = "Branislav Stojkovic", category = "Connectivity",
instanceNamePrefix = "Trace", description = "Curved copper trace with two control points", instanceNamePrefix = "Trace", description = "Curved copper trace with two control points",
zOrder = IDIYComponent.TRACE, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, zOrder = IDIYComponent.TRACE, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "PCB", transformer = SimpleComponentTransformer.class) keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "PCB", transformer = SimpleComponentTransformer.class,
enableCache = true)
public class CurvedTrace extends AbstractCurvedComponent<Void> { public class CurvedTrace extends AbstractCurvedComponent<Void> {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -39,7 +39,7 @@ import org.diylc.utils.Constants;
@ComponentDescriptor(name = "Hookup Wire", author = "Branislav Stojkovic", category = "Connectivity", @ComponentDescriptor(name = "Hookup Wire", author = "Branislav Stojkovic", category = "Connectivity",
instanceNamePrefix = "W", description = "Flexible wire with two control points", zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "W", description = "Flexible wire with two control points", zOrder = IDIYComponent.COMPONENT,
flexibleZOrder = true, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, flexibleZOrder = true, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
transformer = SimpleComponentTransformer.class) transformer = SimpleComponentTransformer.class, enableCache = true)
public class HookupWire extends AbstractCurvedComponent<Void> implements IContinuity { public class HookupWire extends AbstractCurvedComponent<Void> implements IContinuity {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -48,7 +48,7 @@ import org.diylc.utils.Constants;
@ComponentDescriptor(name = "Twisted Leads", author = "Branislav Stojkovic", category = "Connectivity", @ComponentDescriptor(name = "Twisted Leads", author = "Branislav Stojkovic", category = "Connectivity",
instanceNamePrefix = "W", description = "A pair of flexible leads twisted tighly together", zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "W", description = "A pair of flexible leads twisted tighly together", zOrder = IDIYComponent.COMPONENT,
flexibleZOrder = true, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, flexibleZOrder = true, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
transformer = SimpleComponentTransformer.class) transformer = SimpleComponentTransformer.class, enableCache = true)
public class TwistedWire extends AbstractCurvedComponent<Void> implements IContinuity { public class TwistedWire extends AbstractCurvedComponent<Void> implements IContinuity {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -48,7 +48,7 @@ import org.diylc.utils.Constants;
@ComponentDescriptor(name = "Electrolytic Capacitor (Axial)", author = "Branislav Stojkovic", category = "Passive", @ComponentDescriptor(name = "Electrolytic Capacitor (Axial)", author = "Branislav Stojkovic", category = "Passive",
creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "C", creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "C",
description = "Axial electrolytic capacitor, similar to Sprague Atom, F&T, etc", zOrder = IDIYComponent.COMPONENT, description = "Axial electrolytic capacitor, similar to Sprague Atom, F&T, etc", zOrder = IDIYComponent.COMPONENT,
transformer = SimpleComponentTransformer.class) transformer = SimpleComponentTransformer.class, enableCache = true)
public class AxialElectrolyticCapacitor extends AbstractLeadedComponent<Capacitance> { public class AxialElectrolyticCapacitor extends AbstractLeadedComponent<Capacitance> {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -45,7 +45,7 @@ import org.diylc.core.measures.SizeUnit;
@ComponentDescriptor(name = "Resistor", author = "Branislav Stojkovic", category = "Passive", @ComponentDescriptor(name = "Resistor", author = "Branislav Stojkovic", category = "Passive",
creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "R", description = "Resistor layout symbol", creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "R", description = "Resistor layout symbol",
zOrder = IDIYComponent.COMPONENT, transformer = SimpleComponentTransformer.class) zOrder = IDIYComponent.COMPONENT, transformer = SimpleComponentTransformer.class, enableCache = true)
public class Resistor extends AbstractLeadedComponent<Resistance> { public class Resistor extends AbstractLeadedComponent<Resistance> {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -57,7 +57,8 @@ import org.diylc.utils.Constants;
@ComponentDescriptor(name = "DIP IC", author = "Branislav Stojkovic", category = "Semiconductors", @ComponentDescriptor(name = "DIP IC", author = "Branislav Stojkovic", category = "Semiconductors",
instanceNamePrefix = "IC", description = "Dual-in-line package IC", instanceNamePrefix = "IC", description = "Dual-in-line package IC",
zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, transformer = DIL_ICTransformer.class) zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, transformer = DIL_ICTransformer.class,
enableCache = true)
public class DIL_IC extends AbstractTransparentComponent<String> { public class DIL_IC extends AbstractTransparentComponent<String> {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -541,6 +542,28 @@ public class DIL_IC extends AbstractTransparentComponent<String> {
@Override @Override
public boolean canPointMoveFreely(int pointIndex) { public boolean canPointMoveFreely(int pointIndex) {
return false; return false;
}
@Override
public Rectangle2D getCachingBounds() {
int minX = Integer.MAX_VALUE;
int maxX = Integer.MIN_VALUE;
int minY = Integer.MAX_VALUE;
int maxY = Integer.MIN_VALUE;
int margin = 50;
for (int i = 0; i < getControlPointCount(); i++) {
Point p = getControlPoint(i);
if (p.x < minX)
minX = p.x;
if (p.x > maxX)
maxX = p.x;
if (p.y < minY)
minY = p.y;
if (p.y > maxY)
maxY = p.y;
}
return new Rectangle2D.Double(minX - margin, minY - margin, maxX - minX + 2 * margin, maxY - minY + 2 * margin);
} }
public static enum PinCount { public static enum PinCount {
@@ -56,7 +56,8 @@ import org.diylc.utils.Constants;
@ComponentDescriptor(name = "SIP IC", author = "Branislav Stojkovic", category = "Semiconductors", @ComponentDescriptor(name = "SIP IC", author = "Branislav Stojkovic", category = "Semiconductors",
instanceNamePrefix = "IC", description = "Single-in-line package IC", instanceNamePrefix = "IC", description = "Single-in-line package IC",
zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, transformer = SIL_ICTransformer.class) zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, transformer = SIL_ICTransformer.class,
enableCache = true)
public class SIL_IC extends AbstractTransparentComponent<String> { public class SIL_IC extends AbstractTransparentComponent<String> {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -429,6 +430,28 @@ public class SIL_IC extends AbstractTransparentComponent<String> {
public void setIndentColor(Color indentColor) { public void setIndentColor(Color indentColor) {
this.indentColor = indentColor; this.indentColor = indentColor;
}
@Override
public Rectangle2D getCachingBounds() {
int minX = Integer.MAX_VALUE;
int maxX = Integer.MIN_VALUE;
int minY = Integer.MAX_VALUE;
int maxY = Integer.MIN_VALUE;
int margin = 50;
for (int i = 0; i < getControlPointCount(); i++) {
Point p = getControlPoint(i);
if (p.x < minX)
minX = p.x;
if (p.x > maxX)
maxX = p.x;
if (p.y < minY)
minY = p.y;
if (p.y > maxY)
maxY = p.y;
}
return new Rectangle2D.Double(minX - margin, minY - margin, maxX - minX + 2 * margin, maxY - minY + 2 * margin);
} }
public static enum PinCount { public static enum PinCount {
+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.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.MAIN_TYPE" value="org.diylc.DIYLCStarter"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="diylc-swing"/> <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="diylc-swing"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms256m -Xmx512m -Dorg.diylc.scriptRun=true -Ddorg.diylc.debugContinuityAreas=true -Ddorg.diylc.WriteStaticVariants=true -Ddorg.diylc.debugComponentAreas=true -Dorg.diylc.WriteStaticBlocks=true"/> <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms512m -Xmx2048m -Dorg.diylc.scriptRun=true -Ddorg.diylc.debugContinuityAreas=true -Dorg.diylc.debugComponentAreas=true -Ddorg.diylc.WriteStaticVariants=true -Dorg.diylc.WriteStaticBlocks=true"/>
</launchConfiguration> </launchConfiguration>