mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-10 17:22:09 +10:00
Improve speed of rendering of the grid
This commit is contained in:
@@ -34,6 +34,7 @@ import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
@@ -108,7 +109,7 @@ public class DrawingManager {
|
||||
|
||||
private boolean debugComponentAreas;
|
||||
private boolean debugContinuityAreas;
|
||||
|
||||
|
||||
// rendering stats
|
||||
private Map<String, Counter> renderStatsByType = new HashMap<String, Counter>();
|
||||
private long lastStatsReportedTime = System.currentTimeMillis();
|
||||
@@ -119,28 +120,30 @@ public class DrawingManager {
|
||||
|
||||
private List<Area> proximityMarkers = null;
|
||||
|
||||
public DrawingManager(MessageDispatcher<EventType> messageDispatcher, IConfigurationManager<?> configManager) {
|
||||
public DrawingManager(MessageDispatcher<EventType> messageDispatcher,
|
||||
IConfigurationManager<?> configManager) {
|
||||
super();
|
||||
this.messageDispatcher = messageDispatcher;
|
||||
this.configManager = configManager;
|
||||
|
||||
|
||||
try {
|
||||
this.theme = (Theme) configManager.readObject(IPlugInPort.THEME_KEY,
|
||||
Constants.DEFAULT_THEME);
|
||||
this.theme = (Theme) configManager.readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error loading theme", e);
|
||||
this.theme = Constants.DEFAULT_THEME;
|
||||
// replace bad value with default
|
||||
configManager.writeValue(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME);
|
||||
}
|
||||
|
||||
|
||||
componentAreaMap = new HashMap<IDIYComponent<?>, ComponentArea>();
|
||||
lastDrawnStateMap = new HashMap<IDIYComponent<?>, ComponentState>();
|
||||
String debugComponentAreasStr = System.getProperty(DEBUG_COMPONENT_AREAS);
|
||||
debugComponentAreas = debugComponentAreasStr != null && debugComponentAreasStr.equalsIgnoreCase("true");
|
||||
debugComponentAreas =
|
||||
debugComponentAreasStr != null && debugComponentAreasStr.equalsIgnoreCase("true");
|
||||
|
||||
String debugContinuityAreasStr = System.getProperty(DEBUG_CONTINUITY_AREAS);
|
||||
debugContinuityAreas = debugContinuityAreasStr != null && debugContinuityAreasStr.equalsIgnoreCase("true");
|
||||
debugContinuityAreas =
|
||||
debugContinuityAreasStr != null && debugContinuityAreasStr.equalsIgnoreCase("true");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -161,10 +164,12 @@ public class DrawingManager {
|
||||
* @param visibleRect
|
||||
* @return
|
||||
*/
|
||||
public List<IDIYComponent<?>> drawProject(Graphics2D g2d, Project project, Set<DrawOption> drawOptions,
|
||||
IComponentFilter filter, Rectangle selectionRect, Collection<IDIYComponent<?>> selectedComponents,
|
||||
Set<IDIYComponent<?>> lockedComponents, Set<IDIYComponent<?>> groupedComponents, List<Point2D> controlPointSlot,
|
||||
List<IDIYComponent<?>> componentSlot, boolean dragInProgress, Double externalZoom, Rectangle2D visibleRect) {
|
||||
public List<IDIYComponent<?>> drawProject(Graphics2D g2d, Project project,
|
||||
Set<DrawOption> drawOptions, IComponentFilter filter, Rectangle selectionRect,
|
||||
Collection<IDIYComponent<?>> selectedComponents, Set<IDIYComponent<?>> lockedComponents,
|
||||
Set<IDIYComponent<?>> groupedComponents, List<Point2D> controlPointSlot,
|
||||
List<IDIYComponent<?>> componentSlot, boolean dragInProgress, Double externalZoom,
|
||||
Rectangle2D visibleRect) {
|
||||
long totalStartTime = System.nanoTime();
|
||||
failedComponents.clear();
|
||||
if (project == null) {
|
||||
@@ -185,104 +190,69 @@ public class DrawingManager {
|
||||
|
||||
if (drawOptions.contains(DrawOption.ANTIALIASING)) {
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
|
||||
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||
} else {
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
|
||||
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
|
||||
}
|
||||
if (configManager.readBoolean(IPlugInPort.HI_QUALITY_RENDER_KEY, false)) {
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
|
||||
RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
|
||||
RenderingHints.VALUE_COLOR_RENDER_QUALITY);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
|
||||
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
// g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
|
||||
// RenderingHints.VALUE_STROKE_PURE);
|
||||
} else {
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_SPEED);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
|
||||
RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
|
||||
RenderingHints.VALUE_COLOR_RENDER_SPEED);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
|
||||
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
|
||||
}
|
||||
|
||||
// AffineTransform initialTx = g2d.getTransform();
|
||||
Dimension d = getCanvasDimensions(project, zoom, drawOptions.contains(DrawOption.EXTRA_SPACE));
|
||||
Dimension canvasDimension =
|
||||
getCanvasDimensions(project, zoom, drawOptions.contains(DrawOption.EXTRA_SPACE));
|
||||
|
||||
g2dWrapper.setColor(theme.getBgColor());
|
||||
g2dWrapper.fillRect(0, 0, d.width, d.height);
|
||||
g2d.clip(new Rectangle(new Point(0, 0), d));
|
||||
|
||||
g2dWrapper.fillRect(0, 0, canvasDimension.width, canvasDimension.height);
|
||||
g2d.clip(new Rectangle(new Point(0, 0), canvasDimension));
|
||||
|
||||
Rectangle2D extraSpaceRect = new Rectangle2D.Double();
|
||||
AffineTransform extraSpaceTx = new AffineTransform();
|
||||
|
||||
// calculate size to be rendered
|
||||
double extraSpace = getExtraSpace(project) * zoom;
|
||||
Dimension dInner = getCanvasDimensions(project, zoom, false);
|
||||
|
||||
GridType gridType = GridType.LINES;
|
||||
if (drawOptions.contains(DrawOption.GRID) && gridType != GridType.NONE) {
|
||||
double zoomStep = project.getGridSpacing().convertToPixels() * zoom;
|
||||
float gridThickness = (float) (1f * (zoom > 1 ? 1 : zoom));
|
||||
if (gridType == GridType.CROSSHAIR) {
|
||||
g2d.setStroke(new BasicStroke(gridThickness, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f, new float[] {
|
||||
(float) zoomStep / 2, (float) zoomStep / 2}, (float) zoomStep / 4));
|
||||
} else if (gridType == GridType.DOT) {
|
||||
g2d.setStroke(new BasicStroke(gridThickness, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f, new float[] {
|
||||
1f, (float) zoomStep - 1}, 0f));
|
||||
} else {
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchZoomableStroke(gridThickness));
|
||||
}
|
||||
|
||||
g2dWrapper.setColor(theme.getGridColor());
|
||||
for (double i = zoomStep; i < d.width; i += zoomStep) {
|
||||
g2dWrapper.draw(new Line2D.Double(i, 0, i, d.height - 1));
|
||||
}
|
||||
for (double j = zoomStep; j < d.height; j += zoomStep) {
|
||||
g2dWrapper.draw(new Line2D.Double(0, j, d.width - 1, j));
|
||||
}
|
||||
// draw dots if needed
|
||||
if (project.getDotSpacing() > 1 && zoomStep > 8) {
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchZoomableStroke(gridThickness * 3));
|
||||
g2d.setColor(theme.getDotColor());
|
||||
for (double i = extraSpace + zoomStep * project.getDotSpacing(); i < extraSpace + dInner.width; i += zoomStep * project.getDotSpacing())
|
||||
for (double j = extraSpace + zoomStep * project.getDotSpacing(); j < extraSpace + dInner.height; j += zoomStep * project.getDotSpacing()) {
|
||||
g2d.fillOval((int)Math.round(i - 1), (int)Math.round(j - 1), 3, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle2D extraSpaceRect = null;
|
||||
AffineTransform extraSpaceTx = null;
|
||||
// manage extra space
|
||||
if (drawOptions.contains(DrawOption.EXTRA_SPACE)) {
|
||||
float borderThickness = (float) (3f * (zoom > 1 ? 1 : zoom));
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchStroke(borderThickness, new float[] {borderThickness * 4, borderThickness * 4, }, 0, BasicStroke.CAP_BUTT));
|
||||
g2dWrapper.setColor(theme.getOutlineColor());
|
||||
extraSpaceRect = new Rectangle2D.Double(extraSpace, extraSpace, dInner.getWidth(), dInner.getHeight());
|
||||
g2d.draw(extraSpaceRect);
|
||||
extraSpaceTx = g2d.getTransform();
|
||||
|
||||
// translate to the new (0, 0)
|
||||
g2d.transform(AffineTransform.getTranslateInstance(extraSpace, extraSpace));
|
||||
if (visibleRect != null)
|
||||
visibleRect.setRect(visibleRect.getX() - extraSpace, visibleRect.getY() - extraSpace,
|
||||
visibleRect.getWidth(), visibleRect.getHeight());
|
||||
}
|
||||
drawGrid(project, g2d, zoom, extraSpace, canvasDimension, visibleRect, drawOptions,
|
||||
extraSpaceRect, extraSpaceTx);
|
||||
|
||||
// apply zoom
|
||||
if (Math.abs(1.0 - zoom) > 1e-4) {
|
||||
g2dWrapper.scale(zoom, zoom);
|
||||
if (visibleRect != null)
|
||||
visibleRect.setRect(visibleRect.getX() / zoom, visibleRect.getY() / zoom,
|
||||
visibleRect.getWidth() / zoom, visibleRect.getHeight() / zoom);
|
||||
visibleRect.setRect(visibleRect.getX() / zoom, visibleRect.getY() / zoom,
|
||||
visibleRect.getWidth() / zoom, visibleRect.getHeight() / zoom);
|
||||
}
|
||||
|
||||
|
||||
// Composite mainComposite = g2d.getComposite();
|
||||
// Composite alphaComposite =
|
||||
// AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f);
|
||||
|
||||
// g2dWrapper.resetTx();
|
||||
|
||||
|
||||
// put components and their states in a map
|
||||
Map<IDIYComponent<?>, ComponentState> componentStateMap = new HashMap<IDIYComponent<?>, ComponentState>();
|
||||
Map<IDIYComponent<?>, ComponentState> componentStateMap =
|
||||
new HashMap<IDIYComponent<?>, ComponentState>();
|
||||
for (IDIYComponent<?> component : project.getComponents()) {
|
||||
ComponentState state = ComponentState.NORMAL;
|
||||
if (drawOptions.contains(DrawOption.SELECTION) && selectedComponents.contains(component)) {
|
||||
@@ -294,9 +264,9 @@ public class DrawingManager {
|
||||
}
|
||||
componentStateMap.put(component, state);
|
||||
}
|
||||
|
||||
|
||||
boolean outlineMode = drawOptions.contains(DrawOption.OUTLINE_MODE);
|
||||
|
||||
|
||||
// give the cache a chance to prepare all the components in multiple threads
|
||||
if (drawOptions.contains(DrawOption.ENABLE_CACHING)) {
|
||||
DrawingCache.Instance.bulkPrepare(componentStateMap, g2dWrapper, outlineMode, project, zoom);
|
||||
@@ -312,7 +282,7 @@ public class DrawingManager {
|
||||
// Do not track the area if component is not invalidated and was
|
||||
// drawn in the same state.
|
||||
boolean trackArea = lastDrawnStateMap.get(component) != state;
|
||||
|
||||
|
||||
synchronized (g2d) {
|
||||
g2dWrapper.startedDrawingComponent();
|
||||
if (!trackArea) {
|
||||
@@ -326,14 +296,16 @@ public class DrawingManager {
|
||||
// Draw the component through the g2dWrapper.
|
||||
long componentStart = System.nanoTime();
|
||||
try {
|
||||
|
||||
if (drawOptions.contains(DrawOption.ENABLE_CACHING)) // go through the DrawingCache
|
||||
DrawingCache.Instance.draw(component, g2dWrapper, state, drawOptions.contains(DrawOption.OUTLINE_MODE), project, zoom, visibleRect);
|
||||
|
||||
if (drawOptions.contains(DrawOption.ENABLE_CACHING)) // go through the DrawingCache
|
||||
DrawingCache.Instance.draw(component, g2dWrapper, state,
|
||||
drawOptions.contains(DrawOption.OUTLINE_MODE), project, zoom, visibleRect);
|
||||
else // go straight to the wrapper
|
||||
component.draw(g2dWrapper, state, outlineMode, project, g2dWrapper);
|
||||
|
||||
|
||||
if (g2dWrapper.isTrackingContinuityArea()) {
|
||||
LOG.info("Component " + component.getName() + " of type " + component.getClass().getName() + " did not stop tracking continuity area.");
|
||||
LOG.info("Component " + component.getName() + " of type "
|
||||
+ component.getClass().getName() + " did not stop tracking continuity area.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error drawing " + component.getName(), e);
|
||||
@@ -349,7 +321,7 @@ public class DrawingManager {
|
||||
Counter stats = null;
|
||||
String key = component.getClass().getCanonicalName().replace("org.diylc.components.", "");
|
||||
if (renderStatsByType.containsKey(key)) {
|
||||
stats = renderStatsByType.get(key);
|
||||
stats = renderStatsByType.get(key);
|
||||
} else {
|
||||
stats = new Counter();
|
||||
renderStatsByType.put(key, stats);
|
||||
@@ -374,13 +346,17 @@ public class DrawingManager {
|
||||
continue;
|
||||
VisibilityPolicy visibilityPolicy = component.getControlPointVisibilityPolicy(i);
|
||||
if ((groupedComponents.contains(component)
|
||||
&& (visibilityPolicy == VisibilityPolicy.ALWAYS || (selectedComponents.contains(component) && visibilityPolicy == VisibilityPolicy.WHEN_SELECTED)) || (!groupedComponents
|
||||
.contains(component) && !selectedComponents.contains(component) && component
|
||||
.getControlPointVisibilityPolicy(i) == VisibilityPolicy.ALWAYS))) {
|
||||
&& (visibilityPolicy == VisibilityPolicy.ALWAYS
|
||||
|| (selectedComponents.contains(component)
|
||||
&& visibilityPolicy == VisibilityPolicy.WHEN_SELECTED))
|
||||
|| (!groupedComponents.contains(component)
|
||||
&& !selectedComponents.contains(component)
|
||||
&& component.getControlPointVisibilityPolicy(i) == VisibilityPolicy.ALWAYS))) {
|
||||
g2dWrapper.setColor(CONTROL_POINT_COLOR);
|
||||
Point2D controlPoint = component.getControlPoint(i);
|
||||
int pointSize = CONTROL_POINT_SIZE - 2;
|
||||
g2dWrapper.fillOval((int)(controlPoint.getX() - pointSize / 2), (int)(controlPoint.getY() - pointSize / 2), pointSize, pointSize);
|
||||
g2dWrapper.fillOval((int) (controlPoint.getX() - pointSize / 2),
|
||||
(int) (controlPoint.getY() - pointSize / 2), pointSize, pointSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -389,17 +365,19 @@ public class DrawingManager {
|
||||
for (IDIYComponent<?> component : selectedComponents) {
|
||||
for (int i = 0; i < component.getControlPointCount(); i++) {
|
||||
if (!groupedComponents.contains(component)
|
||||
&& (component.getControlPointVisibilityPolicy(i) == VisibilityPolicy.WHEN_SELECTED || component
|
||||
.getControlPointVisibilityPolicy(i) == VisibilityPolicy.ALWAYS)) {
|
||||
&& (component.getControlPointVisibilityPolicy(i) == VisibilityPolicy.WHEN_SELECTED
|
||||
|| component.getControlPointVisibilityPolicy(i) == VisibilityPolicy.ALWAYS)) {
|
||||
|
||||
Point2D controlPoint = component.getControlPoint(i);
|
||||
int pointSize = CONTROL_POINT_SIZE;
|
||||
|
||||
g2dWrapper.setColor(SELECTED_CONTROL_POINT_COLOR.darker());
|
||||
g2dWrapper.fillOval((int)(controlPoint.getX() - pointSize / 2), (int)(controlPoint.getY() - pointSize / 2), pointSize, pointSize);
|
||||
g2dWrapper.fillOval((int) (controlPoint.getX() - pointSize / 2),
|
||||
(int) (controlPoint.getY() - pointSize / 2), pointSize, pointSize);
|
||||
g2dWrapper.setColor(SELECTED_CONTROL_POINT_COLOR);
|
||||
g2dWrapper.fillOval((int)(controlPoint.getX() - CONTROL_POINT_SIZE / 2 + 1), (int)(controlPoint.getY() - CONTROL_POINT_SIZE / 2
|
||||
+ 1), CONTROL_POINT_SIZE - 2, CONTROL_POINT_SIZE - 2);
|
||||
g2dWrapper.fillOval((int) (controlPoint.getX() - CONTROL_POINT_SIZE / 2 + 1),
|
||||
(int) (controlPoint.getY() - CONTROL_POINT_SIZE / 2 + 1), CONTROL_POINT_SIZE - 2,
|
||||
CONTROL_POINT_SIZE - 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -412,8 +390,8 @@ public class DrawingManager {
|
||||
for (IDIYComponent<?> component : componentSlot) {
|
||||
try {
|
||||
|
||||
component.draw(g2dWrapper, ComponentState.NORMAL, drawOptions.contains(DrawOption.OUTLINE_MODE), project,
|
||||
g2dWrapper);
|
||||
component.draw(g2dWrapper, ComponentState.NORMAL,
|
||||
drawOptions.contains(DrawOption.OUTLINE_MODE), project, g2dWrapper);
|
||||
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error drawing " + component.getName(), e);
|
||||
@@ -428,11 +406,13 @@ public class DrawingManager {
|
||||
for (Point2D point : controlPointSlot) {
|
||||
if (point != null) {
|
||||
g2dWrapper.setColor(SELECTED_CONTROL_POINT_COLOR.darker());
|
||||
g2dWrapper.fillOval((int)(point.getX() - CONTROL_POINT_SIZE / 2), (int)(point.getY() - CONTROL_POINT_SIZE / 2), CONTROL_POINT_SIZE,
|
||||
g2dWrapper.fillOval((int) (point.getX() - CONTROL_POINT_SIZE / 2),
|
||||
(int) (point.getY() - CONTROL_POINT_SIZE / 2), CONTROL_POINT_SIZE,
|
||||
CONTROL_POINT_SIZE);
|
||||
g2dWrapper.setColor(SELECTED_CONTROL_POINT_COLOR);
|
||||
g2dWrapper.fillOval((int)(point.getX() - CONTROL_POINT_SIZE / 2 + 1), (int)(point.getY() - CONTROL_POINT_SIZE / 2 + 1),
|
||||
CONTROL_POINT_SIZE - 2, CONTROL_POINT_SIZE - 2);
|
||||
g2dWrapper.fillOval((int) (point.getX() - CONTROL_POINT_SIZE / 2 + 1),
|
||||
(int) (point.getY() - CONTROL_POINT_SIZE / 2 + 1), CONTROL_POINT_SIZE - 2,
|
||||
CONTROL_POINT_SIZE - 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -477,9 +457,8 @@ public class DrawingManager {
|
||||
g2d.draw(a);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.proximityMarkers != null)
|
||||
{
|
||||
|
||||
if (this.proximityMarkers != null) {
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2));
|
||||
g2d.setColor(Color.red);
|
||||
for (Shape s : this.proximityMarkers)
|
||||
@@ -493,33 +472,125 @@ public class DrawingManager {
|
||||
g2d.fill(currentContinuityArea);
|
||||
g2d.setComposite(oldComposite);
|
||||
}
|
||||
|
||||
|
||||
// shade extra space
|
||||
if (SHADE_EXTRA_SPACE && extraSpaceRect != null) {
|
||||
Area extraSpaceArea = new Area(new Rectangle2D.Double(0, 0, d.getWidth(), d.getHeight()));
|
||||
Area extraSpaceArea = new Area(
|
||||
new Rectangle2D.Double(0, 0, canvasDimension.getWidth(), canvasDimension.getHeight()));
|
||||
extraSpaceArea.subtract(new Area(extraSpaceRect));
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.05f));
|
||||
g2d.setTransform(extraSpaceTx);
|
||||
g2d.setColor(theme.getOutlineColor());
|
||||
g2d.fill(extraSpaceArea);
|
||||
}
|
||||
|
||||
|
||||
long totalEndTime = System.nanoTime();
|
||||
|
||||
|
||||
totalStats.add(totalEndTime - totalStartTime);
|
||||
|
||||
|
||||
logStats();
|
||||
|
||||
return failedComponents;
|
||||
}
|
||||
|
||||
|
||||
private double zoomCached = 0;
|
||||
private Dimension canvasDimensionCached;
|
||||
private double extraSpaceCached;
|
||||
private GridType gridTypeCached;
|
||||
private BufferedImage cachedGridImage;
|
||||
|
||||
private void drawGrid(Project project, Graphics2D g2dIn, double zoom, double extraSpace,
|
||||
Dimension canvasDimension, Rectangle2D visibleRect, Set<DrawOption> drawOptions,
|
||||
Rectangle2D extraSpaceRect, AffineTransform extraSpaceTx) {
|
||||
|
||||
GridType gridType = GridType.LINES;
|
||||
|
||||
Dimension innerCanvasDimension = getCanvasDimensions(project, zoom, false);
|
||||
|
||||
// draw from cache
|
||||
if (zoom != zoomCached || !canvasDimension.equals(canvasDimensionCached)
|
||||
|| extraSpace != extraSpaceCached || gridType != gridTypeCached) {
|
||||
try {
|
||||
cachedGridImage = new BufferedImage((int) canvasDimension.getWidth(),
|
||||
(int) canvasDimension.getHeight(), BufferedImage.TYPE_INT_ARGB);
|
||||
// create graphics
|
||||
Graphics2D g2d = cachedGridImage.createGraphics();
|
||||
|
||||
if (drawOptions.contains(DrawOption.GRID) && gridType != GridType.NONE) {
|
||||
double zoomStep = project.getGridSpacing().convertToPixels() * zoom;
|
||||
float gridThickness = (float) (1f * (zoom > 1 ? 1 : zoom));
|
||||
if (gridType == GridType.CROSSHAIR) {
|
||||
g2d.setStroke(new BasicStroke(gridThickness, BasicStroke.CAP_BUTT,
|
||||
BasicStroke.JOIN_MITER, 10f,
|
||||
new float[] {(float) zoomStep / 2, (float) zoomStep / 2}, (float) zoomStep / 4));
|
||||
} else if (gridType == GridType.DOT) {
|
||||
g2d.setStroke(new BasicStroke(gridThickness, BasicStroke.CAP_BUTT,
|
||||
BasicStroke.JOIN_MITER, 10f, new float[] {1f, (float) zoomStep - 1}, 0f));
|
||||
} else {
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchZoomableStroke(gridThickness));
|
||||
}
|
||||
|
||||
g2d.setColor(theme.getGridColor());
|
||||
for (double i = zoomStep; i < canvasDimension.width; i += zoomStep) {
|
||||
g2d.draw(new Line2D.Double(i, 0, i, canvasDimension.height - 1));
|
||||
}
|
||||
for (double j = zoomStep; j < canvasDimension.height; j += zoomStep) {
|
||||
g2d.draw(new Line2D.Double(0, j, canvasDimension.width - 1, j));
|
||||
}
|
||||
// draw dots if needed
|
||||
if (project.getDotSpacing() > 1 && zoomStep > 8) {
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchZoomableStroke(gridThickness * 3));
|
||||
g2d.setColor(theme.getDotColor());
|
||||
for (double i = extraSpace + zoomStep * project.getDotSpacing(); i < extraSpace
|
||||
+ innerCanvasDimension.width; i += zoomStep * project.getDotSpacing())
|
||||
for (double j = extraSpace + zoomStep * project.getDotSpacing(); j < extraSpace
|
||||
+ innerCanvasDimension.height; j += zoomStep * project.getDotSpacing()) {
|
||||
g2d.fillOval((int) Math.round(i - 1), (int) Math.round(j - 1), 3, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
zoomCached = zoom;
|
||||
canvasDimensionCached = (Dimension) canvasDimension.clone();
|
||||
extraSpaceCached = extraSpace;
|
||||
gridTypeCached = gridType;
|
||||
}
|
||||
}
|
||||
|
||||
if (cachedGridImage == null) {
|
||||
LOG.warn("Cached grid image is null!");
|
||||
return;
|
||||
}
|
||||
|
||||
g2dIn.drawImage(cachedGridImage, 0, 0, null);
|
||||
|
||||
// manage extra space
|
||||
if (drawOptions.contains(DrawOption.EXTRA_SPACE)) {
|
||||
float borderThickness = (float) (3f * (zoom > 1 ? 1 : zoom));
|
||||
g2dIn.setStroke(ObjectCache.getInstance().fetchStroke(borderThickness,
|
||||
new float[] {borderThickness * 4, borderThickness * 4,}, 0, BasicStroke.CAP_BUTT));
|
||||
g2dIn.setColor(theme.getOutlineColor());
|
||||
extraSpaceRect.setRect(new Rectangle2D.Double(extraSpace, extraSpace,
|
||||
innerCanvasDimension.getWidth(), innerCanvasDimension.getHeight()));
|
||||
g2dIn.draw(extraSpaceRect);
|
||||
extraSpaceTx.setTransform(g2dIn.getTransform());
|
||||
|
||||
// translate to the new (0, 0)
|
||||
g2dIn.transform(AffineTransform.getTranslateInstance(extraSpace, extraSpace));
|
||||
if (visibleRect != null)
|
||||
visibleRect.setRect(visibleRect.getX() - extraSpace, visibleRect.getY() - extraSpace,
|
||||
visibleRect.getWidth(), visibleRect.getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
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("; ", "{", "}"));
|
||||
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);
|
||||
LOG.debug("Page stats: " + totalStats.toAvgString());
|
||||
DrawingCache.Instance.logStats();
|
||||
@@ -572,11 +643,13 @@ public class DrawingManager {
|
||||
public double getExtraSpace(Project project) {
|
||||
double width = project.getWidth().convertToPixels();
|
||||
double height = project.getHeight().convertToPixels();
|
||||
double targetExtraSpace = EXTRA_SPACE * Math.max(width, height);
|
||||
return CalcUtils.roundToGrid(targetExtraSpace, project.getGridSpacing().scale(project.getDotSpacing()));
|
||||
double targetExtraSpace = EXTRA_SPACE * Math.max(width, height);
|
||||
return CalcUtils.roundToGrid(targetExtraSpace,
|
||||
project.getGridSpacing().scale(project.getDotSpacing()));
|
||||
}
|
||||
|
||||
public Dimension getCanvasDimensions(Project project, Double zoomLevel, boolean includeExtraSpace) {
|
||||
public Dimension getCanvasDimensions(Project project, Double zoomLevel,
|
||||
boolean includeExtraSpace) {
|
||||
double width = project.getWidth().convertToPixels();
|
||||
double height = project.getHeight().convertToPixels();
|
||||
|
||||
@@ -588,7 +661,7 @@ public class DrawingManager {
|
||||
|
||||
width *= zoomLevel;
|
||||
height *= zoomLevel;
|
||||
|
||||
|
||||
return new Dimension((int) width, (int) height);
|
||||
}
|
||||
|
||||
@@ -606,7 +679,7 @@ public class DrawingManager {
|
||||
configManager.writeValue(IPlugInPort.THEME_KEY, theme);
|
||||
messageDispatcher.dispatchMessage(EventType.REPAINT);
|
||||
}
|
||||
|
||||
|
||||
public void findContinuityAreaAtPoint(Project project, Point2D p) {
|
||||
if (continuityAreaCache == null)
|
||||
continuityAreaCache = getContinuityAreas(project);
|
||||
@@ -620,7 +693,7 @@ public class DrawingManager {
|
||||
|
||||
currentContinuityArea = null;
|
||||
}
|
||||
|
||||
|
||||
public List<Area> getContinuityAreas(Project project) {
|
||||
// Find all individual continuity areas for all components
|
||||
List<Area> preliminaryAreas = new ArrayList<Area>();
|
||||
@@ -628,11 +701,11 @@ public class DrawingManager {
|
||||
Set<Connection> connections = new HashSet<Connection>();
|
||||
for (IDIYComponent<?> c : project.getComponents()) {
|
||||
ComponentArea a = getComponentArea(c);
|
||||
|
||||
|
||||
if (c instanceof IContinuity) {
|
||||
for (int i = 0; i < c.getControlPointCount() - 1; i++)
|
||||
for (int j = i + 1; j < c.getControlPointCount(); j++)
|
||||
if (((IContinuity)c).arePointsConnected(i, j))
|
||||
if (((IContinuity) c).arePointsConnected(i, j))
|
||||
connections.add(new Connection(c.getControlPoint(i), c.getControlPoint(j)));
|
||||
}
|
||||
|
||||
@@ -654,30 +727,32 @@ 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(AreaUtils.tryAreaBreakout(a));
|
||||
else
|
||||
areas.add(a);
|
||||
if (checkBreakout.get(i))
|
||||
areas.addAll(AreaUtils.tryAreaBreakout(a));
|
||||
else
|
||||
areas.add(a);
|
||||
}
|
||||
|
||||
|
||||
CalcUtils.expandConnections(connections);
|
||||
|
||||
AreaUtils.crunchAreas(areas, connections);
|
||||
|
||||
|
||||
return areas;
|
||||
}
|
||||
|
||||
|
||||
public List<Area> getContinuityAreaProximity(Project project, float threshold) {
|
||||
List<Area> continuityAreas = getContinuityAreas(project);
|
||||
Stroke s = ObjectCache.getInstance().fetchBasicStroke(threshold - 1); // value eyeballed for approx good results
|
||||
List<Area> expanded = continuityAreas.parallelStream().map((a) -> new Area(s.createStrokedShape(a))).collect(Collectors.toList());
|
||||
List<Area> continuityAreas = getContinuityAreas(project);
|
||||
Stroke s = ObjectCache.getInstance().fetchBasicStroke(threshold - 1); // value eyeballed for
|
||||
// approx good results
|
||||
List<Area> expanded = continuityAreas.parallelStream()
|
||||
.map((a) -> new Area(s.createStrokedShape(a))).collect(Collectors.toList());
|
||||
List<Area> intersections = new ArrayList<Area>();
|
||||
for (int i = 0; i < expanded.size() - 1; i++) {
|
||||
for (int j = i + 1; j < expanded.size(); j++) {
|
||||
@@ -688,25 +763,28 @@ public class DrawingManager {
|
||||
intersections.add(first);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AreaUtils.crunchAreas(intersections, null);
|
||||
double minSize = new Size(1d, SizeUnit.cm).convertToPixels();
|
||||
|
||||
|
||||
List<Area> shapes = new ArrayList<Area>();
|
||||
for (Area a : intersections) {
|
||||
Rectangle2D bounds2d = a.getBounds2D();
|
||||
if (bounds2d.getWidth() < minSize)
|
||||
bounds2d = new Rectangle2D.Double(bounds2d.getCenterX() - minSize / 2, bounds2d.getY(), minSize, bounds2d.getHeight());
|
||||
bounds2d = new Rectangle2D.Double(bounds2d.getCenterX() - minSize / 2, bounds2d.getY(),
|
||||
minSize, bounds2d.getHeight());
|
||||
if (bounds2d.getHeight() < minSize)
|
||||
bounds2d = new Rectangle2D.Double(bounds2d.getX(), bounds2d.getCenterY() - minSize / 2, bounds2d.getWidth(), minSize);
|
||||
|
||||
shapes.add(new Area(new Ellipse2D.Double(bounds2d.getX(), bounds2d.getY(), bounds2d.getWidth(), bounds2d.getHeight())));
|
||||
bounds2d = new Rectangle2D.Double(bounds2d.getX(), bounds2d.getCenterY() - minSize / 2,
|
||||
bounds2d.getWidth(), minSize);
|
||||
|
||||
shapes.add(new Area(new Ellipse2D.Double(bounds2d.getX(), bounds2d.getY(),
|
||||
bounds2d.getWidth(), bounds2d.getHeight())));
|
||||
}
|
||||
|
||||
//AreaUtils.crunchAreas(shapes, null);
|
||||
|
||||
this.proximityMarkers = shapes;
|
||||
|
||||
|
||||
// AreaUtils.crunchAreas(shapes, null);
|
||||
|
||||
this.proximityMarkers = shapes;
|
||||
|
||||
return shapes;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3801,5 +3801,21 @@
|
||||
</changes>
|
||||
<url>https://github.com/bancika/diy-layout-creator/releases</url>
|
||||
</org.diylc.appframework.update.Version>
|
||||
<org.diylc.appframework.update.Version>
|
||||
<versionNumber>
|
||||
<major>4</major>
|
||||
<minor>22</minor>
|
||||
<build>3</build>
|
||||
</versionNumber>
|
||||
<releaseDate>2022-03-18 00:00:00.000 CET</releaseDate>
|
||||
<name></name>
|
||||
<changes>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>BUG_FIX</changeType>
|
||||
<description>Improved rendering performance</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
</changes>
|
||||
<url>https://github.com/bancika/diy-layout-creator/releases</url>
|
||||
</org.diylc.appframework.update.Version>
|
||||
</a>
|
||||
</java.util.Arrays_-ArrayList>
|
||||
|
||||
Reference in New Issue
Block a user