# Bending a PShape object to make it circular

**URL:** <https://discourse.processing.org/t/bending-a-pshape-object-to-make-it-circular/3640>\
**Category:** Processing.py\
**Created:** [September 18, 2018, 2:26pm UTC](https://discourse.processing.org/t/bending-a-pshape-object-to-make-it-circular/3640 "2018-09-18T14:26:47Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![solub](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/solub/32/333_2.png) [@solub](https://discourse.processing.org/u/solub)\
**Post date:** [September 18, 2018, 2:26pm UTC](https://discourse.processing.org/t/bending-a-pshape-object-to-make-it-circular/3640/1 "2018-09-18T14:26:47Z")

</div>

Hi everyone,

The title says it all, I’d like to bend a PShape object to give it a circular shape:

 ![](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/a/ae541f369cc789ea8273a4eaab218ee77157d50c.png)

I tried to project the vertices around a circle (circular translation) but it didn’t work:

**Questions** :

- Is it the correct way to achieve that warping effect ? If so, could you tell me what is wrong with the polar coordinates transformation below (line 25-30)?
- If not, what’s the best way to distort a PShape object ?

```auto
PShape object;

void setup(){
    size(1300, 800);
    
    object = createShape();
    object.beginShape();
    object.fill(255, 40, 40);
    object.translate(width/2 - width/8, height/2 - height/8);
    object.vertex(0, 0);
    object.vertex(64, 10);
    object.vertex(87, 5);
    object.vertex(173, 47);
    object.vertex(389, 20);
    object.vertex(380, 125);
    object.vertex(309, 100);
    object.vertex(83, 120);
    object.vertex(47, 175);
    object.vertex(4, 130);
    object.endShape(CLOSE);
    
    float angle = radians(360) / object.getVertexCount();    
    int radius = 100;
    
    //for (int i = 0; i < object.getVertexCount(); i++) {
    // PVector v = object.getVertex(i);
    // float x = cos(v.x * angle) * radius;
    // float y = sin(v.x * angle) * radius;
    // PVector vec = new PVector(x, y);
    // object.setVertex(i, vec);
    //}
}
        
void draw(){
    background(255);
    shape(object);     
}

```

Thank you

---

<div class="post-metadata">

**Author:** ![jb4x](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jb4x/32/789_2.png) [@jb4x](https://discourse.processing.org/u/jb4x)\
**Post date:** [September 18, 2018, 2:33pm UTC](https://discourse.processing.org/t/bending-a-pshape-object-to-make-it-circular/3640/2 "2018-09-18T14:33:41Z")

</div>

Hi,

The problem with your solution is that your are only remapping the points and even if you put them where they should go you can’t curve the lines in between as you show on your example. You would need to add way more points to achieve the curve.

What is your end goal? Do you really need a PShape or you can use an image?

---

<div class="post-metadata">

**Author:** ![solub](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/solub/32/333_2.png) [@solub](https://discourse.processing.org/u/solub)\
**Post date:** [September 18, 2018, 2:38pm UTC](https://discourse.processing.org/t/bending-a-pshape-object-to-make-it-circular/3640/3 "2018-09-18T14:38:07Z")

</div>

Hi @jb4x,

> [@jb4x](#):
>
> The problem with your solution is that your are only remapping the points and even if you put them where they should go you can’t curve the lines in between as you show on your example. You would need to add way more points to achieve the curve.

I know, it was just an example picture. The object I’d like to bend have millions of points so I guess that wouldn’t be a problem

> [@jb4x](#):
>
> What is your end goal? Do you really need a PShape or you can use an image?

The object is a `.obj` file so I really need to warp the object itself, not the pixels of an image.

---

<div class="post-metadata">

**Author:** ![jb4x](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jb4x/32/789_2.png) [@jb4x](https://discourse.processing.org/u/jb4x)\
**Post date:** [September 18, 2018, 2:43pm UTC](https://discourse.processing.org/t/bending-a-pshape-object-to-make-it-circular/3640/4 "2018-09-18T14:43:24Z")

</div>

And what is the end goal?

The transformation is not trivial at all and there would be several ways to achieve simalr effect I guess.

Is there some constraints, some rules that it should follows?

---

<div class="post-metadata">

**Author:** ![solub](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/solub/32/333_2.png) [@solub](https://discourse.processing.org/u/solub)\
**Post date:** [September 18, 2018, 2:46pm UTC](https://discourse.processing.org/t/bending-a-pshape-object-to-make-it-circular/3640/5 "2018-09-18T14:46:52Z")

</div>

> [@jb4x](#):
>
> And what is the end goal?

… for the moment, just to make the object circular. Nothing more.

There are no specific constraints I can think of right now. I just would like to explore the different ways to bend an object.

---

<div class="post-metadata">

**Author:** ![jb4x](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jb4x/32/789_2.png) [@jb4x](https://discourse.processing.org/u/jb4x)\
**Post date:** [September 18, 2018, 2:57pm UTC](https://discourse.processing.org/t/bending-a-pshape-object-to-make-it-circular/3640/6 "2018-09-18T14:57:51Z")

</div>

You can find some really interesting answers on this link: [https://math.stackexchange.com/questions/1753227/how-do-i-transpose-an-ellipse-function-to-stretch-the-ellipse-into-curved-space](https://math.stackexchange.com/questions/1753227/how-do-i-transpose-an-ellipse-function-to-stretch-the-ellipse-into-curved-space)

---

<div class="post-metadata">

**Author:** ![solub](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/solub/32/333_2.png) [@solub](https://discourse.processing.org/u/solub)\
**Post date:** [September 19, 2018, 11:04pm UTC](https://discourse.processing.org/t/bending-a-pshape-object-to-make-it-circular/3640/7 "2018-09-19T23:04:38Z")

</div>

So, trying to answer my own questions:

- the circular projection of the coordinates is **not** correct
- After giving it some thought I believe a better way to warp an object would be to attach it (with springs ?) to a spline or a point line that could be then distorted at will. Any bending of the spline would consequently affect the object’s shape, thus acting as a “backbone”.

That second suggestion being quite advanced and not necessary in this case (I just want a regular circular shape) I will stick to the circular projection. So back to my first question:

How would you project the vertices of a rather “complex” shape (PShape or group of PShape with an interior part, not a line) around a circle ?

More specifically:

- what would be the computation of the angle ?  
`float angle = radians(360) / object.getVertexCount();` doesn’t seem correct to me

---

<div class="post-metadata">

**Author:** ![solub](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/solub/32/333_2.png) [@solub](https://discourse.processing.org/u/solub)\
**Post date:** [September 20, 2018, 6:33pm UTC](https://discourse.processing.org/t/bending-a-pshape-object-to-make-it-circular/3640/8 "2018-09-20T18:33:43Z")

</div>

Simpler question.

Say you have points placed on a line at different intervals:

```auto
void setup(){
  size(800, 600, P2D);
  strokeWeight(6);
  background(255);
  smooth(8);
  
  int xmin = 200;
  int xmax = 800;
  int ymean = height/2;
  int step = 20;
    
  for (int i = 0; i < step; i++) {
    float x = lerp(xmin, xmax , i/float(step+i));
    float y = lerp(ymean, ymean, i/float(step+i));
    point(x, y);
    }
  }

```

 ![](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/d/db61f538254e06d840b9f0ac866d47c323b9c5a3.png)

How would you project them around a circle ?

 ![](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/b/b41536a317fe9fb10188f006cf72be71810ed38b.png)

---

<div class="post-metadata">

**Author:** ![noahbuddy](https://avatars.discourse-cdn.com/v4/letter/n/73ab20/32.png) [@noahbuddy](https://discourse.processing.org/u/noahbuddy)\
**Post date:** [September 21, 2018, 5:19am UTC](https://discourse.processing.org/t/bending-a-pshape-object-to-make-it-circular/3640/9 "2018-09-21T05:19:40Z")

</div>

For line-to-circle position:

```
float angleRadians = TWO_PI * linePosition / lineLength;
float circleX = radius * cos(angleRadians);
float circleY = radius * sin(angleRadians);

```

If you simply wanted a visual, you might wrap your shape as a texture onto an object. Perhaps a cylinder (included in examples).

---

<div class="post-metadata">

**Author:** ![jb4x](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jb4x/32/789_2.png) [@jb4x](https://discourse.processing.org/u/jb4x)\
**Post date:** [September 21, 2018, 5:35am UTC](https://discourse.processing.org/t/bending-a-pshape-object-to-make-it-circular/3640/10 "2018-09-21T05:35:41Z")

</div>

I was about to give you the same answer as @noahbuddy.

In this case you just need to map the distance of your point from the first one to an angle between 0 and 2\*PI.

That says, you do have constraint and rules that it should follows in this case:

- The line should be transformed in a complete circle
- the line of point should wrap completely on that circle
- the radius of the circle is known

Now to generalize the concept:

- what happen for points that are a bit further away on that line or before the first point? Are they still mapped to the same circle?
- What happen for points that are not in that line? Are they also mapped in another circle but bigger or smaller than the first one?
- The radius was here chosen at random, but should there be a rule to select the radius? In other word how do you characterize this transformation? Is it a point in the space and the closest distance to the line is the radius?
- The angles also were assumed but should the first point be 0 degree or not?
- There is also the direction of the line that was assumed to be horizontal but would it always be the case?

The reason I was asking the end goal and if there was some rules or constraints to follow is because, as you can see, the subject is really big. There is plenty of ways to deform an object and it really depend on what you want to do with it.

How you want to control it is really important because it says a lot on what are the parameters for it.

One easy way is to use the concept they use in the link I posted earlier.  
The basic idea behind it is to take a “square” space and to bend it with parabole equation. This way you can easily get the position of every points in the bent space using those equation. The cool thing about it is that you can use the equation you want to bend your space. After it’s just a matter of understanding how to control the bending.

---

<div class="post-metadata">

**Author:** ![solub](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/solub/32/333_2.png) [@solub](https://discourse.processing.org/u/solub)\
**Post date:** [September 21, 2018, 7:13pm UTC](https://discourse.processing.org/t/bending-a-pshape-object-to-make-it-circular/3640/11 "2018-09-21T19:13:24Z")

</div>

@noahbuddy – Thank you, that’s exactly what I was looking for.

@jb4x – Let me explain what I’m trying to do. I might be wrong but at least you’ll get the big picture.

There are 2 main approaches (not 1 as you’re implying) mentionned in the SE thread you are referring to. One is to compute the transformation of the _whole_ object (thing that is mathematically difficult to do accurately as stated several times in the thread), and the other one is to **approximate** that transformation by bending a spline (or a volumetric space) to which the object is attached to.

It is that second option (that I’ve mentionned before) that I’ve finally decided to try to implement.  
Here’s the idea:

- 1/ Take an object and put an imaginary line inside of it. That line crosses the object from `min(x)` to `max(x)` at height = `mean(y)`

 ![](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/9/992a98efbc84a10082f5bf1684888d95e57a89e2.png)

- 2/ Project the `x` coordinate of every vertices on that line and place a point.

 ![](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/c/c59dcc865d58cc5d7b256df573b434fa50255618.png)

- 3/ Convert these reference points to `curvePoint()` and **compute their tangents** up to their original `y` coordinate using `curveTangent()`

 ![](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/e/e11f8853f6a6bebd9edf2bec80e0e30ec163206b.png)

We now have the coordinates of every vertices based on all the tangents to the central line. Now, if I’m not mistaken, if we curve that central line then all the vertices should be curved accordingly. The object has been warped ! (I wish)

 ![](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/d/d45a587e84020a7989fa32cd0d3db02e8d04f19b.png)  
In the same way, If I project the reference points around a circle (hence my previous question) the object should be distorted circularly.

Of course I don’t know if all that is possible and I would be very curious to hear your opinion(s). Also if you have details (step-by-step explanations or pseudo-code) or ideas regarding a bending method based on a volumetric space instead of on a line/spline in Processing, I would also love to hear that.

---

<div class="post-metadata">

**Author:** ![jb4x](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jb4x/32/789_2.png) [@jb4x](https://discourse.processing.org/u/jb4x)\
**Post date:** [September 21, 2018, 8:26pm UTC](https://discourse.processing.org/t/bending-a-pshape-object-to-make-it-circular/3640/12 "2018-09-21T20:26:16Z")

</div>

You already described all the process! You have done the hard part!

Here is an example with a bezier curve. You can play around with the handles.:

```auto
PVector[] originalPoints;
float[][] param;
int xMin, xMax;
float deltaX, deltaY;
Point[] p;

void setup() {
  size(800, 600);
  noFill();
  background(20);
  stroke(230);

  initialyzeoriginalPoints();
  initializeparam();
  initializeBezierCurve();

  beginShape();
  for (int i = 0; i < originalPoints.length; i++) {
    vertex(originalPoints[i].x, originalPoints[i].y);
  }
  endShape(CLOSE);
}

void draw() {
  background(20);
  
  // Draw the deformed shape
  stroke(200, 25, 25);
  strokeWeight(2);
  noFill();
  drawShape();
  
  // Draw the control lines
  stroke(50);
  strokeWeight(2);
  line(p[0].pos().x, p[0].pos().y, p[1].pos().x, p[1].pos().y);
  line(p[2].pos().x, p[2].pos().y, p[3].pos().x, p[3].pos().y);
  
  // Draw the bezier curves
  noFill();
  stroke(200);
  strokeWeight(2);
  bezier(p[0].pos().x, p[0].pos().y, p[1].pos().x, p[1].pos().y, p[2].pos().x, p[2].pos().y, p[3].pos().x, p[3].pos().y);
  
  // Draw the points
  for (int i = 0; i < 4; i++) {
    p[i].show();
  }
  
  
}

void mousePressed() {
  // Check if mouse is over a point
  for (int i = 0; i < 4; i++) {
    if (p[i].isHit(mouseX, mouseY)) {
      p[i].lock();
      deltaX = mouseX - p[i].pos().x;
      deltaY = mouseY - p[i].pos().y;
      return;
    }
  }
}

void mouseReleased() {
  for (int i = 0; i < 4; i++) {
    p[i].unlock();
  }
}

void mouseDragged() {
  for (int i = 0; i < 4; i++) {
    if (p[i].isLocked()) {
      p[i].move(mouseX - deltaX, mouseY - deltaY);
    }
  }
}

void initialyzeoriginalPoints() {
  originalPoints = new PVector[7];
  originalPoints[0] = new PVector(100, 320);
  originalPoints[1] = new PVector(340, 210);
  originalPoints[2] = new PVector(530, 240);
  originalPoints[3] = new PVector(700, 420);
  originalPoints[4] = new PVector(420, 330);
  originalPoints[5] = new PVector(340, 370);
  originalPoints[6] = new PVector(210, 400);
  
  xMin = 100;
  xMax = 700;
}

void initializeparam() {
  param = new float[7][2];
  for (int i = 0; i < originalPoints.length; i++) {
    param[i][0] = (originalPoints[i].x - xMin) / (float)(xMax - xMin);
    param[i][1] = (float)((height / 2.0) - originalPoints[i].y);
  }
}

void initializeBezierCurve() {
  p = new Point[4];
  p[0] = new Point(xMin, (height / 2.0), color(200, 200, 10), 10);
  p[1] = new Point((xMin + xMax) / 2.0, (height / 2.0), color(200, 200, 10), 10);
  p[2] = new Point((xMin + xMax) / 2.0, (height / 2.0), color(200, 200, 10), 10);
  p[3] = new Point(xMax, (height / 2.0), color(200, 200, 10), 10);
}

void drawShape() {
  
  beginShape();
  for (int i = 0; i < param.length; i++) {
    float bezierX = bezierPoint(p[0].pos().x, p[1].pos().x, p[2].pos().x, p[3].pos().x, param[i][0]);
    float bezierY = bezierPoint(p[0].pos().y, p[1].pos().y, p[2].pos().y, p[3].pos().y, param[i][0]);
    PVector dir = getTan(param[i][0]);
    if (i == 3) {
      println(dir.y);
    }
    dir.rotate(HALF_PI);
    dir.normalize();
    dir.mult(param[i][1]);
    vertex(bezierX + dir.x, bezierY + dir.y);
  }
  endShape(CLOSE);
}

PVector getTan(float t) {
  float resultX, resultY;
  
  resultX = evaluateDerivativeX(t);
  resultY = evaluateDerivativeY(t);
  
  return new PVector(resultX, resultY);
}

float evaluateDerivativeX(float t) {
  float temp1, temp2, temp3, temp4, temp5, temp6;
  
  temp1 = -3 * p[0].pos().x * (1 - t) * (1 - t);
  temp2 = 3 * p[1].pos().x * (1 - t) * (1 - t);
  temp3 = -6 * p[1].pos().x * t * (1 - t);
  temp4 = -3 * p[2].pos().x * t * t;
  temp5 = 6 * p[2].pos().x * t * (1 - t);
  temp6 = 3 * p[3].pos().x * t * t;
  
  return temp1 + temp2 + temp3 + temp4 + temp5 + temp6;
}

float evaluateDerivativeY(float t) {
  float temp1, temp2, temp3, temp4, temp5, temp6;
  
  temp1 = -3 * p[0].pos().y * (1 - t) * (1 - t);
  temp2 = 3 * p[1].pos().y * (1 - t) * (1 - t);
  temp3 = -6 * p[1].pos().y * t * (1 - t);
  temp4 = -3 * p[2].pos().y * t * t;
  temp5 = 6 * p[2].pos().y * t * (1 - t);
  temp6 = 3 * p[3].pos().y * t * t;
  
  return temp1 + temp2 + temp3 + temp4 + temp5 + temp6;
}

class Point {
  
  private PVector pos;
  private color col;
  private int size;
  private boolean locked;
 
  Point(float x, float y, color p_col, int p_size) {
    pos = new PVector(x, y);
    col = p_col;
    size = p_size;
    locked = false;
  }
  
  void move(float x, float y) {
   pos.x = x;
   pos.y = y;
  }
  
  void show() {
    fill(col);
    noStroke();
    ellipse(pos.x, pos.y, size, size);
  }
  
  PVector pos() {
    return pos;
  }
  
  void lock() {
    locked = true;
  }
  
  void unlock() {
    locked = false;
  }
  
  boolean isLocked() {
    return locked;
  }
  
  boolean isHit(float x, float y) {
    return (pos.x - x) * (pos.x - x) + (pos.y - y) * (pos.y - y) < (size * size) / 4.0;
  }
}

```

---

<div class="post-metadata">

**Author:** ![solub](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/solub/32/333_2.png) [@solub](https://discourse.processing.org/u/solub)\
**Post date:** [September 22, 2018, 4:39pm UTC](https://discourse.processing.org/t/bending-a-pshape-object-to-make-it-circular/3640/13 "2018-09-22T16:39:36Z")

</div>

So I am trying to implement the ideas of my previous post and have an issue with `curvePoint()` and `curveTangent()`

In the following example sketch, the point in the middle is not taken into account by `curvePoint()` and `curveTangent()`. As a result, out of the 16 original points only 15 are displayed on the screen.

Why is that point being skipped ?

EDIT: I’ve changed some bits in the code but I still have a point missing. I believe I’m not using curvePoint() and curveTangent() correctly.

 ![](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/f/f6f67659b51f3a839939c609226dbf8956cbf463.png)

```auto
def setup():
    size(800, 800, P2D)
    background(255)
    smooth(8)

    xmin, xmax = 200, 800
    ymean = height/2
    step = 20
    
    points = []
    n_points = 16
    factor = 10
   
    
    #Bending points
    for i in range(n_points):
        x = lerp(xmin, xmax , i/float(step))
        y = lerp(ymean, ymean, i/float(step))
        points.append(PVector(x, y+sin(i)*factor))
        
        #Draw points
        strokeWeight(4)
        point(x, y+sin(i)*factor +30)
        
        #Draw number
        fill(0)
        textSize(10)
        text(i, x, y+sin(i)*10 +40)

    #Convert original points to curvePoint + compute tangent
    for i in range(len(points)-1):
        
        t = i / float(points-1)
        
        x = curvePoint(points[i].x, points[i].x, points[i+1].x, points[i+1].x, t)
        y = curvePoint(points[i].y, points[i].y, points[i+1].y, points[i+1].y, t)
        
        tx = curveTangent(points[i].x, points[i].x, points[i+1].x, points[i+1].x, t)
        ty = curveTangent(points[i].y, points[i].y, points[i+1].y, points[i+1].y, t)
        
        a = atan2(ty, tx)
        a -= PI/2.0
        
        #Draw curvepoints
        strokeWeight(4)
        stroke(255, 30, 30)
        point(x, y)

        #Draw tangents
        stroke(80, 80, 205)
        strokeWeight(1)
        line(x, y, cos(a)*28 + x, sin(a)*28 + y)

```

---

<div class="post-metadata">

**Author:** ![solub](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/solub/32/333_2.png) [@solub](https://discourse.processing.org/u/solub)\
**Post date:** [September 23, 2018, 10:32am UTC](https://discourse.processing.org/t/bending-a-pshape-object-to-make-it-circular/3640/14 "2018-09-23T10:32:14Z")

</div>

The following seems to work, not sure why though…

```auto
def setup():
    size(800, 800, P2D)
    background(255)
    smooth(8)

    xmin, xmax = 200, 800
    ymean = height/2
    step = 20
    
    points = []
    n_points = 16
    factor = 10
   
    
    #Bending points
    for i in range(n_points):
        x = lerp(xmin, xmax , i/float(step))
        y = lerp(ymean, ymean, i/float(step))
        points.append(PVector(x, y+sin(i)*factor))
        
        #Draw points
        strokeWeight(4)
        point(x, y+sin(i)*factor +30)
        
        #Draw number
        fill(0)
        textSize(10)
        text(i, x, y+sin(i)*10 +40)
        
        
    #Adding last point to pointlist again - will serve as ending control point
    points.insert(-1, points[-1])
    

    #Convert original points to curvePoint + compute tangent
    for i in range(len(points)-1):
        
        t = i / float(len(points)*n_points)
        
        x = curvePoint(points[i].x, points[i].x, points[i+1].x, points[i+1].x, t)
        y = curvePoint(points[i].y, points[i].y, points[i+1].y, points[i+1].y, t)
        
        tx = curveTangent(points[i].x, points[i].x, points[i+1].x, points[i+1].x, t)
        ty = curveTangent(points[i].y, points[i].y, points[i+1].y, points[i+1].y, t)
        
        a = atan2(ty, tx)
        a -= PI/2.0
        
        #Draw curvepoints
        strokeWeight(4)
        stroke(255, 30, 30)
        point(x, y)

        #Draw tangents
        stroke(80, 80, 205)
        strokeWeight(1)
        line(x, y, cos(a)*28 + x, sin(a)*28 + y)

```

 ![](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/0/0a34e7fee5e6de1b803d78e314a563ffd8f7ef0d.png)

---

<div class="post-metadata">

**Author:** ![solub](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/solub/32/333_2.png) [@solub](https://discourse.processing.org/u/solub)\
**Post date:** [September 23, 2018, 4:33pm UTC](https://discourse.processing.org/t/bending-a-pshape-object-to-make-it-circular/3640/15 "2018-09-23T16:33:52Z")

</div>

Here is a proof of concept.

 ![](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/6/617e60f04ea5bc9d02daffec8770fae0250d505b.gif)

Problem is I still haven’t figure out how to correctly use `curvePoint()` with `curveTangent()`. Here I’m multiplying `xmax` by 80 (number found at random) to push curvePoints (in red) to the left until they meet their corresponding tangent (blue lines). It does the trick but I shouldn’t be doing this normally.

All is happening here:

```auto
 #Convert reference points to curvePoint + compute tangent
    for i in range(len(points)-1):
        
        t = map(points[i].x, xmin, xmax*80, 0, 1) #multiplying by 80... just because it works
        
 
        x = curvePoint(points[i].x, points[i].x, points[i+1].x, points[i+1].x, t)
        y = curvePoint(points[i].y, points[i].y, points[i+1].y, points[i+1].y, t)

        tx = curveTangent(points[i].x, points[i].x, points[i+1].x, points[i+1].x, t)
        ty = curveTangent(points[i].y, points[i].y, points[i+1].y, points[i+1].y, t)
        
        a = atan2(ty, tx)
        a -= PI/2.0

```

It’s not really a big deal but that would be great if someone could spot the problem so we have a perfectly working example to share with everyone.

 ![](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/c/ce25ecf494bb4cd4bd44ec54e00909e05c536c32.jpeg)

_bending Manhattan_

EDIT: script is now corrected

> **Full code**
>
> ```auto
> points, idx = [], []
> X, Y = [], []
> vertices = [[264, 290], [287, 295], [373, 267], [433, 207], 
> [589, 280], [580, 325], [509, 300], [309, 330], 
> [283, 320], [247, 375], [200, 330]]
> nvertices = [0 for e in range(len(vertices))]
> refpoints = [0 for e in range(len(vertices))]
> 
> def setup():
> global object, xmin, xmax, ymean
> size(800, 600, P2D)
> smooth(8)
>     
> #Creating original object from vertices
> object = createShape()
> object.beginShape()
> object.stroke(0, 40)
> object.strokeWeight(1)
> object.noFill()
> for v in vertices:
> object.vertex(v[0], v[1])
> object.endShape(CLOSE)
> 
> #Computing mid-line coordinates
> for i, v in enumerate(vertices):
> X.append(v[0])
> Y.append(v[1])
>         
> xmin, xmax = min(X), max(X)
> ymean = sum(Y) / len(Y)
>     
> #Displaying reference points (on mid-line)
> for x in sorted(X):
> idx.append(X.index(x))
> points.append(PVector(x, ymean))
>         
> #Adding last point to pointlist again / will serve as ending control point
> points.insert(-1, points[-1])
>   
>     
> def draw():
> background(255)
>     
> #Drawing original object
> shape(object)
>     
>     
> #Bending mid-line (curving reference points with sin())
> for i, p in enumerate(points):
> p.y += cos(i*.4 + frameCount * .1) * 4
> fill(255, 30, 30)
> noStroke()
> rectMode(CENTER)
> rect(p.x, p.y, 6, 6)
> 
> points[i] = PVector(p.x, p.y) 
>         
> #Replacing ending control point
> points[-1] = points[-2]
>             
> 
> #Convert reference points to curvePoint + compute tangent
> for i in range(len(points)-1):
>        
> x = points[i].x
> y = points[i].y
> 
> tx = points[i+1].x - points[i].x
> ty = points[i+1].y - points[i].y
>         
> a = atan2(ty, tx)
> a -= PI/2.0
>         
> #computing tangent's height (ymean - original p.y)
> h = ymean - vertices[idx[i]][1] 
>         
> #Drawing tangents and new vertices
> strokeWeight(1)
> stroke(30, 30, 255)
> line(x, y, cos(a)*h + x, sin(a)*h + y)
> strokeWeight(8)
> stroke(0, 205, 0)
> point(cos(a)*h + x, sin(a)*h + y)
>         
> #Storing new vertices in their original order
> nvertices[idx[i]] = PVector(cos(a)*h + x, sin(a)*h + y) 
>         
> #Storing reference points
> refpoints[i] = PVector(x, y)
>                 
>         
> #Building object from new vertices
> beginShape()
> fill(200, 100, 0, 30)
> stroke(0)
> strokeWeight(1)
> for i in range(len(nvertices)):
> vertex(nvertices[i].x, nvertices[i].y)
> endShape(CLOSE)
>     
> #Drawing backbone (mid-line)
> for i in range(len(refpoints)-1):
> strokeWeight(.6)
> line(refpoints[i].x, refpoints[i].y, refpoints[i+1].x, refpoints[i+1].y)
>  
> #Text
> fill(0)
> textSize(14)
> for i in range(len(nvertices)): text(i, nvertices[i].x, nvertices[i].y-10)
> 
> ```

---

<div class="post-metadata">

**Author:** ![noahbuddy](https://avatars.discourse-cdn.com/v4/letter/n/73ab20/32.png) [@noahbuddy](https://discourse.processing.org/u/noahbuddy)\
**Post date:** [September 26, 2018, 3:47am UTC](https://discourse.processing.org/t/bending-a-pshape-object-to-make-it-circular/3640/16 "2018-09-26T03:47:04Z")

</div>

Starting here:

```
t = map(points[i].x, xmin, xmax*80, 0, 1) #multiplying by 80 but don't know what this number corresponds to

```

As “xmax\*n” increases, points[i].x will appear closer to “xmin”.  
Therefore t tends toward zero.

If t is zero then:

```
x = curvePoint(points[i].x, points[i].x, points[i+1].x, points[i+1].x, 0.0)
y = curvePoint(points[i].y, points[i].y, points[i+1].y, points[i+1].y, 0.0)

```

Since points[i] is the start point to those curves:

```
x = points[i].x
y = points[i].y

```

Then:

```
tx = curveTangent(points[i].x, points[i].x, points[i+1].x, points[i+1].x, t)
ty = curveTangent(points[i].y, points[i].y, points[i+1].y, points[i+1].y, t)

```

Since there are two points instead of four (start, end, pair of control points), the tangent can be quickly estimated with the slope of a line segment.

Imagine a line between two points on a curve, gradually decrease the distance between those two points, and we get what looks like the tangent.  
See Tangent reference, specifically the part of using secant.

Forgive me if you already know this.

With ‘t’ equal to zero, we are looking at points[i] and the slope to the next point:

```
tx = points[i+1].x - points[i].x
ty = points[i+1].y - points[i].y

```

Depending on your math instructor, you may have heard this as “rise over run”.  
The function atan2(ty,tx) will then get the angle of the line segment. Subtracting PI/2 (90 degrees) will give a perpendicular angle.

The variable ‘t’ is no longer needed, at least in this case.

As an aside, even without the visual, the phrase “Bending Manhattan” paints a picture… 🙂

> **[Tangent | Tangent line to a curve](https://en.wikipedia.org/wiki/Tangent#Tangent_line_to_a_curve)**
>
> The intuitive notion that a tangent line "touches" a curve can be made more explicit by considering the sequence of straight lines (secant lines) passing through two points, A and B, those that lie on the function curve. The tangent at A is the limit when point B approximates or tends to A. The existence and uniqueness of the tangent line depends on a certain type of mathematical smoothness, known as "differentiability." For example, if two circular arcs meet at a sharp point (a vertex) then ther...

---

<div class="post-metadata">

**Author:** ![solub](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/solub/32/333_2.png) [@solub](https://discourse.processing.org/u/solub)\
**Post date:** [September 26, 2018, 8:40am UTC](https://discourse.processing.org/t/bending-a-pshape-object-to-make-it-circular/3640/17 "2018-09-26T08:40:15Z")

</div>

@noahbuddy – Thanks a ton for the helpful clarifications. I wanted so badly to stick to the reference examples that I totally lost sight of the underlying logic.

Script above has been updated.

Big thanks to all of you.
