package gecaoji;
|
|
import java.awt.Color;
|
import java.awt.Graphics2D;
|
import java.awt.Image;
|
import java.awt.geom.AffineTransform;
|
import java.awt.geom.Ellipse2D;
|
import java.awt.geom.Point2D;
|
|
import javax.swing.ImageIcon;
|
|
/** Mower rendering helper. */
|
public class Gecaoji {
|
private static final double ICON_PIXEL_SIZE = 48.0;
|
private static final double MIN_SCALE = 1e-6;
|
private static final Color FALLBACK_FILL = new Color(0, 150, 0);
|
|
private final Image mowerIcon;
|
private final Ellipse2D.Double fallbackShape = new Ellipse2D.Double();
|
private Point2D.Double position = new Point2D.Double();
|
private boolean positionValid;
|
|
public Gecaoji() {
|
mowerIcon = loadIcon();
|
refreshFromDevice();
|
}
|
|
private Image loadIcon() {
|
try {
|
ImageIcon icon = new ImageIcon("image/mow.png");
|
if (icon.getIconWidth() <= 0 || icon.getIconHeight() <= 0) {
|
return null;
|
}
|
return icon.getImage();
|
} catch (Exception ex) {
|
System.err.println("Unable to load mower icon: " + ex.getMessage());
|
return null;
|
}
|
}
|
|
public void refreshFromDevice() {
|
Device device = Device.getGecaoji();
|
if (device == null) {
|
positionValid = false;
|
return;
|
}
|
|
double x = parseCoordinate(device.getRealtimeX());
|
double y = parseCoordinate(device.getRealtimeY());
|
if (Double.isNaN(x) || Double.isNaN(y)) {
|
positionValid = false;
|
return;
|
}
|
|
ensurePosition();
|
position.x = x;
|
position.y = y;
|
positionValid = true;
|
}
|
|
private void ensurePosition() {
|
if (position == null) {
|
position = new Point2D.Double();
|
}
|
}
|
|
private double parseCoordinate(String value) {
|
if (value == null) {
|
return Double.NaN;
|
}
|
String trimmed = value.trim();
|
if (trimmed.isEmpty() || "-1".equals(trimmed)) {
|
return Double.NaN;
|
}
|
try {
|
return Double.parseDouble(trimmed);
|
} catch (NumberFormatException ex) {
|
return Double.NaN;
|
}
|
}
|
|
public void draw(Graphics2D g2d, double scale) {
|
if (!positionValid) {
|
return;
|
}
|
|
double worldSize = ICON_PIXEL_SIZE / Math.max(scale, MIN_SCALE);
|
if (mowerIcon != null && mowerIcon.getWidth(null) > 0 && mowerIcon.getHeight(null) > 0) {
|
drawIcon(g2d, worldSize);
|
} else {
|
drawFallback(g2d, worldSize);
|
}
|
}
|
|
private void drawIcon(Graphics2D g2d, double worldSize) {
|
double iconWidth = mowerIcon.getWidth(null);
|
double iconHeight = mowerIcon.getHeight(null);
|
double maxSide = Math.max(iconWidth, iconHeight);
|
double scaleFactor = worldSize / Math.max(maxSide, MIN_SCALE);
|
|
AffineTransform original = g2d.getTransform();
|
AffineTransform transformed = new AffineTransform(original);
|
transformed.translate(position.x, position.y);
|
transformed.scale(scaleFactor, scaleFactor);
|
transformed.translate(-iconWidth / 2.0, -iconHeight / 2.0);
|
g2d.setTransform(transformed);
|
g2d.drawImage(mowerIcon, 0, 0, null);
|
g2d.setTransform(original);
|
}
|
|
private void drawFallback(Graphics2D g2d, double worldSize) {
|
double radius = worldSize / 2.0;
|
ensurePosition();
|
fallbackShape.setFrame(position.x - radius, position.y - radius, worldSize, worldSize);
|
|
Color original = g2d.getColor();
|
g2d.setColor(FALLBACK_FILL);
|
g2d.fill(fallbackShape);
|
g2d.setColor(Color.WHITE);
|
g2d.draw(fallbackShape);
|
g2d.setColor(original);
|
}
|
|
public boolean hasValidPosition() {
|
return positionValid;
|
}
|
|
public Point2D.Double getPosition() {
|
if (!positionValid) {
|
return null;
|
}
|
ensurePosition();
|
return new Point2D.Double(position.x, position.y);
|
}
|
|
public double getWorldRadius(double scale) {
|
if (!positionValid) {
|
return Double.NaN;
|
}
|
double worldSize = ICON_PIXEL_SIZE / Math.max(scale, MIN_SCALE);
|
return worldSize / 2.0;
|
}
|
}
|