| | |
| | | private JLabel statusLabel; |
| | | private JLabel speedLabel; // 速度显示标签 |
| | | private JLabel areaNameLabel; |
| | | private JLabel drawingBoundaryLabel; // 正在绘制边界状态标签 |
| | | private JLabel navigationPreviewLabel; // 导航预览模式标签 |
| | | |
| | | // 边界警告相关 |
| | | private Timer boundaryWarningTimer; // 边界警告检查定时器 |
| | |
| | | } |
| | | // 关闭模式时不需要做任何操作,用户已经可以自由移动地图 |
| | | |
| | | // 更新工具提示 |
| | | // 更新图标显示(重绘以切换图标) |
| | | if (visualizationPanel != null) { |
| | | visualizationPanel.repaint(); |
| | | } |
| | |
| | | } |
| | | } |
| | | mapRenderer.setIdleTrailDurationSeconds(durationSeconds); |
| | | |
| | | // 应用边界距离显示设置和测量模式设置 |
| | | Setsys setsys = new Setsys(); |
| | | setsys.initializeFromProperties(); |
| | | mapRenderer.setBoundaryLengthVisible(setsys.isBoundaryLengthVisible()); |
| | | // 初始化测量模式 |
| | | boolean measurementEnabled = setsys.isMeasurementModeEnabled(); |
| | | mapRenderer.setMeasurementMode(measurementEnabled); |
| | | if (measurementEnabled) { |
| | | celiangmoshi.start(); |
| | | } else { |
| | | celiangmoshi.stop(); |
| | | } |
| | | } |
| | | |
| | | private void createHeaderPanel() { |
| | |
| | | |
| | | // 添加速度显示标签 |
| | | speedLabel = new JLabel(""); |
| | | speedLabel.setFont(new Font("微软雅黑", Font.PLAIN, 12)); |
| | | speedLabel.setForeground(Color.GRAY); |
| | | speedLabel.setVisible(false); // 默认隐藏 |
| | | speedLabel.setFont(new Font("微软雅黑", Font.PLAIN, 12)); |
| | | speedLabel.setForeground(Color.GRAY); |
| | | speedLabel.setVisible(false); // 默认隐藏 |
| | | |
| | | // 正在绘制边界状态标签 |
| | | drawingBoundaryLabel = new JLabel("正在绘制边界"); |
| | | drawingBoundaryLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14)); |
| | | drawingBoundaryLabel.setForeground(new Color(46, 139, 87)); |
| | | drawingBoundaryLabel.setVisible(false); // 默认隐藏 |
| | | |
| | | // 导航预览模式标签 |
| | | navigationPreviewLabel = new JLabel("当前导航预览模式"); |
| | | navigationPreviewLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14)); |
| | | navigationPreviewLabel.setForeground(new Color(46, 139, 87)); |
| | | navigationPreviewLabel.setVisible(false); // 默认隐藏 |
| | | |
| | | // 将状态与速度放在同一行,显示在地块名称下面一行 |
| | | JPanel statusRow = new JPanel(new FlowLayout(FlowLayout.LEFT, 8, 0)); |
| | | statusRow.setOpaque(false); |
| | | statusRow.add(statusLabel); |
| | | statusRow.add(drawingBoundaryLabel); |
| | | statusRow.add(navigationPreviewLabel); |
| | | statusRow.add(speedLabel); |
| | | |
| | | // 左对齐标签与状态行,确保它们在 BoxLayout 中靠左显示 |
| | |
| | | |
| | | // 可视化区域 - 使用MapRenderer进行绘制 |
| | | visualizationPanel = new JPanel() { |
| | | private ImageIcon gecaojiIcon = null; |
| | | private ImageIcon gecaojiIcon1 = null; // 默认图标 |
| | | private ImageIcon gecaojiIcon2 = null; // 以割草机为中心模式图标 |
| | | private static final int GECAOJI_ICON_X = 37; |
| | | private static final int GECAOJI_ICON_Y = 10; |
| | | private static final int GECAOJI_ICON_SIZE = 20; |
| | | |
| | | { |
| | | // 加载割草机图标,大小20x20像素 |
| | | gecaojiIcon = loadScaledIcon("image/gecaoji.png", GECAOJI_ICON_SIZE, GECAOJI_ICON_SIZE); |
| | | gecaojiIcon1 = loadScaledIcon("image/gecaojishijiao1.png", GECAOJI_ICON_SIZE, GECAOJI_ICON_SIZE); |
| | | gecaojiIcon2 = loadScaledIcon("image/gecaojishijiao2.png", GECAOJI_ICON_SIZE, GECAOJI_ICON_SIZE); |
| | | } |
| | | |
| | | /** |
| | |
| | | if (isMowerOutsideBoundary && warningIconVisible) { |
| | | // 绘制红色三角形警告图标(带叹号) |
| | | drawWarningIcon(g, GECAOJI_ICON_X, GECAOJI_ICON_Y, GECAOJI_ICON_SIZE); |
| | | } else if (gecaojiIcon != null) { |
| | | // 绘制正常的割草机图标 |
| | | // 水平方向与速度指示器对齐(x=37) |
| | | // 垂直方向与卫星状态图标对齐(y=10,速度指示器面板顶部边距10像素,使图标中心对齐) |
| | | g.drawImage(gecaojiIcon.getImage(), GECAOJI_ICON_X, GECAOJI_ICON_Y, null); |
| | | } else { |
| | | // 根据模式选择不同的图标 |
| | | ImageIcon iconToDraw = centerOnMowerMode ? gecaojiIcon2 : gecaojiIcon1; |
| | | if (iconToDraw != null) { |
| | | // 绘制割草机图标 |
| | | // 水平方向与速度指示器对齐(x=37) |
| | | // 垂直方向与卫星状态图标对齐(y=10,速度指示器面板顶部边距10像素,使图标中心对齐) |
| | | g.drawImage(iconToDraw.getImage(), GECAOJI_ICON_X, GECAOJI_ICON_Y, null); |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | if (parentWindow != null) { |
| | | // 使用 yaokong 包中的 RemoteControlDialog 实现 |
| | | remoteDialog = new yaokong.RemoteControlDialog(this, THEME_COLOR, speedLabel); |
| | | } else { |
| | | } else {/* */ |
| | | remoteDialog = new yaokong.RemoteControlDialog((JFrame) null, THEME_COLOR, speedLabel); |
| | | } |
| | | } |
| | |
| | | circleDialogMode = false; |
| | | hideCircleGuidancePanel(); |
| | | enterDrawingControlMode(); |
| | | |
| | | // 显示"正在绘制边界"提示 |
| | | if (drawingBoundaryLabel != null) { |
| | | drawingBoundaryLabel.setVisible(true); |
| | | } |
| | | |
| | | boolean enableCircleGuidance = drawingShape != null |
| | | && "circle".equalsIgnoreCase(drawingShape.trim()); |
| | |
| | | if (latest == null) { |
| | | return false; |
| | | } |
| | | return lastCapturedCoordinate == null || latest != lastCapturedCoordinate; |
| | | |
| | | // 检查是否有新的坐标(与上次采集的不同) |
| | | if (lastCapturedCoordinate != null && latest == lastCapturedCoordinate) { |
| | | return false; |
| | | } |
| | | |
| | | // 检查定位状态是否为4(固定解) |
| | | // 当选择割草机绘制圆形障碍物时,需要检查设备编号和定位状态 |
| | | Device device = Device.getGecaoji(); |
| | | if (device == null) { |
| | | return false; |
| | | } |
| | | |
| | | String positioningStatus = device.getPositioningStatus(); |
| | | if (positioningStatus == null || !"4".equals(positioningStatus.trim())) { |
| | | return false; |
| | | } |
| | | |
| | | // 检查设备编号是否匹配割草机编号 |
| | | String mowerId = Setsys.getPropertyValue("mowerId"); |
| | | String deviceId = device.getMowerNumber(); |
| | | if (mowerId != null && !mowerId.trim().isEmpty()) { |
| | | if (deviceId == null || !mowerId.trim().equals(deviceId.trim())) { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | return true; |
| | | } |
| | | |
| | | private void applyCirclePrimaryButtonState(boolean enabled) { |
| | |
| | | activeBoundaryMode = BoundaryCaptureMode.NONE; |
| | | } |
| | | endDrawingCallback = null; |
| | | |
| | | // 隐藏"正在绘制边界"提示 |
| | | if (drawingBoundaryLabel != null) { |
| | | drawingBoundaryLabel.setVisible(false); |
| | | } |
| | | |
| | | visualizationPanel.revalidate(); |
| | | visualizationPanel.repaint(); |
| | | setHandheldMowerIconActive(false); |
| | |
| | | String obstacles, |
| | | String plannedPath, |
| | | Runnable returnAction) { |
| | | if (mapRenderer == null || !isMeaningfulValue(plannedPath)) { |
| | | if (mapRenderer == null) { |
| | | return false; |
| | | } |
| | | // 允许没有路径的预览(例如障碍物预览),只要有返回回调即可 |
| | | if (!isMeaningfulValue(plannedPath) && returnAction == null) { |
| | | return false; |
| | | } |
| | | |
| | |
| | | |
| | | mapRenderer.setCurrentBoundary(boundary, landNumber, landName); |
| | | mapRenderer.setCurrentObstacles(obstacles, landNumber); |
| | | mapRenderer.setCurrentPlannedPath(plannedPath); |
| | | // 只有在有路径时才设置路径 |
| | | if (isMeaningfulValue(plannedPath)) { |
| | | mapRenderer.setCurrentPlannedPath(plannedPath); |
| | | } else { |
| | | mapRenderer.setCurrentPlannedPath(null); |
| | | } |
| | | mapRenderer.clearHandheldBoundaryPreview(); |
| | | mapRenderer.setBoundaryPointSizeScale(1.0d); |
| | | mapRenderer.setBoundaryPointsVisible(isMeaningfulValue(boundary)); |
| | | // 启用障碍物边界点显示 |
| | | mapRenderer.setObstaclePointsVisible(isMeaningfulValue(obstacles)); |
| | | |
| | | String displayName = isMeaningfulValue(landName) ? landName : landNumber; |
| | | updateCurrentAreaName(displayName); |
| | |
| | | return mapRenderer; |
| | | } |
| | | |
| | | /** |
| | | * 获取控制面板(用于导航预览时替换按钮) |
| | | * @return 控制面板 |
| | | */ |
| | | public JPanel getControlPanel() { |
| | | return controlPanel; |
| | | } |
| | | |
| | | /** |
| | | * 获取开始按钮(用于导航预览时隐藏) |
| | | * @return 开始按钮 |
| | | */ |
| | | public JButton getStartButton() { |
| | | return startBtn; |
| | | } |
| | | |
| | | /** |
| | | * 获取结束按钮(用于导航预览时隐藏) |
| | | * @return 结束按钮 |
| | | */ |
| | | public JButton getStopButton() { |
| | | return stopBtn; |
| | | } |
| | | |
| | | /** |
| | | * 设置导航预览模式标签的显示状态 |
| | | * @param visible 是否显示 |
| | | */ |
| | | public void setNavigationPreviewLabelVisible(boolean visible) { |
| | | if (navigationPreviewLabel != null) { |
| | | navigationPreviewLabel.setVisible(visible); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 获取可视化面板实例 |
| | | */ |
| | | public JPanel getVisualizationPanel() { |
| | | return visualizationPanel; |
| | | } |
| | | |
| | | /** |
| | | * 获取主内容面板实例(用于添加浮动按钮) |
| | | */ |
| | | public JPanel getMainContentPanel() { |
| | | return mainContentPanel; |
| | | } |
| | | |
| | | |
| | | public void updateCurrentAreaName(String areaName) { |
| | | if (areaNameLabel == null) { |
| | | return; |