You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Processing(Java)中基于鼠标坐标绘制箭头:多次绘制位置异常问题排查

问题分析与解决方案

你的箭头绘制程序出现后续箭头位置错误的问题,主要出在三个核心细节上:PVector的原地修改特性、坐标变换未做隔离,以及鼠标起点的获取逻辑。让我一步步拆解并修复:


1. PVector的sub()方法会原地修改原对象

PVector的sub()、add()这类实例方法默认会直接修改调用它的PVector本身,而不是返回一个全新的向量。比如你在draw()里写的:

drawArrow(lineBase, arrowTip.sub(lineBase));

这行代码执行后,arrowTip已经被改成了相对lineBase的偏移量,而非原来的绝对坐标。后续保存vec[i].x=arrowTip.x时,存的已经是错误的相对坐标,直接导致重绘时位置混乱。

同样,drawSavedArrows()里的vector.sub(base[i])会修改全局的vector对象,让所有后续箭头复用被篡改过的向量。

修复方案:使用PVector.sub(a, b)静态方法,它会返回一个新的PVector,完全不影响原数据:

// 替换draw()中的调用
drawArrow(lineBase, PVector.sub(arrowTip, lineBase));

// 替换drawSavedArrows()中的调用
drawArrow(base[i], PVector.sub(vec[i], base[i]));

2. 坐标变换未用pushMatrix()/popMatrix()隔离

你的drawArrow()方法使用了translate()和rotate(),但没有在开头保存当前坐标状态,结尾恢复状态。这会导致后续所有绘制元素(包括其他箭头)都继承这个变换后的坐标系统,位置彻底错乱。

修复方案:用pushMatrix()和popMatrix()包裹坐标变换逻辑:

void drawArrow(PVector base, PVector vector) {
  strokeWeight(height / 50);
  fill(20, 85, 30, 180);
  stroke(20, 85, 30, 180);
  
  pushMatrix(); // 保存当前坐标系统状态
  translate(base.x, base.y); 
  line(0, 0, vector.x, vector.y); 
  rotate(vector.heading());
  int arrowSize = height / 20;
  translate(vector.mag() - arrowSize, 0); 
  triangle(0, arrowSize / 1.5, 0, -arrowSize / 1.5, arrowSize, 0);
  popMatrix(); // 恢复原始坐标系统,不影响后续绘制
}

3. 鼠标按下时的起点获取错误

你在mousePressed()里用了pmouseX/pmouseY,但右键按下时,pmouseX是按下前的鼠标位置,应该直接用mouseX/mouseY作为箭头起点:

// 替换mousePressed()中的起点赋值
lineBase.x = mouseX;
lineBase.y = mouseY;
base[i].x = mouseX;
base[i].y = mouseY;

修改后的完整代码

PVector arrowTip = new PVector(); 
PVector lineBase = new PVector(); 
PVector [] base = new PVector[100];
PVector [] vec = new PVector[100];
boolean drawing;
int flag=0;

void settings() {
  float hg=displayHeight/1.1;
  int wd=(int)hg*10/8;
  size(wd, (int)hg);
  drawing=false;
}

void draw() {
  background(255);
  // 绘制正在拖拽的箭头
  if (flag == 1) {
    arrowTip.x = mouseX;
    arrowTip.y = mouseY;
    drawArrow(lineBase, PVector.sub(arrowTip, lineBase));
  }
  // 重绘已保存的箭头
  drawSavedArrows();
}

void drawSavedArrows() {
  for (int i =0; i<base.length; i++) {
    if (vec[i]!=null && base[i]!=null) {
      drawArrow(base[i], PVector.sub(vec[i], base[i]));
    }
  }
}

void drawArrow(PVector base, PVector vector) {
  strokeWeight(height / 50);
  fill(20, 85, 30, 180);
  stroke(20, 85, 30, 180);
  
  pushMatrix();
  translate(base.x, base.y);
  line(0, 0, vector.x, vector.y);
  rotate(vector.heading());
  int arrowSize = height / 20;
  translate(vector.mag() - arrowSize, 0);
  triangle(0, arrowSize / 1.5, 0, -arrowSize / 1.5, arrowSize, 0);
  popMatrix();
}

void mousePressed() {
  if (mouseButton == RIGHT) 
  {
    lineBase.x = mouseX;
    lineBase.y = mouseY;
    for (int i =0; i<base.length; i++) {
      if (base[i]==null) {
        base[i] = new PVector(mouseX, mouseY);
        break;
      }
    }
    drawing=true;
  } else if(mouseButton == LEFT){
    for (int i=0; i<base.length; i++) {
      if (base[i]==null) {
        break;
      }
      base[i]=null;
      vec[i]=null;
    }
  }
}

void mouseDragged() {
  if (mouseButton == RIGHT) {
    flag = 1;
  }
}

void mouseReleased() {
  flag = 0;
  if (drawing) {
    for (int i =0; i<vec.length; i++) {
      if (vec[i]==null) {
        vec[i] = new PVector(mouseX, mouseY);
        break;
      }
    }
  }
  drawing=false;
}

额外优化说明

  • 移除了多余的全局变量vector、xx、yy,直接用PVector静态方法处理,减少出错点
  • 保存箭头尖端时直接使用mouseX/mouseY,不再依赖arrowTip,逻辑更简洁

修改后你就能正常绘制多个箭头,每个箭头的位置和方向都会正确显示了。

内容的提问来源于stack exchange,提问作者yoyo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 16:27:32