# Shape from Stroke

**URL:** https://discourse.processing.org/t/shape-from-stroke/14893
**Category:** Coding Questions
**Created:** [October 23, 2019, 8:27am UTC](https://discourse.processing.org/t/shape-from-stroke/14893 "2019-10-23T08:27:44Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![dehyde](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/dehyde/32/5153_2.png) [@dehyde](https://discourse.processing.org/u/dehyde)
#### Post date: [October 23, 2019, 8:27am UTC](https://discourse.processing.org/t/shape-from-stroke/14893/1 "2019-10-23T08:27:44Z")

</div>

Is there a known way to take the stroke of a bezier curve or PShape and turn it into a closed path / shape?

for example:

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

---

<div class="post-metadata">

### Author: ![bohnacker](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/bohnacker/32/5868_2.png) [@bohnacker](https://discourse.processing.org/u/bohnacker)
#### Post date: [October 23, 2019, 9:09am UTC](https://discourse.processing.org/t/shape-from-stroke/14893/2 "2019-10-23T09:09:59Z")

</div>

Hi,

I found the following in the processing forum which might be just your question:  
[https://forum.processing.org/one/topic/creating-the-outline-path-from-a-line-with-specified-strokeweight.html](https://forum.processing.org/one/topic/creating-the-outline-path-from-a-line-with-specified-strokeweight.html)

Unfortunately the final solution isn’t there. But there is mentioned the Geomerative library from Richard Marxer which has lots of functions to manipulate paths and shapes.

I couldn’t quickly find if there is a function implemented that solves your problem.

---

<div class="post-metadata">

### Author: ![noel](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/noel/32/213_2.png) [@noel](https://discourse.processing.org/u/noel)
#### Post date: [October 23, 2019, 9:13am UTC](https://discourse.processing.org/t/shape-from-stroke/14893/3 "2019-10-23T09:13:20Z")

</div>

[geomerative](https://github.com/rikrd/geomerative)

---

<div class="post-metadata">

### Author: ![hotfooted](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/hotfooted/32/3670_2.png) [@hotfooted](https://discourse.processing.org/u/hotfooted)
#### Post date: [October 23, 2019, 9:41am UTC](https://discourse.processing.org/t/shape-from-stroke/14893/4 "2019-10-23T09:41:03Z")

</div>

what about [this answer on stackoverflow](https://gamedev.stackexchange.com/a/86322)

---

<div class="post-metadata">

### Author: ![Tiemen](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/tiemen/32/5477_2.png) [@Tiemen](https://discourse.processing.org/u/Tiemen)
#### Post date: [October 23, 2019, 9:52am UTC](https://discourse.processing.org/t/shape-from-stroke/14893/5 "2019-10-23T09:52:09Z")

</div>

Think you made a copy-paste error with the link 😱

---

<div class="post-metadata">

### Author: ![hotfooted](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/hotfooted/32/3670_2.png) [@hotfooted](https://discourse.processing.org/u/hotfooted)
#### Post date: [October 23, 2019, 9:53am UTC](https://discourse.processing.org/t/shape-from-stroke/14893/6 "2019-10-23T09:53:39Z")

</div>

oops. fixed. i’m not sure if it is what you are looking for but it might at least point you in a direction worthwhile.

---

<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: [October 23, 2019, 3:22pm UTC](https://discourse.processing.org/t/shape-from-stroke/14893/7 "2019-10-23T15:22:20Z")

</div>

Hi @dehyde

The approach suggested in the SO thread linked by @hotfooted is interesting but you might face a problem when dealing with `curveVertex` or `bezierVertex` as you won’t be able to retrieve all the vertices along that line that are necessary to compute their perpendicular projection.

Below an annotated example sketch (Python mode) that:

- computes a degree 3 polyline (close to Bezier spline) from a set of control points using the Catmull-Clark subdivision algorithm

- calculates the perpendicular projection of each vertex of that polyline on both sides (inner and outer edge of your path).

- draw a PShape made of `QUAD_STRIP` from these projected vertices

You can adjust the subdivision level to your needs, tune the length of the perpendicular lines (the width of your path) and interactively change the position of the control points with the mouse.

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

```auto
ITER = 5 #up to 7 max
SW = 25.0
toMove = None

def setup():
    size(1000, 600, P2D)
    strokeWeight(2)
    smooth(8)
    noFill()
    
    global ctrlPnts, pnts
        
    ctrlPnts = [PVector(250, 320), PVector(450, 150), PVector(610, 200), PVector(850, 280), PVector(500, 400), PVector(540, 480), PVector(260, 500)]
    pnts = ctrlPnts
    subdivide()
    

def draw():
    background('#FFFFFF')
      
    #Draw lines between control points
    pushStyle()
    strokeWeight(1)
    stroke(40, 40, 255)
    for i, p in enumerate(ctrlPnts):
        line(p.x, p.y, ctrlPnts[(i+1)%len(ctrlPnts)].x, ctrlPnts[(i+1)%len(ctrlPnts)].y)
    popStyle()
    
    
    
    #Draw control points
    pushStyle() 
    stroke(255, 30, 90)
    strokeWeight(10)
    for p in ctrlPnts:
        point(p.x, p.y)
    popStyle()
    
        
        
    #Draw Catmull-Clark subdivided polyline (spline)
    for i in xrange(len(pnts)):
        p1 = pnts[i]
        p2 = pnts[(i+1)%len(pnts)]
        line(p1.x, p1.y, p2.x, p2.y)
        
        

    #Draw PShape from quads
    pushStyle()
    strokeWeight(.7)
    fill(95, 250, 90, 60)
    beginShape(QUAD_STRIP)
    for i in xrange(len(pnts)+1):
        p1 = pnts[i-1] #last point
        pm = pnts[i%len(pnts)] #midpoint
        p2 = pnts[(i+1)%len(pnts)] # next point
        theta = atan2(p2.y - p1.y, p2.x - p1.x) + HALF_PI
        
        px = (SW*.5) * cos(theta)
        py = (SW*.5) * sin(theta) 
        
        vertex(pm.x - px, pm.y - py) #vertices for the outer edge of path 
        vertex(pm.x + px, pm.y + py) #vertices for the inner edge of path
    endShape()
    popStyle()
        

def mouseDragged():
    global toMove
    for p in ctrlPnts:
        if dist(p.x, p.y, mouseX, mouseY) < 12:
            toMove = p
            break
        
    try:
        toMove.set(mouseX, mouseY)
    except:
        print "No control point selected"
        

            
            
def mouseReleased():
    global toMove
    do = False
    for p in ctrlPnts:
        if dist(p.x, p.y, mouseX, mouseY) < 12:
            do = True
            break
    if do:
        toMove = None
        subdivide()

            
        
def subdivide():
    
    global pnts
    pnts = ctrlPnts
    
    #Catmull-Clark subdivision
    for j in xrange(ITER): 
        newPnts = []
        for i in xrange(len(pnts)):
            p1 = pnts[i]
            p2 = pnts[(i+1)%len(pnts)]
            p3 = pnts[(i+2)%len(pnts)]
            qp = p1 * .5 + p2 * .5 
            rp = p1 * .125 + p2 * .75 + p3 * .125 #(Catmull-Clark subdivision = degree 3)
            newPnts.append(qp)
            newPnts.append(rp) 
    
        pnts = newPnts

```

**edit** : You could also offset the contour of a polygon along its vertices normals. The contour and its offsetted self would compose the inner and outer edges of the PShape.

 ![ss210](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/e/e19cd134f33efd37a6ff6e16f037bc339df89811.png)  
_The contour of a polygon offsetted 20 times_

They are a dozen of SO threads on the subject (_inward/outward offset polygon_) so feel free to check there if you’re interested, you’ll probably find different approaches to your problem.

Meanwhile, here’s one them implemented in Processing Python mode:

```auto
### Based on @MBo's solution suggested here -> https://stackoverflow.com/questions/54033808/how-to-offset-polygon-edges

SW = -25.0 #Stroke width of path/PShape (-/+ for inner/outer offset)

def setup():
    size(1000, 600, P2D)
    background('#FFFFFF')
    fill(230)
    smooth(8)
            
    #List of vertices (polygon)
    points = [PVector(250, 320), PVector(450, 150), PVector(610, 200), PVector(850, 280), PVector(500, 400), PVector(540, 480), PVector(260, 500)]
    
    beginShape(QUAD_STRIP)
    for i in xrange(len(points)+1):
        pp = points[(i-1)%len(points)] #previous vertex
        pc = points[i%len(points)] #current vertex
        pn = points[(i+1)%len(points)] #next vertex
                                
        thetaA = atan2(pc.y - pp.y, pc.x - pp.x) + HALF_PI #right angle with the edge pp-pc 
        thetaB = atan2(pn.y - pc.y, pn.x - pc.x) + HALF_PI #right angle with the edge pc-pn 
        
        a = PVector(cos(thetaA), sin(thetaA)) #vector pointing perpendicularly to edge pp-pc
        b = PVector(cos(thetaB), sin(thetaB)) #vector pointing perpendicularly to edge pc-pn
        
        nsum = (a + b).normalize() #normalized sum

        l = SW / sqrt(1 + PVector.dot(a,b)) #desired length
        po = pc + (l * nsum) #offsetted vertex
        
        vertex(pc.x, pc.y)
        vertex(po.x, po.y)
    endShape(CLOSE)

```

---

<div class="post-metadata">

### Author: ![dehyde](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/dehyde/32/5153_2.png) [@dehyde](https://discourse.processing.org/u/dehyde)
#### Post date: [October 25, 2019, 11:02am UTC](https://discourse.processing.org/t/shape-from-stroke/14893/8 "2019-10-25T11:02:44Z")

</div>

Thank you for the comprehensive answer  
I didn’t have the chance to implement it just yet, once I will I’ll update with the results
