mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-07 12:24:58 +10:00
Improved the accuracy of board underside rendering; some of the components were not rendered in the right place or at all
This commit is contained in:
@@ -50,7 +50,6 @@ import org.diylc.appframework.miscutils.IConfigurationManager;
|
||||
import org.diylc.appframework.simplemq.MessageDispatcher;
|
||||
|
||||
import org.diylc.common.*;
|
||||
import org.diylc.components.AbstractTransparentComponent;
|
||||
import org.diylc.core.*;
|
||||
import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
@@ -192,19 +191,27 @@ public class DrawingManager {
|
||||
Map<IBoard, List<IDIYComponent<?>>> boardMap = project.getComponents().stream()
|
||||
.filter(IBoard.class::isInstance)
|
||||
.map(IBoard.class::cast)
|
||||
.filter(b -> b.getUndersideDisplay() != BoardUndersideDisplay.NONE)
|
||||
.filter(b -> b.getUndersideDisplay() != null && b.getUndersideDisplay() != BoardUndersideDisplay.NONE)
|
||||
.collect(Collectors.toMap(x -> x, x -> new ArrayList<IDIYComponent<?>>()));
|
||||
Map<IDIYComponent<?>, Set<IBoard>> componentBoardMap = new HashMap<IDIYComponent<?>, Set<IBoard>>();
|
||||
|
||||
for (IBoard board : boardMap.keySet()) {
|
||||
Rectangle2D boardRect = board.getBoardRectangle();
|
||||
if (boardRect == null) {
|
||||
continue;
|
||||
}
|
||||
double minX = Math.min(boardRect.getMinX(), boardRect.getMaxX());
|
||||
double maxX = Math.max(boardRect.getMinX(), boardRect.getMaxX());
|
||||
double minY = Math.min(boardRect.getMinY(), boardRect.getMaxY());
|
||||
double maxY = Math.max(boardRect.getMinY(), boardRect.getMaxY());
|
||||
Rectangle2D normalizedBoardRect = new Rectangle2D.Double(minX, minY, maxX - minX, maxY - minY);
|
||||
for (IDIYComponent<?> c : project.getComponents()) {
|
||||
if (c == board) {
|
||||
continue;
|
||||
}
|
||||
boolean include = false;
|
||||
for (int i = 0; i < c.getControlPointCount(); i++) {
|
||||
if (boardRect.contains(c.getControlPoint(i))) {
|
||||
if (normalizedBoardRect.contains(c.getControlPoint(i))) {
|
||||
include = true;
|
||||
break;
|
||||
}
|
||||
@@ -337,26 +344,17 @@ public class DrawingManager {
|
||||
try {
|
||||
// Mirror components that belong to boards that need to be mirrored
|
||||
if (componentBoardMap.containsKey(component)) {
|
||||
@SuppressWarnings("unchecked")
|
||||
ComponentType componentType = ComponentProcessor.getInstance()
|
||||
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) component.getClass());
|
||||
if (componentType.getTransformer() != null) {
|
||||
Set<IBoard> boards = componentBoardMap.get(component);
|
||||
for (IBoard board : boards) {
|
||||
drawMirroredComponent(project, board, component, componentType, g2dWrapper, state,
|
||||
outlineMode);
|
||||
}
|
||||
Set<IBoard> boards = componentBoardMap.get(component);
|
||||
for (IBoard board : boards) {
|
||||
drawMirroredComponent(project, board, component, g2dWrapper, state, outlineMode);
|
||||
}
|
||||
}
|
||||
|
||||
// if a component itself is a board that needs to be mirrored, do it
|
||||
if (IBoard.class.isInstance(component) && componentBoardMap.values().stream()
|
||||
.anyMatch(boards -> boards.contains(component))) {
|
||||
ComponentType componentType = ComponentProcessor.getInstance()
|
||||
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) component.getClass());
|
||||
if (componentType.getTransformer() != null) {
|
||||
drawMirroredComponent(project, (IBoard) component, component, componentType,
|
||||
g2dWrapper, state, outlineMode);
|
||||
if (component instanceof IBoard) {
|
||||
IBoard board = (IBoard) component;
|
||||
if (board.getUndersideDisplay() != null && board.getUndersideDisplay() != BoardUndersideDisplay.NONE) {
|
||||
drawMirroredComponent(project, board, component, g2dWrapper, state, outlineMode);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
@@ -526,39 +524,85 @@ public class DrawingManager {
|
||||
}
|
||||
|
||||
private static void drawMirroredComponent(Project project, IBoard board, IDIYComponent<?> component,
|
||||
ComponentType componentType, G2DWrapper g2dWrapper, ComponentState state, boolean outlineMode) {
|
||||
double offset = board.getUndersideOffset().convertToPixels();
|
||||
G2DWrapper g2dWrapper, ComponentState state, boolean outlineMode) {
|
||||
if (board.getUndersideDisplay() == null || board.getUndersideDisplay() == BoardUndersideDisplay.NONE) {
|
||||
return;
|
||||
}
|
||||
double offset = board.getUndersideOffset() == null ? 0 : board.getUndersideOffset().convertToPixels();
|
||||
Rectangle2D boardRectangle = board.getBoardRectangle();
|
||||
try {
|
||||
IDIYComponent<?> clonedComponent = component.clone();
|
||||
int direction = 0;
|
||||
Point2D pivotPoint = new Point2D.Double();
|
||||
switch (board.getUndersideDisplay()) {
|
||||
case ABOVE:
|
||||
direction = IComponentTransformer.VERTICAL;
|
||||
pivotPoint.setLocation(boardRectangle.getMinX(), boardRectangle.getMinY() - offset / 2);
|
||||
break;
|
||||
case BELOW:
|
||||
direction = IComponentTransformer.VERTICAL;
|
||||
pivotPoint.setLocation(boardRectangle.getMinX(), boardRectangle.getMaxY() + offset / 2);
|
||||
break;
|
||||
case LEFT:
|
||||
direction = IComponentTransformer.HORIZONTAL;
|
||||
pivotPoint.setLocation(boardRectangle.getMinX() - offset / 2, boardRectangle.getMinY());
|
||||
break;
|
||||
case RIGHT:
|
||||
direction = IComponentTransformer.HORIZONTAL;
|
||||
pivotPoint.setLocation(boardRectangle.getMaxX() + offset / 2, boardRectangle.getMinY());
|
||||
break;
|
||||
}
|
||||
componentType.getTransformer().mirror(clonedComponent, pivotPoint, direction);
|
||||
if (board.getUndersideTransparency() && AbstractTransparentComponent.class.isInstance(clonedComponent)) {
|
||||
AbstractTransparentComponent<?> transparentComponent = (AbstractTransparentComponent<?>) clonedComponent;
|
||||
transparentComponent.setAlpha(MIRROR_ALPHA);
|
||||
if (boardRectangle == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
double minX = Math.min(boardRectangle.getMinX(), boardRectangle.getMaxX());
|
||||
double maxX = Math.max(boardRectangle.getMinX(), boardRectangle.getMaxX());
|
||||
double minY = Math.min(boardRectangle.getMinY(), boardRectangle.getMaxY());
|
||||
double maxY = Math.max(boardRectangle.getMinY(), boardRectangle.getMaxY());
|
||||
|
||||
AffineTransform mirrorTx = new AffineTransform();
|
||||
switch (board.getUndersideDisplay()) {
|
||||
case ABOVE: {
|
||||
double pivotY = minY - offset / 2;
|
||||
mirrorTx.translate(0, pivotY);
|
||||
mirrorTx.scale(1.0, -1.0);
|
||||
mirrorTx.translate(0, -pivotY);
|
||||
break;
|
||||
}
|
||||
clonedComponent.draw(g2dWrapper, state, outlineMode, project, g2dWrapper);
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new RuntimeException(e);
|
||||
case BELOW: {
|
||||
double pivotY = maxY + offset / 2;
|
||||
mirrorTx.translate(0, pivotY);
|
||||
mirrorTx.scale(1.0, -1.0);
|
||||
mirrorTx.translate(0, -pivotY);
|
||||
break;
|
||||
}
|
||||
case LEFT: {
|
||||
double pivotX = minX - offset / 2;
|
||||
mirrorTx.translate(pivotX, 0);
|
||||
mirrorTx.scale(-1.0, 1.0);
|
||||
mirrorTx.translate(-pivotX, 0);
|
||||
break;
|
||||
}
|
||||
case RIGHT: {
|
||||
double pivotX = maxX + offset / 2;
|
||||
mirrorTx.translate(pivotX, 0);
|
||||
mirrorTx.scale(-1.0, 1.0);
|
||||
mirrorTx.translate(-pivotX, 0);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
G2DWrapper.MirrorDirection mirrorDirection;
|
||||
switch (board.getUndersideDisplay()) {
|
||||
case ABOVE:
|
||||
case BELOW:
|
||||
mirrorDirection = G2DWrapper.MirrorDirection.VERTICAL;
|
||||
break;
|
||||
case LEFT:
|
||||
case RIGHT:
|
||||
mirrorDirection = G2DWrapper.MirrorDirection.HORIZONTAL;
|
||||
break;
|
||||
default:
|
||||
mirrorDirection = G2DWrapper.MirrorDirection.NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
AffineTransform oldTx = g2dWrapper.getTransform();
|
||||
Composite oldComposite = g2dWrapper.getComposite();
|
||||
g2dWrapper.setMirrorDirection(mirrorDirection);
|
||||
try {
|
||||
g2dWrapper.transform(mirrorTx);
|
||||
if (Boolean.TRUE.equals(board.getUndersideTransparency())) {
|
||||
g2dWrapper.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, MIRROR_ALPHA.getValue() / 100f));
|
||||
}
|
||||
component.draw(g2dWrapper, state, outlineMode, project, g2dWrapper);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error drawing mirrored " + component.getName(), e);
|
||||
} finally {
|
||||
g2dWrapper.setMirrorDirection(G2DWrapper.MirrorDirection.NONE);
|
||||
g2dWrapper.setTransform(oldTx);
|
||||
g2dWrapper.setComposite(oldComposite);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ import java.awt.Shape;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.GlyphVector;
|
||||
import java.awt.font.TextLayout;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Arc2D;
|
||||
import java.awt.geom.Area;
|
||||
@@ -106,6 +107,12 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
|
||||
private String continuityMarker;
|
||||
private Shape lastShape;
|
||||
|
||||
public enum MirrorDirection {
|
||||
NONE, HORIZONTAL, VERTICAL
|
||||
}
|
||||
|
||||
private MirrorDirection mirrorDirection = MirrorDirection.NONE;
|
||||
|
||||
private double zoom;
|
||||
private int zOrder;
|
||||
|
||||
@@ -133,6 +140,14 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
|
||||
return canvasGraphics;
|
||||
}
|
||||
|
||||
public void setMirrorDirection(MirrorDirection mirrorDirection) {
|
||||
this.mirrorDirection = mirrorDirection != null ? mirrorDirection : MirrorDirection.NONE;
|
||||
}
|
||||
|
||||
public MirrorDirection getMirrorDirection() {
|
||||
return mirrorDirection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears out the current area and caches canvas settings.
|
||||
*
|
||||
@@ -332,7 +347,35 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
|
||||
|
||||
@Override
|
||||
public void drawGlyphVector(GlyphVector g, float x, float y) {
|
||||
canvasGraphics.drawGlyphVector(g, x, y);
|
||||
if (g == null) {
|
||||
return;
|
||||
}
|
||||
if (mirrorDirection != MirrorDirection.NONE) {
|
||||
Rectangle2D bounds = g.getVisualBounds();
|
||||
double width = bounds.getWidth();
|
||||
double height = bounds.getHeight();
|
||||
AffineTransform oldTx = canvasGraphics.getTransform();
|
||||
AffineTransform flipTx = new AffineTransform();
|
||||
if (mirrorDirection == MirrorDirection.HORIZONTAL) {
|
||||
double cx = x + bounds.getX() + width / 2.0;
|
||||
flipTx.translate(cx, 0);
|
||||
flipTx.scale(-1.0, 1.0);
|
||||
flipTx.translate(-cx, 0);
|
||||
} else if (mirrorDirection == MirrorDirection.VERTICAL) {
|
||||
double cy = y + bounds.getY() + height / 2.0;
|
||||
flipTx.translate(0, cy);
|
||||
flipTx.scale(1.0, -1.0);
|
||||
flipTx.translate(0, -cy);
|
||||
}
|
||||
canvasGraphics.transform(flipTx);
|
||||
try {
|
||||
canvasGraphics.drawGlyphVector(g, x, y);
|
||||
} finally {
|
||||
canvasGraphics.setTransform(oldTx);
|
||||
}
|
||||
} else {
|
||||
canvasGraphics.drawGlyphVector(g, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -361,7 +404,14 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
|
||||
|
||||
@Override
|
||||
public void drawString(String str, int x, int y) {
|
||||
canvasGraphics.drawString(str, x, y);
|
||||
if (str == null) {
|
||||
return;
|
||||
}
|
||||
if (mirrorDirection != MirrorDirection.NONE) {
|
||||
drawMirroredString(str, x, y);
|
||||
} else {
|
||||
canvasGraphics.drawString(str, x, y);
|
||||
}
|
||||
if (drawingComponent && trackingAllowed) {
|
||||
FontMetrics fontMetrics = canvasGraphics.getFontMetrics();
|
||||
Rectangle2D rect = fontMetrics.getStringBounds(str, canvasGraphics);
|
||||
@@ -376,7 +426,14 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
|
||||
|
||||
@Override
|
||||
public void drawString(String str, float x, float y) {
|
||||
canvasGraphics.drawString(str, x, y);
|
||||
if (str == null) {
|
||||
return;
|
||||
}
|
||||
if (mirrorDirection != MirrorDirection.NONE) {
|
||||
drawMirroredString(str, x, y);
|
||||
} else {
|
||||
canvasGraphics.drawString(str, x, y);
|
||||
}
|
||||
if (drawingComponent && trackingAllowed) {
|
||||
FontMetrics fontMetrics = canvasGraphics.getFontMetrics();
|
||||
Rectangle2D rect = fontMetrics.getStringBounds(str, canvasGraphics);
|
||||
@@ -386,14 +443,87 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
|
||||
|
||||
@Override
|
||||
public void drawString(AttributedCharacterIterator iterator, int x, int y) {
|
||||
canvasGraphics.drawString(iterator, x, y);
|
||||
// FIXME: process map
|
||||
if (iterator == null) {
|
||||
return;
|
||||
}
|
||||
if (mirrorDirection != MirrorDirection.NONE) {
|
||||
drawMirroredString(iterator, x, y);
|
||||
} else {
|
||||
canvasGraphics.drawString(iterator, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawString(AttributedCharacterIterator iterator, float x, float y) {
|
||||
canvasGraphics.drawString(iterator, x, y);
|
||||
// FIXME: process map
|
||||
if (iterator == null) {
|
||||
return;
|
||||
}
|
||||
if (mirrorDirection != MirrorDirection.NONE) {
|
||||
drawMirroredString(iterator, x, y);
|
||||
} else {
|
||||
canvasGraphics.drawString(iterator, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawMirroredString(String str, float x, float y) {
|
||||
FontMetrics fontMetrics = canvasGraphics.getFontMetrics();
|
||||
Rectangle2D rect = fontMetrics.getStringBounds(str, canvasGraphics);
|
||||
double width = rect.getWidth();
|
||||
double ascent = fontMetrics.getAscent();
|
||||
double descent = fontMetrics.getDescent();
|
||||
|
||||
AffineTransform oldTx = canvasGraphics.getTransform();
|
||||
AffineTransform flipTx = new AffineTransform();
|
||||
|
||||
if (mirrorDirection == MirrorDirection.HORIZONTAL) {
|
||||
double cx = x + width / 2.0;
|
||||
flipTx.translate(cx, 0);
|
||||
flipTx.scale(-1.0, 1.0);
|
||||
flipTx.translate(-cx, 0);
|
||||
} else if (mirrorDirection == MirrorDirection.VERTICAL) {
|
||||
double cy = y - (ascent - descent) / 2.0;
|
||||
flipTx.translate(0, cy);
|
||||
flipTx.scale(1.0, -1.0);
|
||||
flipTx.translate(0, -cy);
|
||||
}
|
||||
|
||||
canvasGraphics.transform(flipTx);
|
||||
try {
|
||||
canvasGraphics.drawString(str, x, y);
|
||||
} finally {
|
||||
canvasGraphics.setTransform(oldTx);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawMirroredString(AttributedCharacterIterator iterator, float x, float y) {
|
||||
FontRenderContext frc = canvasGraphics.getFontRenderContext();
|
||||
TextLayout layout = new TextLayout(iterator, frc);
|
||||
Rectangle2D bounds = layout.getBounds();
|
||||
double width = bounds.getWidth();
|
||||
double ascent = layout.getAscent();
|
||||
double descent = layout.getDescent();
|
||||
|
||||
AffineTransform oldTx = canvasGraphics.getTransform();
|
||||
AffineTransform flipTx = new AffineTransform();
|
||||
|
||||
if (mirrorDirection == MirrorDirection.HORIZONTAL) {
|
||||
double cx = x + width / 2.0;
|
||||
flipTx.translate(cx, 0);
|
||||
flipTx.scale(-1.0, 1.0);
|
||||
flipTx.translate(-cx, 0);
|
||||
} else if (mirrorDirection == MirrorDirection.VERTICAL) {
|
||||
double cy = y - (ascent - descent) / 2.0;
|
||||
flipTx.translate(0, cy);
|
||||
flipTx.scale(1.0, -1.0);
|
||||
flipTx.translate(0, -cy);
|
||||
}
|
||||
|
||||
canvasGraphics.transform(flipTx);
|
||||
try {
|
||||
canvasGraphics.drawString(iterator, x, y);
|
||||
} finally {
|
||||
canvasGraphics.setTransform(oldTx);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -401,6 +401,10 @@
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Significantly improved AI Assistant's knowledge base on DIYLC usage by ingesting most of the material from the eBook</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Improved the accuracy of board underside rendering; some of the components were not rendered in the right place or at all</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Show a progress dialog while waiting for a long-running AI Analysis to complete</description>
|
||||
|
||||
@@ -0,0 +1,532 @@
|
||||
package org.diylc.presenter;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
import org.diylc.appframework.miscutils.InMemoryConfigurationManager;
|
||||
import org.diylc.appframework.simplemq.MessageDispatcher;
|
||||
import org.diylc.common.DrawOption;
|
||||
import org.diylc.common.EventType;
|
||||
import org.diylc.core.BoardUndersideDisplay;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IBoard;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
import org.diylc.testcomponents.MockDIYComponent;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DrawingManagerTest {
|
||||
|
||||
@ComponentDescriptor(name = "MockBoard", author = "test", category = "Boards", instanceNamePrefix = "B",
|
||||
description = "Mock board for testing", zOrder = IDIYComponent.BOARD)
|
||||
public static class MockBoard extends MockDIYComponent implements IBoard {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Rectangle2D boardRectangle = new Rectangle2D.Double(100, 100, 200, 300);
|
||||
private BoardUndersideDisplay undersideDisplay = BoardUndersideDisplay.BELOW;
|
||||
private Size undersideOffset = new Size(20.0, SizeUnit.px);
|
||||
private Boolean undersideTransparency = Boolean.TRUE;
|
||||
|
||||
public List<AffineTransform> capturedTransforms = new ArrayList<>();
|
||||
public List<Float> capturedAlphas = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public Rectangle2D getBoardRectangle() {
|
||||
return boardRectangle;
|
||||
}
|
||||
|
||||
public void setBoardRectangle(Rectangle2D boardRectangle) {
|
||||
this.boardRectangle = boardRectangle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoardUndersideDisplay getUndersideDisplay() {
|
||||
return undersideDisplay;
|
||||
}
|
||||
|
||||
public void setUndersideDisplay(BoardUndersideDisplay undersideDisplay) {
|
||||
this.undersideDisplay = undersideDisplay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Size getUndersideOffset() {
|
||||
return undersideOffset;
|
||||
}
|
||||
|
||||
public void setUndersideOffset(Size undersideOffset) {
|
||||
this.undersideOffset = undersideOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getUndersideTransparency() {
|
||||
return undersideTransparency;
|
||||
}
|
||||
|
||||
public void setUndersideTransparency(Boolean undersideTransparency) {
|
||||
this.undersideTransparency = undersideTransparency;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldExportToGerber() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
|
||||
IDrawingObserver drawingObserver) {
|
||||
capturedTransforms.add(new AffineTransform(g2d.getTransform()));
|
||||
if (g2d.getComposite() instanceof AlphaComposite) {
|
||||
capturedAlphas.add(((AlphaComposite) g2d.getComposite()).getAlpha());
|
||||
} else {
|
||||
capturedAlphas.add(1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class TransformTrackingComponent extends MockDIYComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public List<AffineTransform> capturedTransforms = new ArrayList<>();
|
||||
public List<Float> capturedAlphas = new ArrayList<>();
|
||||
private Point2D controlPoint = new Point2D.Double(150, 150);
|
||||
|
||||
@Override
|
||||
public int getControlPointCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point2D getControlPoint(int index) {
|
||||
return controlPoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
|
||||
IDrawingObserver drawingObserver) {
|
||||
capturedTransforms.add(new AffineTransform(g2d.getTransform()));
|
||||
if (g2d.getComposite() instanceof AlphaComposite) {
|
||||
capturedAlphas.add(((AlphaComposite) g2d.getComposite()).getAlpha());
|
||||
} else {
|
||||
capturedAlphas.add(1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DrawingManager createDrawingManager() {
|
||||
return new DrawingManager(new MessageDispatcher<EventType>(false), InMemoryConfigurationManager.getInstance());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMirrorBelow() {
|
||||
Project project = new Project();
|
||||
MockBoard board = new MockBoard();
|
||||
board.setBoardRectangle(new Rectangle2D.Double(100, 100, 200, 300));
|
||||
board.setUndersideDisplay(BoardUndersideDisplay.BELOW);
|
||||
board.setUndersideOffset(new Size(20.0, SizeUnit.px));
|
||||
board.setUndersideTransparency(true);
|
||||
|
||||
TransformTrackingComponent component = new TransformTrackingComponent();
|
||||
project.getComponents().add(board);
|
||||
project.getComponents().add(component);
|
||||
|
||||
DrawingManager drawingManager = createDrawingManager();
|
||||
BufferedImage img = new BufferedImage(1000, 1000, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g2d = img.createGraphics();
|
||||
|
||||
drawingManager.drawProject(g2d, project, EnumSet.of(DrawOption.ZOOM), null, null,
|
||||
Collections.emptyList(), Collections.emptySet(), Collections.emptySet(), null, null, false, 1.0, 1.0, null);
|
||||
|
||||
g2d.dispose();
|
||||
|
||||
// The component should be drawn twice: once normally and once mirrored
|
||||
assertEquals(2, component.capturedTransforms.size());
|
||||
|
||||
// Original drawing: identity / no reflection
|
||||
AffineTransform normalTx = component.capturedTransforms.get(0);
|
||||
Point2D p = new Point2D.Double(150, 150);
|
||||
Point2D normalP = normalTx.transform(p, null);
|
||||
assertEquals(150.0, normalP.getX(), 0.001);
|
||||
assertEquals(150.0, normalP.getY(), 0.001);
|
||||
|
||||
// Mirrored drawing: BELOW reflection across Y = maxY + offset/2 = 400 + 10 = 410
|
||||
// Expected y' = 2 * 410 - 150 = 820 - 150 = 670
|
||||
AffineTransform mirrorTx = component.capturedTransforms.get(1);
|
||||
Point2D mirroredP = mirrorTx.transform(p, null);
|
||||
assertEquals(150.0, mirroredP.getX(), 0.001);
|
||||
assertEquals(670.0, mirroredP.getY(), 0.001);
|
||||
|
||||
// Check transparency
|
||||
assertEquals(2, component.capturedAlphas.size());
|
||||
assertEquals(1.0f, component.capturedAlphas.get(0), 0.01f);
|
||||
assertEquals(0.5f, component.capturedAlphas.get(1), 0.01f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMirrorAbove() {
|
||||
Project project = new Project();
|
||||
MockBoard board = new MockBoard();
|
||||
board.setBoardRectangle(new Rectangle2D.Double(100, 100, 200, 300));
|
||||
board.setUndersideDisplay(BoardUndersideDisplay.ABOVE);
|
||||
board.setUndersideOffset(new Size(40.0, SizeUnit.px));
|
||||
board.setUndersideTransparency(false);
|
||||
|
||||
TransformTrackingComponent component = new TransformTrackingComponent();
|
||||
project.getComponents().add(board);
|
||||
project.getComponents().add(component);
|
||||
|
||||
DrawingManager drawingManager = createDrawingManager();
|
||||
BufferedImage img = new BufferedImage(1000, 1000, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g2d = img.createGraphics();
|
||||
|
||||
drawingManager.drawProject(g2d, project, EnumSet.of(DrawOption.ZOOM), null, null,
|
||||
Collections.emptyList(), Collections.emptySet(), Collections.emptySet(), null, null, false, 1.0, 1.0, null);
|
||||
|
||||
g2d.dispose();
|
||||
|
||||
assertEquals(2, component.capturedTransforms.size());
|
||||
|
||||
// Mirrored drawing: ABOVE reflection across Y = minY - offset/2 = 100 - 20 = 80
|
||||
// Expected y' = 2 * 80 - 150 = 160 - 150 = 10
|
||||
AffineTransform mirrorTx = component.capturedTransforms.get(1);
|
||||
Point2D mirroredP = mirrorTx.transform(new Point2D.Double(150, 150), null);
|
||||
assertEquals(150.0, mirroredP.getX(), 0.001);
|
||||
assertEquals(10.0, mirroredP.getY(), 0.001);
|
||||
|
||||
// Transparency should not be 0.5 when undersideTransparency is false
|
||||
assertEquals(1.0f, component.capturedAlphas.get(1), 0.01f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMirrorLeft() {
|
||||
Project project = new Project();
|
||||
MockBoard board = new MockBoard();
|
||||
board.setBoardRectangle(new Rectangle2D.Double(100, 100, 200, 300));
|
||||
board.setUndersideDisplay(BoardUndersideDisplay.LEFT);
|
||||
board.setUndersideOffset(new Size(20.0, SizeUnit.px));
|
||||
|
||||
TransformTrackingComponent component = new TransformTrackingComponent();
|
||||
project.getComponents().add(board);
|
||||
project.getComponents().add(component);
|
||||
|
||||
DrawingManager drawingManager = createDrawingManager();
|
||||
BufferedImage img = new BufferedImage(1000, 1000, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g2d = img.createGraphics();
|
||||
|
||||
drawingManager.drawProject(g2d, project, EnumSet.of(DrawOption.ZOOM), null, null,
|
||||
Collections.emptyList(), Collections.emptySet(), Collections.emptySet(), null, null, false, 1.0, 1.0, null);
|
||||
|
||||
g2d.dispose();
|
||||
|
||||
assertEquals(2, component.capturedTransforms.size());
|
||||
|
||||
// Mirrored drawing: LEFT reflection across X = minX - offset/2 = 100 - 10 = 90
|
||||
// Expected x' = 2 * 90 - 150 = 180 - 150 = 30
|
||||
AffineTransform mirrorTx = component.capturedTransforms.get(1);
|
||||
Point2D mirroredP = mirrorTx.transform(new Point2D.Double(150, 150), null);
|
||||
assertEquals(30.0, mirroredP.getX(), 0.001);
|
||||
assertEquals(150.0, mirroredP.getY(), 0.001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMirrorRight() {
|
||||
Project project = new Project();
|
||||
MockBoard board = new MockBoard();
|
||||
board.setBoardRectangle(new Rectangle2D.Double(100, 100, 200, 300));
|
||||
board.setUndersideDisplay(BoardUndersideDisplay.RIGHT);
|
||||
board.setUndersideOffset(new Size(20.0, SizeUnit.px));
|
||||
|
||||
TransformTrackingComponent component = new TransformTrackingComponent();
|
||||
project.getComponents().add(board);
|
||||
project.getComponents().add(component);
|
||||
|
||||
DrawingManager drawingManager = createDrawingManager();
|
||||
BufferedImage img = new BufferedImage(1000, 1000, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g2d = img.createGraphics();
|
||||
|
||||
drawingManager.drawProject(g2d, project, EnumSet.of(DrawOption.ZOOM), null, null,
|
||||
Collections.emptyList(), Collections.emptySet(), Collections.emptySet(), null, null, false, 1.0, 1.0, null);
|
||||
|
||||
g2d.dispose();
|
||||
|
||||
assertEquals(2, component.capturedTransforms.size());
|
||||
|
||||
// Mirrored drawing: RIGHT reflection across X = maxX + offset/2 = 300 + 10 = 310
|
||||
// Expected x' = 2 * 310 - 150 = 620 - 150 = 470
|
||||
AffineTransform mirrorTx = component.capturedTransforms.get(1);
|
||||
Point2D mirroredP = mirrorTx.transform(new Point2D.Double(150, 150), null);
|
||||
assertEquals(470.0, mirroredP.getX(), 0.001);
|
||||
assertEquals(150.0, mirroredP.getY(), 0.001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUndersideDisplayNone() {
|
||||
Project project = new Project();
|
||||
MockBoard board = new MockBoard();
|
||||
board.setUndersideDisplay(BoardUndersideDisplay.NONE);
|
||||
|
||||
TransformTrackingComponent component = new TransformTrackingComponent();
|
||||
project.getComponents().add(board);
|
||||
project.getComponents().add(component);
|
||||
|
||||
DrawingManager drawingManager = createDrawingManager();
|
||||
BufferedImage img = new BufferedImage(1000, 1000, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g2d = img.createGraphics();
|
||||
|
||||
drawingManager.drawProject(g2d, project, EnumSet.of(DrawOption.ZOOM), null, null,
|
||||
Collections.emptyList(), Collections.emptySet(), Collections.emptySet(), null, null, false, 1.0, 1.0, null);
|
||||
|
||||
g2d.dispose();
|
||||
|
||||
// No mirrored drawing
|
||||
assertEquals(1, component.capturedTransforms.size());
|
||||
assertEquals(1, board.capturedTransforms.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTextUnmirroringHorizontal() {
|
||||
BufferedImage img = new BufferedImage(500, 500, BufferedImage.TYPE_INT_ARGB);
|
||||
final List<AffineTransform> capturedDuringDrawString = new ArrayList<>();
|
||||
Graphics2D canvasG2d = new Graphics2DProxy(img.createGraphics()) {
|
||||
@Override
|
||||
public void drawString(String str, int x, int y) {
|
||||
capturedDuringDrawString.add(new AffineTransform(getTransform()));
|
||||
super.drawString(str, x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawString(String str, float x, float y) {
|
||||
capturedDuringDrawString.add(new AffineTransform(getTransform()));
|
||||
super.drawString(str, x, y);
|
||||
}
|
||||
};
|
||||
|
||||
G2DWrapper wrapper = new G2DWrapper(canvasG2d, 1.0, EnumSet.noneOf(DrawOption.class));
|
||||
|
||||
// Simulate horizontal mirror mode
|
||||
wrapper.setMirrorDirection(G2DWrapper.MirrorDirection.HORIZONTAL);
|
||||
AffineTransform mirrorTx = new AffineTransform();
|
||||
mirrorTx.translate(300, 0);
|
||||
mirrorTx.scale(-1.0, 1.0);
|
||||
mirrorTx.translate(-300, 0);
|
||||
wrapper.transform(mirrorTx);
|
||||
|
||||
wrapper.drawString("10K Log", 200, 200);
|
||||
|
||||
assertEquals(1, capturedDuringDrawString.size());
|
||||
AffineTransform textTx = capturedDuringDrawString.get(0);
|
||||
|
||||
// The determinant should be positive (un-mirrored / right-reading text)
|
||||
assertTrue("Text transform determinant should be positive (not mirrored)", textTx.getDeterminant() > 0);
|
||||
|
||||
// After drawing, wrapper transform should still be the mirrorTx
|
||||
assertEquals(-1.0, wrapper.getTransform().getScaleX(), 0.001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTextUnmirroringVertical() {
|
||||
BufferedImage img = new BufferedImage(500, 500, BufferedImage.TYPE_INT_ARGB);
|
||||
final List<AffineTransform> capturedDuringDrawString = new ArrayList<>();
|
||||
Graphics2D canvasG2d = new Graphics2DProxy(img.createGraphics()) {
|
||||
@Override
|
||||
public void drawString(String str, int x, int y) {
|
||||
capturedDuringDrawString.add(new AffineTransform(getTransform()));
|
||||
super.drawString(str, x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawString(String str, float x, float y) {
|
||||
capturedDuringDrawString.add(new AffineTransform(getTransform()));
|
||||
super.drawString(str, x, y);
|
||||
}
|
||||
};
|
||||
|
||||
G2DWrapper wrapper = new G2DWrapper(canvasG2d, 1.0, EnumSet.noneOf(DrawOption.class));
|
||||
|
||||
// Simulate vertical mirror mode
|
||||
wrapper.setMirrorDirection(G2DWrapper.MirrorDirection.VERTICAL);
|
||||
AffineTransform mirrorTx = new AffineTransform();
|
||||
mirrorTx.translate(0, 300);
|
||||
mirrorTx.scale(1.0, -1.0);
|
||||
mirrorTx.translate(0, -300);
|
||||
wrapper.transform(mirrorTx);
|
||||
|
||||
wrapper.drawString("47uF", 200, 200);
|
||||
|
||||
assertEquals(1, capturedDuringDrawString.size());
|
||||
AffineTransform textTx = capturedDuringDrawString.get(0);
|
||||
|
||||
// The determinant should be positive (un-mirrored / right-reading text)
|
||||
assertTrue("Text transform determinant should be positive (not mirrored)", textTx.getDeterminant() > 0);
|
||||
|
||||
// After drawing, wrapper transform should still be the mirrorTx
|
||||
assertEquals(-1.0, wrapper.getTransform().getScaleY(), 0.001);
|
||||
}
|
||||
|
||||
// Simple delegating Graphics2D proxy for testing
|
||||
private static class Graphics2DProxy extends Graphics2D {
|
||||
private final Graphics2D delegate;
|
||||
|
||||
public Graphics2DProxy(Graphics2D delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(java.awt.Shape s) { delegate.draw(s); }
|
||||
@Override
|
||||
public boolean drawImage(java.awt.Image img, AffineTransform xform, java.awt.image.ImageObserver obs) { return delegate.drawImage(img, xform, obs); }
|
||||
@Override
|
||||
public void drawImage(BufferedImage img, java.awt.image.BufferedImageOp op, int x, int y) { delegate.drawImage(img, op, x, y); }
|
||||
@Override
|
||||
public void drawRenderedImage(java.awt.image.RenderedImage img, AffineTransform xform) { delegate.drawRenderedImage(img, xform); }
|
||||
@Override
|
||||
public void drawRenderableImage(java.awt.image.renderable.RenderableImage img, AffineTransform xform) { delegate.drawRenderableImage(img, xform); }
|
||||
@Override
|
||||
public void drawString(String str, int x, int y) { delegate.drawString(str, x, y); }
|
||||
@Override
|
||||
public void drawString(String str, float x, float y) { delegate.drawString(str, x, y); }
|
||||
@Override
|
||||
public void drawString(java.text.AttributedCharacterIterator iterator, int x, int y) { delegate.drawString(iterator, x, y); }
|
||||
@Override
|
||||
public void drawString(java.text.AttributedCharacterIterator iterator, float x, float y) { delegate.drawString(iterator, x, y); }
|
||||
@Override
|
||||
public void drawGlyphVector(java.awt.font.GlyphVector g, float x, float y) { delegate.drawGlyphVector(g, x, y); }
|
||||
@Override
|
||||
public void fill(java.awt.Shape s) { delegate.fill(s); }
|
||||
@Override
|
||||
public boolean hit(java.awt.Rectangle rect, java.awt.Shape s, boolean onStroke) { return delegate.hit(rect, s, onStroke); }
|
||||
@Override
|
||||
public java.awt.GraphicsConfiguration getDeviceConfiguration() { return delegate.getDeviceConfiguration(); }
|
||||
@Override
|
||||
public void setComposite(java.awt.Composite comp) { delegate.setComposite(comp); }
|
||||
@Override
|
||||
public void setPaint(java.awt.Paint paint) { delegate.setPaint(paint); }
|
||||
@Override
|
||||
public void setStroke(java.awt.Stroke s) { delegate.setStroke(s); }
|
||||
@Override
|
||||
public void setRenderingHint(java.awt.RenderingHints.Key hintKey, Object hintValue) { delegate.setRenderingHint(hintKey, hintValue); }
|
||||
@Override
|
||||
public Object getRenderingHint(java.awt.RenderingHints.Key hintKey) { return delegate.getRenderingHint(hintKey); }
|
||||
@Override
|
||||
public void setRenderingHints(java.util.Map<?, ?> hints) { delegate.setRenderingHints(hints); }
|
||||
@Override
|
||||
public void addRenderingHints(java.util.Map<?, ?> hints) { delegate.addRenderingHints(hints); }
|
||||
@Override
|
||||
public java.awt.RenderingHints getRenderingHints() { return delegate.getRenderingHints(); }
|
||||
@Override
|
||||
public void translate(int x, int y) { delegate.translate(x, y); }
|
||||
@Override
|
||||
public void translate(double tx, double ty) { delegate.translate(tx, ty); }
|
||||
@Override
|
||||
public void rotate(double theta) { delegate.rotate(theta); }
|
||||
@Override
|
||||
public void rotate(double theta, double x, double y) { delegate.rotate(theta, x, y); }
|
||||
@Override
|
||||
public void scale(double sx, double sy) { delegate.scale(sx, sy); }
|
||||
@Override
|
||||
public void shear(double shx, double shy) { delegate.shear(shx, shy); }
|
||||
@Override
|
||||
public void transform(AffineTransform Tx) { delegate.transform(Tx); }
|
||||
@Override
|
||||
public void setTransform(AffineTransform Tx) { delegate.setTransform(Tx); }
|
||||
@Override
|
||||
public AffineTransform getTransform() { return delegate.getTransform(); }
|
||||
@Override
|
||||
public java.awt.Paint getPaint() { return delegate.getPaint(); }
|
||||
@Override
|
||||
public java.awt.Composite getComposite() { return delegate.getComposite(); }
|
||||
@Override
|
||||
public void setBackground(java.awt.Color color) { delegate.setBackground(color); }
|
||||
@Override
|
||||
public java.awt.Color getBackground() { return delegate.getBackground(); }
|
||||
@Override
|
||||
public java.awt.Stroke getStroke() { return delegate.getStroke(); }
|
||||
@Override
|
||||
public void clip(java.awt.Shape s) { delegate.clip(s); }
|
||||
@Override
|
||||
public java.awt.font.FontRenderContext getFontRenderContext() { return delegate.getFontRenderContext(); }
|
||||
@Override
|
||||
public java.awt.Graphics create() { return delegate.create(); }
|
||||
@Override
|
||||
public java.awt.Color getColor() { return delegate.getColor(); }
|
||||
@Override
|
||||
public void setColor(java.awt.Color c) { delegate.setColor(c); }
|
||||
@Override
|
||||
public void setPaintMode() { delegate.setPaintMode(); }
|
||||
@Override
|
||||
public void setXORMode(java.awt.Color c1) { delegate.setXORMode(c1); }
|
||||
@Override
|
||||
public java.awt.Font getFont() { return delegate.getFont(); }
|
||||
@Override
|
||||
public void setFont(java.awt.Font font) { delegate.setFont(font); }
|
||||
@Override
|
||||
public java.awt.FontMetrics getFontMetrics(java.awt.Font f) { return delegate.getFontMetrics(f); }
|
||||
@Override
|
||||
public java.awt.Rectangle getClipBounds() { return delegate.getClipBounds(); }
|
||||
@Override
|
||||
public void clipRect(int x, int y, int width, int height) { delegate.clipRect(x, y, width, height); }
|
||||
@Override
|
||||
public void setClip(int x, int y, int width, int height) { delegate.setClip(x, y, width, height); }
|
||||
@Override
|
||||
public java.awt.Shape getClip() { return delegate.getClip(); }
|
||||
@Override
|
||||
public void setClip(java.awt.Shape clip) { delegate.setClip(clip); }
|
||||
@Override
|
||||
public void copyArea(int x, int y, int width, int height, int dx, int dy) { delegate.copyArea(x, y, width, height, dx, dy); }
|
||||
@Override
|
||||
public void drawLine(int x1, int y1, int x2, int y2) { delegate.drawLine(x1, y1, x2, y2); }
|
||||
@Override
|
||||
public void fillRect(int x, int y, int width, int height) { delegate.fillRect(x, y, width, height); }
|
||||
@Override
|
||||
public void clearRect(int x, int y, int width, int height) { delegate.clearRect(x, y, width, height); }
|
||||
@Override
|
||||
public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { delegate.drawRoundRect(x, y, width, height, arcWidth, arcHeight); }
|
||||
@Override
|
||||
public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { delegate.fillRoundRect(x, y, width, height, arcWidth, arcHeight); }
|
||||
@Override
|
||||
public void drawOval(int x, int y, int width, int height) { delegate.drawOval(x, y, width, height); }
|
||||
@Override
|
||||
public void fillOval(int x, int y, int width, int height) { delegate.fillOval(x, y, width, height); }
|
||||
@Override
|
||||
public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { delegate.drawArc(x, y, width, height, startAngle, arcAngle); }
|
||||
@Override
|
||||
public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) { delegate.fillArc(x, y, width, height, startAngle, arcAngle); }
|
||||
@Override
|
||||
public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) { delegate.drawPolyline(xPoints, yPoints, nPoints); }
|
||||
@Override
|
||||
public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) { delegate.drawPolygon(xPoints, yPoints, nPoints); }
|
||||
@Override
|
||||
public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) { delegate.fillPolygon(xPoints, yPoints, nPoints); }
|
||||
@Override
|
||||
public boolean drawImage(java.awt.Image img, int x, int y, java.awt.image.ImageObserver observer) { return delegate.drawImage(img, x, y, observer); }
|
||||
@Override
|
||||
public boolean drawImage(java.awt.Image img, int x, int y, int width, int height, java.awt.image.ImageObserver observer) { return delegate.drawImage(img, x, y, width, height, observer); }
|
||||
@Override
|
||||
public boolean drawImage(java.awt.Image img, int x, int y, java.awt.Color bgcolor, java.awt.image.ImageObserver observer) { return delegate.drawImage(img, x, y, bgcolor, observer); }
|
||||
@Override
|
||||
public boolean drawImage(java.awt.Image img, int x, int y, int width, int height, java.awt.Color bgcolor, java.awt.image.ImageObserver observer) { return delegate.drawImage(img, x, y, width, height, bgcolor, observer); }
|
||||
@Override
|
||||
public boolean drawImage(java.awt.Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, java.awt.image.ImageObserver observer) { return delegate.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer); }
|
||||
@Override
|
||||
public boolean drawImage(java.awt.Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, java.awt.Color bgcolor, java.awt.image.ImageObserver observer) { return delegate.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer); }
|
||||
@Override
|
||||
public void dispose() { delegate.dispose(); }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user