package home; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import javax.swing.BorderFactory; import javax.swing.JPanel; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; // ¿ÉÊÓ»¯Ãæ°åÀà class VisualizationPanel extends JPanel { /** * */ private static final long serialVersionUID = 1L; private int distance = 0; private int angle = 0; private AOAFollowSystem parentFrame; private String anchorid = "Anchor"; private String tagid = "Tag"; private double scaleFactor = 1.0; // Ëõ·ÅÒò×Ó private static final double MIN_SCALE = 0.2; // ×îСËõ·Å±¶Êý private static final double MAX_SCALE = 5.0; // ×î´óËõ·Å±¶Êý // ʹÓÃÖ§³ÖÖÐÎĵÄ×ÖÌå private Font boldFont = new Font("Microsoft YaHei", Font.BOLD, 14); private Font normalFont = new Font("Microsoft YaHei", Font.PLAIN, 12); private Font titleFont = new Font("Microsoft YaHei", Font.BOLD, 12); public VisualizationPanel(AOAFollowSystem parentFrame) { this.parentFrame = parentFrame; setPreferredSize(new Dimension(400, 400)); setBorder(BorderFactory.createTitledBorder(parentFrame.getString("visualization"))); // Ìí¼ÓÊó±ê¹öÂÖ¼àÌýÆ÷ addMouseWheelListener(new MouseWheelListener() { @Override public void mouseWheelMoved(MouseWheelEvent e) { int notches = e.getWheelRotation(); if (notches < 0) { // ÏòÉϹö¶¯£¬·Å´ó scaleFactor = Math.min(scaleFactor * 1.1, MAX_SCALE); } else { // ÏòϹö¶¯£¬ËõС scaleFactor = Math.max(scaleFactor / 1.1, MIN_SCALE); } repaint(); } }); } public void updatePosition(int distance, int angle) { // ÓÅ»¯£ºÖ»ÓÐÊý¾Ý±ä»¯Ê±²ÅÖØ»æ if (this.distance != distance || this.angle != angle) { this.distance = distance; // ½«½Ç¶È·¶Î§×ª»»Îª-180µ½180¶È£¬ÕýÏ·½Îª0¶È this.angle = normalizeAngle(angle); repaint(); } } // ½Ç¶È¹éÒ»»¯·½·¨£¬½«½Ç¶Èת»»Îª-180µ½180¶È·¶Î§£¬ÕýÏ·½Îª0¶È private int normalizeAngle(int angle) { // Ê×ÏȽ«½Ç¶Èת»»Îª0-360¶È·¶Î§ angle = angle % 360; if (angle < 0) { angle += 360; } // ½«0-360¶Èת»»Îª-180µ½180¶È£¬ÕýÏ·½Îª0¶È // 0¶È¶ÔÓ¦ÕýÏ·½£¬90¶È¶ÔÓ¦Õý×ó·½£¬180/-180¶È¶ÔÓ¦ÕýÉÏ·½£¬-90¶È¶ÔÓ¦ÕýÓÒ·½ int normalizedAngle = angle - 180; if (normalizedAngle > 180) { normalizedAngle -= 360; } else if (normalizedAngle <= -180) { normalizedAngle += 360; } return normalizedAngle; } public void setAnchorId(String anchorid) { this.anchorid = anchorid; } public void setTagId(String tagid) { this.tagid = tagid; } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g; g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // È·±£Ê¹ÓÃÖ§³ÖÖÐÎĵÄ×ÖÌå g2d.setFont(normalFont); int centerX = getWidth() / 2; int centerY = getHeight()/ 2 - 30; int maxRadius = (int) (Math.min(centerX, centerY) * scaleFactor - 20); // ÉèÖñ³¾°ÑÕÉ« g2d.setColor(new Color(240, 240, 240)); g2d.fillRect(0, 0, getWidth(), getHeight()); // »æÖÆ×ø±êÖá g2d.setColor(Color.LIGHT_GRAY); g2d.drawLine(centerX, 0, centerX, getHeight()); g2d.drawLine(0, centerY, getWidth(), centerY); // »æÖƽǶȿ̶ÈÏß (-180¡ã µ½ 180¡ã) g2d.setColor(new Color(150, 150, 150)); for (int i = -180; i <= 180; i += 30) { // ת»»Îª»¡¶È£¬ÕýÏ·½Îª0¶È double rad = Math.toRadians(i); int x1 = centerX + (int) (maxRadius * Math.sin(rad)); int y1 = centerY - (int) (maxRadius * Math.cos(rad)); g2d.setColor(new Color(100, 100, 100)); g2d.drawLine(centerX, centerY, x1, y1); // »æÖƽǶȱêÇ© int labelX = centerX + (int) ((maxRadius + 15) * Math.sin(rad)); int labelY = centerY - (int) ((maxRadius + 15) * Math.cos(rad)); g2d.setColor(Color.blue); g2d.drawString(i + "¡ã", labelX - 10, labelY + 5); } // »æÖƾàÀëԲȦºÍ±êÇ© g2d.setColor(new Color(100, 100, 100)); for (int i = 1; i <= 5; i++) { int radius = maxRadius * i / 5; g2d.drawOval(centerX - radius, centerY - radius, radius * 2, radius * 2); // Ð޸ģº½«¾àÀë±êÇ©ÏÔʾÔÚԲȦÕýÄÏ·½Öмä String distanceLabel = (int)(i * 200 / scaleFactor) + "cm"; int labelWidth = g2d.getFontMetrics().stringWidth(distanceLabel); g2d.drawString(distanceLabel, centerX - labelWidth / 2, centerY + radius + 15); } // »æÖÆAµã£¨Ãªµã£© g2d.setColor(Color.BLACK); g2d.fillOval(centerX - 5, centerY - 5, 10, 10); // AµãÕýÉÏ·½ÏÔʾÉ豸±àºÅ g2d.setFont(titleFont); g2d.drawString(anchorid, centerX - g2d.getFontMetrics().stringWidth(anchorid)/2, centerY - 15); g2d.setFont(normalFont); // »æÖÆBµã£¨±êÇ©µã£© if (distance > 0) { // ¸ù¾Ý¾àÀë¼ÆËãËõ·Å±ÈÀý£¨×î´ó1000ÀåÃ×£© double scaledDistance = Math.min(distance, 1000) * maxRadius / 1000.0; double rad = Math.toRadians(angle); int bX = centerX + (int) (scaledDistance * Math.sin(rad)); int bY = centerY - (int) (scaledDistance * Math.cos(rad)); // »æÖÆÁ¬½ÓÏß g2d.setColor(new Color(0, 100, 200, 150)); g2d.drawLine(centerX, centerY, bX, bY); // BµãÕýÏ·½ÏÔʾ¾àÀëºÍ½Ç¶ÈÐÅÏ¢ String distanceText = distance + "cm"; String angleText = angle + "¡ã"; // ÉèÖüӴÖ×ÖÌåºÍ¼Ó´ó×ֺŠg2d.setFont(boldFont); g2d.setColor(Color.RED); // ¼ÆËãÎı¾Î»Öã¨BµãÕýÏ·½£© int textY = bY + 25; g2d.drawString(distanceText, bX - g2d.getFontMetrics().stringWidth(distanceText)/2, textY); g2d.drawString(angleText, bX - g2d.getFontMetrics().stringWidth(angleText)/2, textY + 20); // »Ö¸´Ô­Ê¼×ÖÌå g2d.setFont(normalFont); // ÔÚÃæ°åµ×²¿ÏÔʾ¾àÀëºÍ½Ç¶ÈÐÅÏ¢ - ʵʱ»ñÈ¡×Ö·û´®£¬²»Ê¹Óûº´æ g2d.setFont(boldFont); // Ö±½Ó´Ó¸¸¿ò¼Ü»ñÈ¡µ±Ç°ÓïÑÔµÄ×Ö·û´® g2d.drawString(parentFrame.getString("distance") + distance + "cm", 10, 40); g2d.drawString(parentFrame.getString("angle") + angle + "¡ã", 10, 70); g2d.setFont(normalFont); g2d.setColor(Color.BLUE); g2d.fillOval(bX - 5, bY - 5, 10, 10); // BµãÕýÉÏ·½ÏÔʾÉ豸±àºÅ g2d.setFont(titleFont); g2d.drawString(tagid, bX - g2d.getFontMetrics().stringWidth(tagid)/2, bY - 15); g2d.setFont(normalFont); } // ÏÔʾµ±Ç°Ëõ·Å±ÈÀý g2d.setColor(Color.DARK_GRAY); g2d.drawString(String.format("Ëõ·Å: %.1fx", scaleFactor), getWidth() - 80, 20); } public void updateLanguage() { setBorder(BorderFactory.createTitledBorder(parentFrame.getString("visualization"))); // ÒÆ³ý×Ö·û´®»º´æ£¬¸ÄΪÔÚpaintComponentÖÐʵʱ»ñÈ¡ repaint(); } }