Processing 将鼠标daw限制为45度处理

Processing 将鼠标daw限制为45度处理,processing,Processing,如何以交互方式将绘制线约束为45度? 想象一下,在一个45度的下划线网格中,鼠标画的东西也被磁化了。也许在mousedown上决定了你的起始位置,然后你的Mouse.X和Mouse.Y位置只会在45度内从起始点开始更新 float dif = 10; float easing = 0.05; boolean current = false; boolean started = false; float rainbow, x, y; float colbase; PVector pos, prev

如何以交互方式将绘制线约束为45度? 想象一下,在一个45度的下划线网格中,鼠标画的东西也被磁化了。也许在mousedown上决定了你的起始位置,然后你的Mouse.X和Mouse.Y位置只会在45度内从起始点开始更新

float dif = 10;
float easing = 0.05;
boolean current = false;
boolean started = false;
float rainbow, x, y;
float colbase;
PVector pos, prev_pos, update_pos;
float step = 25;

void setup(){
  size(400, 400);
  background(100);
  colorMode(HSB);
}
 
void draw(){

  if (rainbow >= 255)  rainbow=0;  else  rainbow+=5;
  if (frameCount % dif == 0) {
   colbase = rainbow; 
  }
  if(mousePressed){

    update_pos();
      
        if(current){
          started =  true;//start drawing
          pos =      update_pos;
        }else{
          prev_pos = update_pos;
        }
       current = !current;
      
  }else{
      update_pos();
      started   = false;
      pos       = update_pos;
      prev_pos  = update_pos;
  }
 
  if(started){
      //style for lines
      strokeWeight(step);
      stroke(colbase,255,255);
      noFill();
      line(prev_pos.x, prev_pos.y, pos.x, pos.y);
   }
  
 }

PVector update_pos(){
  x = lerp(x, mouseX, easing);
  y = lerp(y, mouseY, easing);
  update_pos = new PVector(x, y);
  return update_pos;
  }

我想说我喜欢这个。而且,这个问题最终比我想象的要难回答得多

结果如下:

首先,我冒昧地重新组织了您的示例代码。我不知道你的经验有多丰富,也许我改变的一些事情是故意的,但在我看来,你的例子有很多奇怪的代码。下面是我所做更改的示例代码(请查看下一个代码块以获得答案,这一个更像是一个代码复查,以帮助您了解总体情况):

注意我如何更改了几个变量的名称。作为一般规则,你应该总是把你的变量命名为,好像维护你代码的人是一个知道你住在哪里的愤怒的摩托车手

现在来解决您的实际问题:

boolean isDrawing;
float rainbow, colbase, dif, easing, step, centerZone;
PVector pos, prev_pos, origin, quadrant;

void setup() {
  size(400, 400);
  background(100);
  colorMode(HSB); // clever!

  centerZone = 5; // determine how close to the original click you must be to change quadrant
  dif = 10;
  easing = 0.05;
  step = 25;

  origin = pos = prev_pos = new PVector();
}

void draw() {
  updatePosition();

  if (mousePressed) {
    if (!isDrawing) {
      // setting variables needed for drawing
      isDrawing = true;
      origin = pos = prev_pos = new PVector(mouseX, mouseY); // drawing should always start where the mouse currently is
    }
  } else {
    isDrawing = false;
  }

  if (isDrawing) {
    updateColor();
    strokeWeight(step);
    stroke(colbase, 255, 255);
    noFill();
    line(prev_pos.x, prev_pos.y, pos.x, pos.y);
  }
}

void updateColor() {
  if (rainbow >= 255) {
    rainbow=0;
  } else {
    rainbow+=5;
  }

  if (frameCount % dif == 0) {
    colbase = rainbow;
  }
}

void updatePosition() {
  float relativeX = pos.x - origin.x;
  float relativeY = pos.y - origin.y;
  float diffX = mouseX - origin.x;
  float diffY = mouseY - origin.y;
  float distance = abs(diffX) > abs(diffY) ? abs(diffX) : abs(diffY); // this is just inline if, the syntax being " condition ? return if true : return if false; "
  prev_pos = pos;
  
  // validating if the mouse is in the same quadrant as the pencil
  PVector mouseQuadrant = new PVector(diffX > 0 ? 1 : -1, diffY > 0 ? 1 : -1);
  
  // we can only change quadrant when near the center
  float distanceFromTheCenter = abs(relativeX) + abs(relativeY);
  if (quadrant == null || distanceFromTheCenter < centerZone) {
    quadrant = new PVector(diffX > 0 ? 1 : -1, diffY > 0 ? 1 : -1);
  }

  // if the mouse left it's quadrant, then draw toward the center until close enough to change direction
  // ^ is the XOR operator, which returns true only when one of the sides is different than the other (one true, one false)
  // if the quadrant info is positive and the diff coordinate is negative (or the other way around) we know the mouse has changed quadrant
  if (distanceFromTheCenter > centerZone && (relativeX > 0 ^ mouseQuadrant.x > 0 || relativeY > 0 ^ mouseQuadrant.y > 0)) {
    // going toward origin
    pos = new PVector(lerp(prev_pos.x, origin.x, easing), lerp(prev_pos.y, origin.y, easing));
  } else {
    // drawing normally
    pos = new PVector(lerp(prev_pos.x, origin.x + (distance * quadrant.x), easing), lerp(prev_pos.y, origin.y + (distance * quadrant.y), easing));
  }
}
这项检查的目的是要知道鼠标是否仍在与“铅笔”相同的象限内,我指的是我们正在绘制的点

但什么是“象限”?请记住,用户只能绘制45度的直线。这些线是相对于用户单击绘制的点定义的,我称之为“原点”:

这意味着屏幕总是分为4个不同的“象限”。为什么?因为我们可以画四个不同的方向。但我们不希望用户必须坚持这些精确的像素才能绘制,是吗?我们可以,但这不是algo的工作原理:它在页面上摆出铅笔姿势,然后跟着鼠标。因此,如果鼠标从原点向左上,铅笔将在45度X线的左上分支上绘制。每一条假想线都有自己的“屏幕部分”,它们控制铅笔有权在哪里画画,我称之为“象限”:

现在使用这个算法,我们可以强制铅笔在45度线上移动,但是如果鼠标从一个象限移动到另一个象限会发生什么呢?我发现铅笔应该遵循,但不违反“只画45度线”的规则,所以它必须在改变象限之前穿过中心:

这里没有什么大秘密。我们很容易找到我们想要应用的业务规则:

  • 当鼠标和铅笔位于同一象限时,按照鼠标的位置进行绘制(但仅在直线上)

  • 如果鼠标与铅笔位于不同的象限,则向中心绘制,然后正常向鼠标绘制

  • 这正是我们在这里所做的:

    if (mouse and pencil are in different quadrants) {
      // draw toward origin
    } else {
      // draw toward the mouse
    }
    
    然后。。。如果它这么简单,为什么要使用这种复杂的代码

    (distanceFromTheCenter > centerZone && (relativeX > 0 ^ mouseQuadrant.x > 0 || relativeY > 0 ^ mouseQuadrant.y > 0))
    
    嗯,真的,它可以写得更容易阅读,但它会更长。让我们分解它,看看为什么它是这样写的:

    我的操作逻辑如下:

  • 您可能知道,点(0,0)位于草图的左上侧。计算机科学中的大多数绘图都是这样计算坐标的

  • 象限相对于原点(用户单击此处开始绘制)存在

  • 每个象限中的相对坐标为正或负。如果它们位于原点右侧,则X为正。如果Y在屏幕中低于原点,则Y为正值:

  • 如果你按照我的逻辑,当鼠标和铅笔的相对坐标不是都是正的或者都是负的,这就意味着它们不在同一象限

  • 因此:

    distance from the center>center zone
    =>当我们离中心足够近时,我们可以让铅笔切换方向。如果铅笔不靠近中心,则无需计算其余部分

    relativeX>0^mouseQuadrant.x>0
    =>
    relativeX
    实际上就是
    pos.x-origin.x
    。这就是铅笔与原点的关系
    mouseQuadrant
    “知道”鼠标相对于原点的位置(只是解释为供以后使用的
    diffX
    diffY
    ,事实上我们完全可以使用
    diffX
    diffY
    ,因为我们只是比较它们是正数还是负数)

    如果XOR运算符如此简单,为什么要使用它?因此:

    relativeX > 0 ^ mouseQuadrant.x > 0
    // is the same thing than this pseudocode:
    if (relativeX sign is different than mousequadrant.x's sign)
    // and the same thing than this more elaborated code:
    !(relativeX > 0 && mouseQuadrant.x > 0) || !(relativeX < 0 && mouseQuadrant.x < 0)
    // or, in a better writing:
    (relativeX > 0 && mouseQuadrant.x < 0) || (relativeX < 0 && mouseQuadrant.x > 0)
    

    我希望这是有意义的!玩得开心

    非常感谢!我仍在努力理解您的代码,象限部分非常智能,但在视觉上有点难以理解。有没有一种更简单的方法,你可以通过按住shift键将其更改为-45度,或者+45度?@sixfeet我编辑了答案,并对这部分解决方案进行了更多解释,以便更容易理解,如果有不清楚的内容,请告诉我。
    (distanceFromTheCenter > centerZone && (relativeX > 0 ^ mouseQuadrant.x > 0 || relativeY > 0 ^ mouseQuadrant.y > 0))
    
    relativeX > 0 ^ mouseQuadrant.x > 0
    // is the same thing than this pseudocode:
    if (relativeX sign is different than mousequadrant.x's sign)
    // and the same thing than this more elaborated code:
    !(relativeX > 0 && mouseQuadrant.x > 0) || !(relativeX < 0 && mouseQuadrant.x < 0)
    // or, in a better writing:
    (relativeX > 0 && mouseQuadrant.x < 0) || (relativeX < 0 && mouseQuadrant.x > 0)
    
    (!(relativeX > 0 && mouseQuadrant.x > 0) || !(relativeX < 0 && mouseQuadrant.x < 0) || !(relativeY > 0 && mouseQuadrant.y > 0) || !(relativeY < 0 && mouseQuadrant.y < 0))