沿着PShape轮廓走并将其分开? [英] Walk along PShape contours and divide them?

查看:84
本文介绍了沿着PShape轮廓走并将其分开?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一种适当的方法来沿PShape轮廓查找点。



我的目标是沿给定点到另一个点的两个距离(正确的距离和左边的距离)生成相同数量的点,然后在精确的位置标记一个点两点之间的中心,这两个点的每一侧都是相同的步数。 (我不确定我是否容易理解,并且我无法附加img,所以我附加了处理代码。)



我想完成此操作是按照路径计算起点和终点之间的确切距离。也许我错了。



对此问题的任何帮助都将非常受欢迎。

  PGraphics g; 
PVector []值=新的PVector [7];

void setup(){
size(1024,768,P3D);
fillVal();
smooth();
}

void draw(){
background(0);
drawSiluette(g);
}

void fillVal(){
values [0] = new PVector(336.0,272.0,0.0);
values [1] =新的PVector(305.0,428.0,0.0);
values [2] =新的PVector(489.0,516.0,0.0);
values [3] =新的PVector(639.0,400.0,0.0);
values [4] =新的PVector(565.0,283.0,0.0);
values [5] =新的PVector(469.0,227.0,0.0);
values [6] =新的PVector(403.0,216.0,0.0);
}


void drawSiluette(PGraphics _s){
_s = createGraphics(width,height);
pushMatrix();
_s.beginDraw();
_s.noFill();
_s.strokeWeight(3);
_s.stroke(255);
_s.beginShape();
for(int i = 0; i< values.length; i ++){
if(i == 0 || i == values.length-1){
for(int它= 0;它< 2; it ++)
_s.curveVertex(values [0] .x,values [0] .y);
} else
_s.curveVertex(values [i] .x,values [i] .y);
}
_s.endShape(CLOSE);
popMatrix();
_s.endDraw();
image(_s,0,0);


//起点和终点
pushMatrix();
noStroke();
fill(255,0,0);
ellipseMode(CENTER);
ellipse(values [0] .x,values [0] .y,10,10);
ellipse(values [int(values.length / 2)]。x,values [int(values.length / 2)]。y,10,10);
popMatrix();
}


解决方案

问题尚不清楚。


沿从给定点
到另一个点的两个距离生成相同数量的点


您可以简单地在两个点之间线性插值(简称lerp)。
此功能内置于



请注意,插值是线性的。对于曲线,您可能需要查看
更高阶的插值函数,例如二次方或三次方。





,这是Hermite曲线上的基本处理演示插值点:

  float百分比= 0; 
PVector P0 =新的PVector(10,90); // 1st控件pt
PVector T0 =新的PVector(300,200); // 1st锚点-注意!锚点相对于控件
PVector P1 =新的PVector(400,90); // 2第二个控件pt
PVector T1 =新的PVector(-100,400); // 2第二个锚点pt
PVector [] points = {P0,T0,P1,T1};
PVector pointAtPercent;

void setup(){
size(500,500);
reset();
}

void reset(){
P1.x = 200 + random(200); //随机分配一个小位
T1.x = random(- 100,100);
%= 0;
背景(255);
loop();
}
void draw(){
pointAtPercent = hermite(percent,points); //计算点

//在屏幕上渲染
椭圆( pointAtPercent.x,pointAtPercent.y,10,10);

//更新沿曲线的遍历百分比
percent + = .015;

//如果已绘制曲线,则停止绘制
if(percent> = 1)noLoop();
}

void mousePressed(){
reset();
}

PVector hermite(float t,PVector [] points){
PVector result = new PVector();
result.x =(2 * pow(t,3)-3 * t * t + 1)* points [0] .x +
(pow(t,3)-2 * t * t + t)* points [1] .x +
(-2 * pow(t,3)+ 3 * t * t)* points [2] .x +
(pow(t,3 )-t * t)* points [3] .x;
result.y =(2 * pow(t,3)-3 * t * t + 1)* points [0] .y +
(pow(t,3)-2 * t * t + t)* points [1] .y +
(-2 * pow(t,3)+ 3 * t * t)* points [2] .y +
(pow(t,3 )-t * t)*点[3] .y;
的返回结果;
}

目前尚不清楚您打算在点之间插值的精确程度,但希望以上概念应该可以帮助您实现目标。


I’m looking for a proper way of finding points along a PShape contour.

My goal is to generate the same number of points along the two distances from a given point to another (right distance and left distance), then mark a point in the exact center between the the two points that are the same step number on each side. (I’m not sure if I’m being easily understandable, and I cannot attach img already, so I attach processing code).

I imagine that the first step for getting it done is to calculate the exact distance between the start and end points, following the path. Maybe I’m wrong.

Any help on this matter would be very very welcome.

PGraphics g ;
PVector[] values = new PVector[7];

void setup(){
  size(1024,768,P3D);
  fillVal();
  smooth();
}

void draw(){
  background(0);
  drawSiluette(g);
}

void fillVal(){
  values[0]=new PVector ( 336.0, 272.0, 0.0 );
  values[1]=new PVector ( 305.0, 428.0, 0.0 );
  values[2]=new PVector ( 489.0, 516.0, 0.0 );
  values[3]=new PVector ( 639.0, 400.0, 0.0);
  values[4]=new PVector ( 565.0, 283.0, 0.0 );
  values[5]=new PVector ( 469.0, 227.0, 0.0 );
  values[6]=new PVector ( 403.0, 216.0, 0.0 );
}


void drawSiluette(PGraphics _s){
  _s = createGraphics(width,height);
  pushMatrix();
  _s.beginDraw();
  _s.noFill();
  _s.strokeWeight(3);
  _s.stroke(255);
  _s.beginShape();  
  for(int i = 0; i <values.length;i++){
    if(i==0 || i==values.length-1){
      for(int it = 0; it<2;it++)
         _s.curveVertex(values[0].x,values[0].y);
    }else   
        _s.curveVertex(values[i].x,values[i].y);
  }
  _s.endShape(CLOSE);
  popMatrix();
  _s.endDraw();
  image(_s,0,0);


  //start and end points
  pushMatrix();
  noStroke();
  fill(255,0,0);
  ellipseMode(CENTER);
  ellipse(values[0].x,values[0].y,10,10);
  ellipse(values[int(values.length/2)].x,values[int(values.length/2)].y,10,10);
  popMatrix();
}

解决方案

The question is a little unclear. To

generate the same number of points along the two distances from a given point to another

you can simply linearly interpolate between two points (lerp for short). This functionality is built into the PVector's lerp() function.

The function takes three parameters:

  1. the start point
  2. the end point
  3. a normalised value, which is a value between 0.0 and 1.0

You can think of the normalised value as a percentage:

  • 0.0 = 0%
  • 0.25 = 25%
  • 1.0 = 100%
  • etc.

Here's a basic example demonstration interpolation between two points with a given number of points in between:

PVector from = new PVector(100,100);
PVector to   = new PVector(300,300);

int numPoints = 10;

void setup(){
  size(400,400);
  fill(0);
}
void draw(){
  background(255);

  for(int i = 0; i <= numPoints; i++){
    //compute interpolation amount = a number from 0.0 and 1.0 , where 0 = 0% along the line and 1.0 = 100 % along the line (0.5 = 50%, etc.)
    float interpolationAmount = (float)i / numPoints;
    //float interpolationAmount = map(i,0,numPoints,0.0,1.0);

    //linearly interpolate point based on the interpolation amount
    PVector interpolatedPoint = PVector.lerp(from,to,interpolationAmount);
    //render the point on screen
    ellipse(interpolatedPoint.x,interpolatedPoint.y,10,10);
  }
  text("numPoints: " + numPoints,10,15);
}

void mouseDragged(){
  if(keyPressed) {
    to.set(mouseX,mouseY);
  }else{
    from.set(mouseX,mouseY);
  }
}

void keyPressed(){
  if(keyCode == UP)   numPoints++;
  if(keyCode == DOWN && numPoints > 0) numPoints--;
}

You can run this as a demo bellow:

var from,to;

var numPoints = 10;

function setup(){
  createCanvas(400,400);
  fill(0);
  
  from = createVector(100,100);
  to   = createVector(300,300);
}
function draw(){
  background(255);
  
  for(var i = 0; i <= numPoints; i++){
    //compute interpolation amount = a number from 0.0 and 1.0 , where 0 = 0% along the line and 1.0 = 100 % along the line (0.5 = 50%, etc.)
    //var interpolationAmount = (float)i / numPoints;
    var interpolationAmount = map(i,0,numPoints,0.0,1.0);
    
    //linearly interpolate point based on the interpolation amount
    var interpolatedPoint = p5.Vector.lerp(from,to,interpolationAmount);//PVector.lerp(from,to,interpolationAmount);
    //render the point on screen
    ellipse(interpolatedPoint.x,interpolatedPoint.y,10,10);
  }
  text("usage:\nclick & drag to move start point\nhold a key pressed while clicking and drag to move end point\nuse LEFT/RIGHT arrow to change number of points: " + numPoints,10,15);
}

function mouseDragged(){
  if(keyIsPressed) {
    to.set(mouseX,mouseY);
  }else{
    from.set(mouseX,mouseY);
  }
}

function keyPressed(){
  if(keyCode == LEFT_ARROW)   numPoints++;
  if(keyCode == RIGHT_ARROW && numPoints > 0) numPoints--;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.4/p5.min.js"></script>

The functionality could be encapsulated into a reusable function:

void drawPointsInbetween(PVector from,PVector to,int numPoints){
  for(int i = 0; i <= numPoints; i++){
    //compute interpolation amount = a number from 0.0 and 1.0 , where 0 = 0% along the line and 1.0 = 100 % along the line (0.5 = 50%, etc.)
    float interpolationAmount = (float)i / numPoints;
    //float interpolationAmount = map(i,0,numPoints,0.0,1.0);

    //linearly interpolate point based on the interpolation amount
    PVector interpolatedPoint = PVector.lerp(from,to,interpolationAmount);
    //render the point on screen
    ellipse(interpolatedPoint.x,interpolatedPoint.y,10,10);
  }
}

Back to your code, one thing that sticks out, although it's not related your main question is the fact that you're creating a new PGraphics instance multiple times per second. You probably don't want to do that. Currently, you should be able to draw straight into Processing with no need for PGraphics.

PVector[] values = new PVector[7];

void setup(){
  size(1024,768,P3D);
  fillVal();
  smooth();
}

void draw(){
  background(0);
  drawSiluette(g);
}

void fillVal(){
  values[0]=new PVector ( 336.0, 272.0, 0.0 );
  values[1]=new PVector ( 305.0, 428.0, 0.0 );
  values[2]=new PVector ( 489.0, 516.0, 0.0 );
  values[3]=new PVector ( 639.0, 400.0, 0.0);
  values[4]=new PVector ( 565.0, 283.0, 0.0 );
  values[5]=new PVector ( 469.0, 227.0, 0.0 );
  values[6]=new PVector ( 403.0, 216.0, 0.0 );
}


void drawSiluette(PGraphics _s){
  //_s = createGraphics(width,height);
  pushMatrix();
  //_s.beginDraw();
  noFill();
  strokeWeight(3);
  stroke(255);
  beginShape();  
  for(int i = 0; i <values.length;i++){
    if(i==0 || i==values.length-1){
      for(int it = 0; it<2;it++)
         curveVertex(values[0].x,values[0].y);
    }else   
        curveVertex(values[i].x,values[i].y);
  }
  endShape(CLOSE);
  popMatrix();


  //start and end points
  pushMatrix();
  noStroke();
  fill(255,0,0);
  ellipseMode(CENTER);
  ellipse(values[0].x,values[0].y,10,10);
  ellipse(values[int(values.length/2)].x,values[int(values.length/2)].y,10,10);
  popMatrix();
}

Adding the points in between function would be as simple as this:

PVector[] values = new PVector[7];

int numPoints = 10;

void setup(){
  size(1024,768,P3D);
  fillVal();
  smooth();
}

void draw(){
  background(0);
  drawSiluette(g);
}

void fillVal(){
  values[0]=new PVector ( 336.0, 272.0, 0.0 );
  values[1]=new PVector ( 305.0, 428.0, 0.0 );
  values[2]=new PVector ( 489.0, 516.0, 0.0 );
  values[3]=new PVector ( 639.0, 400.0, 0.0);
  values[4]=new PVector ( 565.0, 283.0, 0.0 );
  values[5]=new PVector ( 469.0, 227.0, 0.0 );
  values[6]=new PVector ( 403.0, 216.0, 0.0 );
}


void drawSiluette(PGraphics _s){
  //_s = createGraphics(width,height);
  pushMatrix();
  //_s.beginDraw();
  noFill();
  strokeWeight(3);
  stroke(255);
  beginShape();  
  for(int i = 0; i <values.length;i++){
    if(i==0 || i==values.length-1){
      for(int it = 0; it<2;it++)
         curveVertex(values[0].x,values[0].y);
    }else   
        curveVertex(values[i].x,values[i].y);
  }
  endShape(CLOSE);
  popMatrix();


  //start and end points
  pushMatrix();
  noStroke();
  fill(255,0,0);
  ellipseMode(CENTER);
  ellipse(values[0].x,values[0].y,10,10);
  ellipse(values[int(values.length/2)].x,values[int(values.length/2)].y,10,10);
  popMatrix();

  //draw inbetween points
  for(int i = 1 ;  i < values.length; i++){
    drawPointsInbetween(values[i-1],values[i],numPoints);
  }
  //draw last to first
  drawPointsInbetween(values[values.length-1],values[0],numPoints);
}
void drawPointsInbetween(PVector from,PVector to,int numPoints){
  for(int i = 0; i <= numPoints; i++){
    //compute interpolation amount = a number from 0.0 and 1.0 , where 0 = 0% along the line and 1.0 = 100 % along the line (0.5 = 50%, etc.)
    float interpolationAmount = (float)i / numPoints;
    //float interpolationAmount = map(i,0,numPoints,0.0,1.0);

    //linearly interpolate point based on the interpolation amount
    PVector interpolatedPoint = PVector.lerp(from,to,interpolationAmount);
    //render the point on screen
    ellipse(interpolatedPoint.x,interpolatedPoint.y,10,10);
  }
}

Here's a preview:

Notice that the interpolation is linear. For curves you might want to look at higher order interpolation functions such as quadratic or cubic.

Hermite curves are an example of cubic curve.

Here's a basic the formula:

and here's a basic Processing demo interpolating points on a Hermite curve:

float percent = 0;
PVector P0 = new PVector(10,90);//1st control pt
PVector T0 = new PVector(300,200);//1st anchor pt - NOTE! The anchors are relative to the controls
PVector P1 = new PVector(400,90);//2nd control pt
PVector T1 = new PVector(-100,400);//2nd anchor pt
PVector[] points = {P0,T0,P1,T1};
PVector pointAtPercent;

void setup(){
  size(500,500);
  reset();
}

void reset(){
    P1.x = 200 + random(200);//randomize a wee bit
    T1.x = random(-100,100);
    percent = 0;
    background(255);
    loop();
}
void draw() {
    pointAtPercent = hermite(percent, points);//compute point

    //render on screen
    ellipse(pointAtPercent.x,pointAtPercent.y,10,10);

    //update percentage of traversal along curve
    percent += .015;

    //if the curve has been drawn, stop drawing
    if(percent >= 1) noLoop();
}

void mousePressed(){
  reset();
}

PVector hermite(float t,PVector[] points){
    PVector result = new PVector();
    result.x = (2 * pow(t,3) - 3 * t * t + 1) * points[0].x+
                (pow(t,3) - 2 * t * t + t) * points[1].x + 
                (- 2 * pow(t,3) + 3*t*t) * points[2].x +
                ( pow(t,3) - t*t) * points[3].x;
    result.y = (2 * pow(t,3) - 3 * t * t + 1) * points[0].y+
                (pow(t,3) - 2 * t * t + t) * points[1].y + 
                (- 2 * pow(t,3) + 3*t*t) * points[2].y +
                ( pow(t,3) - t*t) * points[3].y;
    return result;
}

It's unclear how exactly you're aiming to interpolate between your points, but hopefully the above concepts should help you achieve your goal.

这篇关于沿着PShape轮廓走并将其分开?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆