diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/robot/RRMapDraw.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/robot/RRMapDraw.java index b61ab7f071147..851215bc123b2 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/robot/RRMapDraw.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/robot/RRMapDraw.java @@ -51,6 +51,8 @@ @NonNullByDefault public class RRMapDraw { + private static final float MM = 50.0f; + private static final int MAP_OUTSIDE = 0x00; private static final int MAP_WALL = 0x01; private static final int MAP_INSIDE = 0xFF; @@ -101,6 +103,10 @@ public int getHeight() { return rmfp.getImgHeight(); } + public RRMapFileParser getMapParseDetails() { + return this.rmfp; + } + /** * load Gzipped RR inputstream * @@ -198,8 +204,8 @@ private void drawPath(Graphics2D g2d, float scale) { float prvX = 0; float prvY = 0; for (float[] point : rmfp.getPaths().get(pathType)) { - float x = point[0] * scale; - float y = point[1] * scale; + float x = toXCoord(point[0]) * scale; + float y = toYCoord(point[1]) * scale; if (prvX > 1) { g2d.draw(new Line2D.Float(prvX, prvY, x, y)); } @@ -211,10 +217,10 @@ private void drawPath(Graphics2D g2d, float scale) { private void drawZones(Graphics2D g2d, float scale) { for (float[] point : rmfp.getZones()) { - float x = point[0] * scale; - float y = point[1] * scale; - float x1 = point[2] * scale; - float y1 = point[3] * scale; + float x = toXCoord(point[0]) * scale; + float y = toYCoord(point[1]) * scale; + float x1 = toXCoord(point[2]) * scale; + float y1 = toYCoord(point[3]) * scale; float sx = Math.min(x, x1); float w = Math.max(x, x1) - sx; float sy = Math.min(y, y1); @@ -227,14 +233,14 @@ private void drawZones(Graphics2D g2d, float scale) { private void drawNoGo(Graphics2D g2d, float scale) { for (Integer area : rmfp.getAreas().keySet()) { for (float[] point : rmfp.getAreas().get(area)) { - float x = point[0] * scale; - float y = point[1] * scale; - float x1 = point[2] * scale; - float y1 = point[3] * scale; - float x2 = point[4] * scale; - float y2 = point[5] * scale; - float x3 = point[6] * scale; - float y3 = point[7] * scale; + float x = toXCoord(point[0]) * scale; + float y = toYCoord(point[1]) * scale; + float x1 = toXCoord(point[2]) * scale; + float y1 = toYCoord(point[3]) * scale; + float x2 = toXCoord(point[4]) * scale; + float y2 = toYCoord(point[5]) * scale; + float x3 = toXCoord(point[6]) * scale; + float y3 = toYCoord(point[7]) * scale; Path2D noGo = new Path2D.Float(); noGo.moveTo(x, y); noGo.lineTo(x1, y1); @@ -253,10 +259,10 @@ private void drawWalls(Graphics2D g2d, float scale) { Stroke stroke = new BasicStroke(3 * scale); g2d.setStroke(stroke); for (float[] point : rmfp.getWalls()) { - float x = point[0] * scale; - float y = point[1] * scale; - float x1 = point[2] * scale; - float y1 = point[3] * scale; + float x = toXCoord(point[0]) * scale; + float y = toYCoord(point[1]) * scale; + float x1 = toXCoord(point[2]) * scale; + float y1 = toYCoord(point[3]) * scale; g2d.setColor(Color.RED); g2d.draw(new Line2D.Float(x, y, x1, y1)); } @@ -267,13 +273,17 @@ private void drawRobo(Graphics2D g2d, float scale) { Stroke stroke = new BasicStroke(2 * scale); g2d.setStroke(stroke); g2d.setColor(COLOR_CHARGER_HALO); - drawCircle(g2d, rmfp.getChargerX() * scale, rmfp.getChargerY() * scale, radius); - drawCenteredImg(g2d, scale / 8, "charger.png", rmfp.getChargerX() * scale, rmfp.getChargerY() * scale); + final float chargerX = toXCoord(rmfp.getChargerX()) * scale; + final float chargerY = toYCoord(rmfp.getChargerY()) * scale; + drawCircle(g2d, chargerX, chargerY, radius); + drawCenteredImg(g2d, scale / 8, "charger.png", chargerX, chargerY); radius = 3 * scale; g2d.setColor(COLOR_ROBO); - drawCircle(g2d, rmfp.getRoboX() * scale, rmfp.getRoboY() * scale, radius); + final float roboX = toXCoord(rmfp.getRoboX()) * scale; + final float roboY = toYCoord(rmfp.getRoboY()) * scale; + drawCircle(g2d, roboX, roboY, radius); if (scale > 1.5) { - drawCenteredImg(g2d, scale / 15, "robo.png", rmfp.getRoboX() * scale, rmfp.getRoboY() * scale); + drawCenteredImg(g2d, scale / 15, "robo.png", roboX, roboY); } } @@ -301,8 +311,8 @@ private void drawCenteredImg(Graphics2D g2d, float scale, String imgFile, float } private void drawGoTo(Graphics2D g2d, float scale) { - float x = rmfp.getGotoX() * scale; - float y = rmfp.getGotoY() * scale; + float x = toXCoord(rmfp.getGotoX()) * scale; + float y = toYCoord(rmfp.getGotoY()) * scale; if (!(x == 0 && y == 0)) { g2d.setStroke(new BasicStroke()); g2d.setColor(Color.YELLOW); @@ -409,6 +419,14 @@ public boolean writePic(String filename, String formatName, float scale) throws return ImageIO.write(getImage(scale), formatName, new File(filename)); } + private float toXCoord(float x) { + return rmfp.getImgWidth() + rmfp.getLeft() - (x / MM); + } + + private float toYCoord(float y) { + return y / MM - rmfp.getTop(); + } + @Override public String toString() { return rmfp.toString(); diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/robot/RRMapFileParser.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/robot/RRMapFileParser.java index 0e70fe27103a4..68c8eea269be0 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/robot/RRMapFileParser.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/robot/RRMapFileParser.java @@ -59,8 +59,6 @@ public class RRMapFileParser { public static final String PATH_POINT_SIZE = "pointSize"; public static final String PATH_ANGLE = "angle"; - private static final float MM = 50.0f; - private byte[] image = new byte[] { 0 }; private final int majorVersion; private final int minorVersion; @@ -73,7 +71,6 @@ public class RRMapFileParser { private int imageSize; private int top; private int left; - private int offset; private int chargerX; private int chargerY; @@ -124,7 +121,6 @@ public RRMapFileParser(byte[] raw) { this.left = getUInt32LE(header, blockHeaderLength - 12); this.imgHeight = (getUInt32LE(header, blockHeaderLength - 8)); this.imgWidth = getUInt32LE(header, blockHeaderLength - 4); - this.offset = imgWidth + left; this.image = data; break; case ROBOT_POSITION: @@ -144,8 +140,8 @@ public RRMapFileParser(byte[] raw) { detail.put(PATH_POINT_SIZE, getUInt32LE(header, 0x0C)); detail.put(PATH_ANGLE, getUInt32LE(header, 0x10)); for (int pathpair = 0; pathpair < pairs; pathpair++) { - float x = offset - (getUInt16(getBytes(raw, blockDataStart + pathpair * 4, 2))) / MM; - float y = getUInt16(getBytes(raw, blockDataStart + pathpair * 4 + 2, 2)) / MM - top; + float x = (getUInt16(getBytes(raw, blockDataStart + pathpair * 4, 2))); + float y = getUInt16(getBytes(raw, blockDataStart + pathpair * 4 + 2, 2)); path.add(new float[] { x, y }); } paths.put(blocktype, path); @@ -154,16 +150,16 @@ public RRMapFileParser(byte[] raw) { case CURRENTLY_CLEANED_ZONES: int zonePairs = getUInt16(header, 0x08); for (int zonePair = 0; zonePair < zonePairs; zonePair++) { - float x0 = offset - (getUInt16(raw, blockDataStart + zonePair * 8)) / MM; - float y0 = getUInt16(raw, blockDataStart + zonePair * 8 + 2) / MM - top; - float x1 = offset - (getUInt16(raw, blockDataStart + zonePair * 8 + 4)) / MM; - float y1 = getUInt16(raw, blockDataStart + zonePair * 8 + 6) / MM - top; + float x0 = (getUInt16(raw, blockDataStart + zonePair * 8)); + float y0 = getUInt16(raw, blockDataStart + zonePair * 8 + 2); + float x1 = (getUInt16(raw, blockDataStart + zonePair * 8 + 4)); + float y1 = getUInt16(raw, blockDataStart + zonePair * 8 + 6); zones.add(new float[] { x0, y0, x1, y1 }); } break; case GOTO_TARGET: - this.gotoX = offset - getUInt16(data, 0x00) / MM; - this.gotoY = getUInt16(data, 0x02) / MM - top; + this.gotoX = getUInt16(data, 0x00); + this.gotoY = getUInt16(data, 0x02); break; case DIGEST: isValid = Arrays.equals(data, sha1Hash(getBytes(raw, 0, mapHeaderLength + mapDataLength - 20))); @@ -171,10 +167,10 @@ public RRMapFileParser(byte[] raw) { case VIRTUAL_WALLS: int wallPairs = getUInt16(header, 0x08); for (int wallPair = 0; wallPair < wallPairs; wallPair++) { - float x0 = offset - (getUInt16(raw, blockDataStart + wallPair * 8)) / MM; - float y0 = getUInt16(raw, blockDataStart + wallPair * 8 + 2) / MM - top; - float x1 = offset - (getUInt16(raw, blockDataStart + wallPair * 8 + 4)) / MM; - float y1 = getUInt16(raw, blockDataStart + wallPair * 8 + 6) / MM - top; + float x0 = (getUInt16(raw, blockDataStart + wallPair * 8)); + float y0 = getUInt16(raw, blockDataStart + wallPair * 8 + 2); + float x1 = (getUInt16(raw, blockDataStart + wallPair * 8 + 4)); + float y1 = getUInt16(raw, blockDataStart + wallPair * 8 + 6); walls.add(new float[] { x0, y0, x1, y1 }); } break; @@ -183,14 +179,14 @@ public RRMapFileParser(byte[] raw) { int areaPairs = getUInt16(header, 0x08); ArrayList area = new ArrayList(); for (int areaPair = 0; areaPair < areaPairs; areaPair++) { - float x0 = offset - (getUInt16(raw, blockDataStart + areaPair * 16)) / MM; - float y0 = getUInt16(raw, blockDataStart + areaPair * 16 + 2) / MM - top; - float x1 = offset - (getUInt16(raw, blockDataStart + areaPair * 16 + 4)) / MM; - float y1 = getUInt16(raw, blockDataStart + areaPair * 16 + 6) / MM - top; - float x2 = offset - (getUInt16(raw, blockDataStart + areaPair * 16 + 8)) / MM; - float y2 = getUInt16(raw, blockDataStart + areaPair * 16 + 10) / MM - top; - float x3 = offset - (getUInt16(raw, blockDataStart + areaPair * 16 + 12)) / MM; - float y3 = getUInt16(raw, blockDataStart + areaPair * 16 + 14) / MM - top; + float x0 = (getUInt16(raw, blockDataStart + areaPair * 16)); + float y0 = getUInt16(raw, blockDataStart + areaPair * 16 + 2); + float x1 = (getUInt16(raw, blockDataStart + areaPair * 16 + 4)); + float y1 = getUInt16(raw, blockDataStart + areaPair * 16 + 6); + float x2 = (getUInt16(raw, blockDataStart + areaPair * 16 + 8)); + float y2 = getUInt16(raw, blockDataStart + areaPair * 16 + 10); + float x3 = (getUInt16(raw, blockDataStart + areaPair * 16 + 12)); + float y3 = getUInt16(raw, blockDataStart + areaPair * 16 + 14); area.add(new float[] { x0, y0, x1, y1, x2, y2, x3, y3 }); } areas.put(Integer.valueOf(blocktype & 0xFF), area); @@ -277,14 +273,18 @@ public String toString() { minorVersion, mapIndex, mapSequence); pw.printf("Image:\tsize: %9d\ttop: %9d\tleft: %9d height: %9d width: %9d\r\n", imageSize, top, left, imgHeight, imgWidth); - pw.printf("Charger pos:\tX: %.1f\tY: %.1f\r\n", getChargerX(), getChargerY()); - pw.printf("Robo pos:\tX: %.1f\tY: %.1f\tAngle: %d\r\n", getRoboX(), getRoboY(), getRoboA()); - pw.printf("Goto:\tX: %.1f\tY: %.1f\r\n", getGotoX(), getGotoY()); + pw.printf("Charger pos:\tX: %.0f\tY: %.0f\r\n", getChargerX(), getChargerY()); + pw.printf("Robo pos:\tX: %.0f\tY: %.0f\tAngle: %d\r\n", getRoboX(), getRoboY(), getRoboA()); + pw.printf("Goto:\tX: %.0f\tY: %.0f\r\n", getGotoX(), getGotoY()); for (Integer area : areas.keySet()) { pw.print(area == NO_GO_AREAS ? "No Go zones:\t" : "MFBZS zones:\t"); pw.printf("%d\r\n", areas.get(area).size()); + printAreaDetails(areas.get(area), pw); } pw.printf("Walls:\t%d\r\n", walls.size()); + printAreaDetails(walls, pw); + pw.printf("Zones:\t%d\r\n", zones.size()); + printAreaDetails(zones, pw); pw.printf("Obstacles:\t%d\r\n", obstacles.size()); pw.printf("Blocks:\t%d\r\n", blocks.length); pw.print("Paths:"); @@ -299,6 +299,16 @@ public String toString() { return sw.toString(); } + private void printAreaDetails(ArrayList areas, PrintWriter pw) { + areas.forEach(area -> { + pw.printf("\tArea coordinates:"); + for (int i = 0; i < area.length; i++) { + pw.printf("\t%.0f", area[i]); + } + pw.println(); + }); + } + /** * Compute SHA-1 hash value for the byte array * @@ -363,19 +373,19 @@ public ArrayList getZones() { } public float getRoboX() { - return offset - (roboX / MM); + return roboX; } public float getRoboY() { - return roboY / MM - top; + return roboY; } public float getChargerX() { - return offset - (chargerX / MM); + return chargerX; } public float getChargerY() { - return chargerY / MM - top; + return chargerY; } public float getGotoX() { @@ -413,4 +423,5 @@ public ArrayList getObstacles() { public byte[] getBlocks() { return blocks; } + } diff --git a/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/RoboMapViewer.java b/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/RoboMapViewer.java index 3c7db4f413e65..b54df4c1bb935 100644 --- a/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/RoboMapViewer.java +++ b/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/RoboMapViewer.java @@ -18,10 +18,14 @@ import java.awt.Dimension; import java.awt.Graphics; import java.awt.HeadlessException; +import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; import java.awt.image.BufferedImage; import java.io.File; import java.nio.file.InvalidPathException; @@ -43,6 +47,7 @@ import org.eclipse.jdt.annotation.Nullable; import org.junit.Ignore; import org.openhab.binding.miio.internal.robot.RRMapDraw; +import org.openhab.binding.miio.internal.robot.RRMapFileParser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -55,6 +60,7 @@ public class RoboMapViewer extends JFrame { private static final String TITLE = "Offline Xiaomi Robot Radar Map Viewer"; + private static final float MM = 50.0f; private final JFrame parent; private final RRDrawPanel rrDrawPanel = new RRDrawPanel(); private final JTextArea textArea = new JTextArea(); @@ -63,18 +69,20 @@ public class RoboMapViewer extends JFrame { private float scale = 1.0f; private @Nullable File file; + private @Nullable RRMapDraw rrMap; private final Logger logger = LoggerFactory.getLogger(RoboMapViewer.class); + protected MapPoint fromLocation = new MapPoint(); private static final long serialVersionUID = 2623447051590306992L; @Ignore public static void main(String args[]) { System.setProperty("swing.defaultlaf", "javax.swing.plaf.metal.MetalLookAndFeel"); - RoboMapViewer vc = new RoboMapViewer(); + RoboMapViewer vc = new RoboMapViewer(args); vc.setVisible(true); } - public RoboMapViewer() { + public RoboMapViewer(String args[]) { super(TITLE); parent = this; setSize(500, 600); @@ -115,21 +123,76 @@ public RoboMapViewer() { statusbar.add(BorderLayout.EAST, statusbarR); c.add(statusbar, "Last"); - // TODO: have the map details of the coord with mouse click/moveover + rrDrawPanel.addMouseWheelListener(new MouseWheelListener() { + @Override + public void mouseWheelMoved(@Nullable MouseWheelEvent event) { + if (event != null) { + if (event.getWheelRotation() < 0) { + zoomIn(); + } else { + zoomOut(); + } + } + } + }); + + rrDrawPanel.addMouseMotionListener(new MouseMotionListener() { + + @Override + public void mouseDragged(@Nullable MouseEvent e) { + if (e != null) { + rrDrawPanel.setEndPoint(e.getX(), e.getY()); + repaint(); + } + } + + @Override + public void mouseMoved(@Nullable MouseEvent e) { + if (e != null) { + MapPoint roboMouseLocation = MapCoordstoRoboCoords(localCoordtoMapCoords(e.getPoint())); + updateStatusLine(roboMouseLocation); + } + } + }); + rrDrawPanel.addMouseListener((new MouseListener() { + @Override public void mouseReleased(@Nullable MouseEvent e) { + if (e != null) { + rrDrawPanel.setEndPoint(e.getX(), e.getY()); + repaint(); + + if (rrDrawPanel.hasDrawZone()) { + final MapPoint endLocation = MapCoordstoRoboCoords(localCoordtoMapCoords(e.getPoint())); + double minX = Math.min(fromLocation.getX(), endLocation.getX()); + double maxX = Math.max(fromLocation.getX(), endLocation.getX()); + double minY = Math.min(fromLocation.getY(), endLocation.getY()); + double maxY = Math.max(fromLocation.getY(), endLocation.getY()); + textArea.append(String.format( + "Zone coordinates:\t%s, %s\t\tZone clean command: app_zone_clean[ %.0f,%.0f,%.0f,%.0f,1 ]\r\n", + endLocation, fromLocation, minX, minY, maxX, maxY)); + } else { + final MapPoint pointLocation = MapCoordstoRoboCoords(localCoordtoMapCoords(e.getPoint())); + textArea.append(String.format( + "GoTo coordinates:\t[X=%.0f, Y=%.0f]\t\tGoto command: app_goto_target[ %.0f,%.0f ]\r\n", + pointLocation.getX(), pointLocation.getY(), pointLocation.getX(), + pointLocation.getY())); + } + } } @Override public void mousePressed(@Nullable MouseEvent e) { if (e != null) { - logger.info("Click @ {}", e.getPoint()); + rrDrawPanel.setStartPoint(e.getX(), e.getY()); + fromLocation = MapCoordstoRoboCoords(localCoordtoMapCoords(e.getPoint())); } } @Override public void mouseExited(@Nullable MouseEvent e) { + updateStatusLine(null); } @Override @@ -144,21 +207,13 @@ public void mouseClicked(@Nullable MouseEvent e) { scalePButton.addActionListener(new ActionListener() { @Override public void actionPerformed(@Nullable ActionEvent ae) { - scale = scale + 0.5f; - final File f = file; - if (f != null) { - loadfile(f); - } + zoomIn(); } }); scaleMButton.addActionListener(new ActionListener() { @Override public void actionPerformed(@Nullable ActionEvent ae) { - scale = scale < 1.5 ? 1 : scale - 0.5f; - final File f = file; - if (f != null) { - loadfile(f); - } + zoomOut(); } }); @@ -182,7 +237,7 @@ public void actionPerformed(@Nullable ActionEvent ae) { } } } catch (SecurityException e) { - logger.debug("Error finding next file:{}", e); + logger.debug("Error finding next file: {}", e); } } }); @@ -234,7 +289,33 @@ public void actionPerformed(@Nullable ActionEvent ae) { } }); - loadFirstFile(); + if (args.length > 0) { + loadfile(new File(args[0])); + } else { + loadFirstFile(); + } + } + + private MapPoint MapCoordstoRoboCoords(MapPoint imagePoint) { + final RRMapDraw rrMap = this.rrMap; + if (rrMap != null) { + final RRMapFileParser mapDetails = rrMap.getMapParseDetails(); + double xPos = (mapDetails.getLeft() + mapDetails.getImgWidth() - imagePoint.getX()) * MM; + double yPos = (mapDetails.getTop() + imagePoint.getY()) * MM; + return new MapPoint(xPos, yPos); + } else { + return new MapPoint(); + } + } + + private MapPoint localCoordtoMapCoords(Point local) { + final RRMapDraw rrMap = this.rrMap; + if (rrMap != null) { + double xLoc = (rrMap.getWidth() * scale - local.getX()) / scale; + double yLoc = (rrMap.getHeight() * scale - local.getY()) / scale; + return new MapPoint(xLoc, yLoc); + } + return new MapPoint(); } protected boolean isRRFile(File fileEntry) { @@ -258,31 +339,89 @@ private void loadFirstFile() { } } - private void updateStatusLine() { + private void updateStatusLine(@Nullable MapPoint p) { final File f = this.file; if (f != null) { statusbarL.setText(f.getName()); } else { statusbarL.setText(""); } - statusbarR.setText("zoom: " + Float.toString(scale) + "x "); + if (p != null) { + statusbarR.setText(String.format("%s zoom: %.1fx ", p.toString(), scale)); + } else { + statusbarR.setText(String.format("zoom: %.1fx ", scale)); + } } private void loadfile(File file) { try { logger.info("Loading " + file.getPath()); - RRMapDraw rrMap = RRMapDraw.loadImage(file); + final RRMapDraw rrMap = RRMapDraw.loadImage(file); + this.rrMap = rrMap; textArea.setText(rrMap.toString()); parent.setTitle(TITLE + " " + file.getName()); rrDrawPanel.setImage(rrMap.getImage(scale)); rrMap.writePic(file.getPath() + ".jpg", "JPEG", scale); - updateStatusLine(); + updateStatusLine(null); rrDrawPanel.setSize(rrMap.getWidth(), rrMap.getHeight()); } catch (Exception e) { textArea.append("Error while loading: " + e.getMessage()); logger.info("Error while loading {}", e); } } + + private void zoomIn() { + scale = scale + 0.5f; + final File f = file; + if (f != null) { + loadfile(f); + } + } + + private void zoomOut() { + scale = scale < 1.5 ? 1 : scale - 0.5f; + final File f = file; + if (f != null) { + loadfile(f); + } + } +} + +/** + * Point with X & Y coordinate + * + * @author Marcel Verpaalen - Initial contribution + */ +@NonNullByDefault +class MapPoint { + private double x; + private double y; + + public MapPoint() { + this(0, 0); + } + + public MapPoint(MapPoint p) { + this(p.x, p.y); + } + + public MapPoint(double x, double y) { + this.x = x; + this.y = y; + } + + public double getX() { + return x; + } + + public double getY() { + return y; + } + + @Override + public String toString() { + return String.format("[%.0f,%.0f]", x, y); + } } /** @@ -296,12 +435,18 @@ class RRDrawPanel extends JPanel { private @Nullable BufferedImage image; Dimension size = new Dimension(); + int x, y, x2, y2; + @Override protected void paintComponent(@Nullable Graphics g) { super.paintComponent(g); final BufferedImage image = this.image; if (g != null && image != null) { g.drawImage(image, 0, 0, this); + if (hasDrawZone()) { + g.setColor(Color.YELLOW); + drawZoneRect(g, x, y, x2, y2); + } } } @@ -312,6 +457,7 @@ public Dimension getPreferredSize() { public void setImage(BufferedImage bi) { image = bi; + x = y = x2 = y2 = 0; setComponentSize(); repaint(); } @@ -324,4 +470,31 @@ private void setComponentSize() { revalidate(); // signal parent/scrollpane } } + + public void setStartPoint(int x, int y) { + this.x = x; + this.y = y; + } + + public void setEndPoint(int x, int y) { + x2 = (x); + y2 = (y); + } + + public boolean hasDrawZone() { + int pw = Math.abs(x - x2); + int ph = Math.abs(y - y2); + if (pw != 0 && ph != 0) { + return true; + } + return false; + } + + public void drawZoneRect(Graphics g, int x, int y, int x2, int y2) { + int px = Math.min(x, x2); + int py = Math.min(y, y2); + int pw = Math.abs(x - x2); + int ph = Math.abs(y - y2); + g.drawRect(px, py, pw, ph); + } }