brian.wamsley

Rounded N-Sided Polygon Possible?

Blog Post created by brian.wamsley on Jan 9, 2020

Trying to use CGA to create a "rounded N-Sided polygon" turned into a hobby.   One I haven't solved it yet but maybe somebody else will.  I thought I would share my findings to give the next person a head start and so I could remove this "sticky" thought of mine and move on.  At least along the way, I got a bit better understanding of recursive code and parameter initiating.   Understanding parameters seems like the key to breaking apart the intense Complete Streets code so that I can make my own modifications.   

 

So what's end goal for a rounded n-sided polygon?  Maybe that leftover shape in your parking lot needs to be rounded curbs?  That's my endpoint I guess.  Not quite worth the attention I gave this problem.   Probably much better work-arounds given the tool sets available internal/externally.

 

From my half circle project I found out that you could rotate the scope after the half circle split but before the "quarter circle" split to produce any obtuse angle.

 

halfCircle-->     
     rotateScope(0,-35,0)
     split(x){'.5: quarterCircleA|'.5: quarterCircleB}

 

Angled Cuts

Obtuse Angle

 

I thought that might be the key to unlocking the next step, an N-Sided Polygon.

 

As for dividing up the shape to set up the angle splits, intuitively I know it involves radius offset (shown by image below).  And then finding where the circle touches the sides to calculate a angle and applying that back to the angled circle for a cut (including rotation, translation, scope).

Rounded Corner Technique

Image: Stackoverflow - user "dbc"

 

I dove into the CGA recursive coding techniques and finally started to grasp some of the CGA reference.   After some trial and error I was able to produce this:

 

Recursive Test on 3 shapes

The red is the starting point for the first shape edge offset, which you have to treat differently than the recursive shapes.  This is because it will create two corners (the one at "0" starting).  The yellow sides are the offsets produced by recursive scope pivots.  The grey is the yellow with a radius/remainder split.  Green circles are inserted into the resulting shapes.  And the light purple is the quarter circle split with no scopeRotation, translation, or rotation applied yet.  I need to figure out how to get the angles and parameter them.  Notice I didn't include a concave polygon.  I think that would require a case/else and maybe a geometryIsConcave test.  Also, the final rotation isn't quite working as the final shapes scope goes beyond the original shape.   Maybe this could be useful itself - for placing something on the inside space of each corner, like a patch of trees?   

 

Here is the CGA:

/**
* File:    N-Gon_Rounder.cga
* Created: 9 Jan 2020 14:45:20 GMT
* Author:  bwamsley
*/

version "2019.1"

@Range(min=1,max=100,restricted=false)
attr CornerRadius = 10
@Hidden
edgeN = geometry.nEdges
@Hidden
verticemover = 0


@Start

Polygon-->
     PolygonN(edgeN,0)

PolygonN(edgeN, verticemover)-->
     case (edgeN) > 1 :
          alignScopeToGeometry(yUp,0,(verticemover))
          split(z){~1: RemainderShape(edgeN, verticemover) |CornerRadius : CornerMaker(edgeN,verticemover)}
     else: InteriorShape

RemainderShape(edgeN, verticemover)-->
     PolygonN(edgeN - 1, verticemover + 1)


###Creating offsets for Circles

CornerMaker(edgeN,verticemover)-->
     case (verticemover) > 0:
          setPivot(xyz,3)
          split(z){~1: InteriorEdgeShapes (edgeN,verticemover)     |CornerRadius: CircleSpace (edgeN,verticemover)}
          #split(z){CornerRadius: CircleSpace(edgeN,verticemover) | ~1: InteriorEdgeShapes}
          #split(x){~1: InteriorEdgeShapes     |CornerRadius: CircleSpace}
          #split(x){CornerRadius: CircleSpace | ~1: InteriorEdgeShapes}
     else:  StartShape (edgeN,verticemover)

###Starting Edge needs special treatment (two circle spaces required)
     
StartShape (edgeN,verticemover)-->
     alignScopeToGeometry(yUp,0,1) ###special case
     split(z){~1: StartShape2 (edgeN,verticemover)   ///Goes back to Scope Origin for Split
     |CornerRadius : CircleSpace(edgeN,verticemover)}

StartShape2 (edgeN,verticemover)-->
     alignScopeToGeometry(yUp,0,3)
     split(z){~1: InteriorEdgeShape0(edgeN,verticemover)
     |CornerRadius : CircleSpace(edgeN,verticemover)}     
          
InteriorShape-->
     color("#006994")  ##Blue          

InteriorEdgeShape0 (edgeN,verticemover)-->      
     color("#e32636")  ##Crimson

InteriorEdgeShapes (edgeN,verticemover)-->      
     color("#FFAA00")  ##Gold     

####Circle Making
     
CircleSpace(edgeN,verticemover)-->
     color("#8db600")  ##Green
     primitiveDisk(32, CornerRadius/2)
     split(x){'.5: halfCircleA (edgeN,verticemover) | '.5: halfCircleB(edgeN,verticemover)}
     
halfCircleA (edgeN,verticemover)-->
     rotateScope(0,0,0)
     split(z){'.5: qCircleA (edgeN,verticemover) | '.5: qCircleB(edgeN,verticemover)}
     
qCircleA (edgeN,verticemover)-->
     color("#b19cd9")  ##LightPurple     

 

I guess one thing I learned about parameters - just carry them the whole way to make sure.  Also, notice that you can see the actual parameter data in the inspector tree per object as you hover your cursor over it!  That kinda helps to see what your recursive code is doing as you write it and test it.   I didn't see that listed anywhere in the reference.

 

This is where I got too and maybe someone will figure it out.   

 

Please share with me if you do!!

 

P.S. - I don't intend to become a blog writer here!!  Just trying to help others who find the CGA reference as confusing as I do.

Outcomes