19 May, 2019

## Polygonise Curve

Distance can be measured with respect to the shape (Geodesic) using a curve's length, or direction (Euclidean) using a straight line's length.

Examples provided by Guido, and Mirco use the Geodesic method, that is they are both based measuring distances or locating points along the curve using EKL's pointoncurve and pointoncurveRatio.

In this post, in addition to showing the Euclidean method (using spheres), I'll also show passing single value spacing, and a list of spacing values. The latter allows for dividing curves using period patterns. The outcome of todays scripts is a polyline representation of the input curve.

### Defining The Pattern

In this example, a pattern is defined as a series of numbers that repeat. Let's take an example:

let numbers(List)
numbers = List(100mm, 50mm, 10mm)



Looping through the above numbers is straight forward if we only need to generate 3 divisions--which is the size of the list. If we need to periodically generate more numbers to achieve a pattern, we need to do the following:

/* Action created by melkhaldi 5/18/2019 */

let numbers(List)
numbers = List(100mm, 50mm, 10mm)
let index(Integer)
let i=1
let count = 17
let currentLength(Length)
for i while i<=count{
if(i<=numbers.Size()){
index = i
}
else{
index = ceil(mod(i, numbers.Size())):Integer
}
if(index==0)
index =numbers.Size()

set currentLength =  numbers.GetItem(index)

Notify("#",currentLength)
}


The above code generates a series of 17 numbers matching the count variables:
100mm, 50mm, 10mm, 100mm, 50mm, 10mm, 100mm, 50mm, 10mm, 100mm, 50mm, 10mm, 100mm, 50mm, 10mm, 100mm, 50mm

### Euclidean Polygonise Curve: Single Value

Here is the code to divide a curve with a single value using spheres

/* Action created by Melkhaldi 2/8/2018 */
//set the local variables
let crv(Curve)
crv  =CurveToDivide

let includeStart(Boolean)
includeStart =IncludeStart

let includeEnd(Boolean)
includeEnd = IncludeEnd

let currentLength(Length)
currentLength=Spacing

//set the start and end points
let start, end(Point)
let vList(List)
vList = crv.GetSubElements(0, false)
start = extract(vList.GetItem(1)):Point
end = extract(vList.GetItem(vList.Size())):Point

let divPoints(List)

//include start point if required
if includeStart
divPoints.Append(start)

let divPt,center(Point)
let pln(Plane)
let arc(Circle)
let revolveAxis(Line)
let sphere(Surface)
let sorted(List)
let index (Integer)

//set the center to be the start point.
center = start

//disable errors
DisableErrors()

let i=1
for i while true  {

//exit condition
if(distance( center, end)<  currentLength){
break
}

else{
//create an offset plane at the point//plane is notmal to z
pln = planeoffset( plane(0,0,1,0m), center)
//create a half circle
arc = circleCtrRadius( center, pln, currentLength,0, 0deg, 180deg)
//get the vertexes of the circle
vList=arc.GetSubElements(0,false)
//create a cord connecting the end of the half circle
revolveAxis=line(extract(vList.GetItem(1)):Point, extract(vList.GetItem(2)):Point)

//revolve the arc to make a sphere using the cord.
sphere = revolve(arc, revolveAxis, 0deg, 360 deg)

//intersect the sphere with the curve
let intersections(List)
intersections = disassemble(intersect( crv, sphere), false)

//find the next center
if (intersections.Size()==1){
//if there is only one intersection, then take it
divPt = intersections.GetItem(1):Point
}
else{
//otherwise, take the point closer to the curve end point
sorted= intersections.Sort("<" , "Point", "Length", "y= distance(x, point( "+end.coord(1) + "," + end.coord(2) + "," + end.coord(3) + "))")
divPt =sorted.GetItem(1)
}

//lastly, if the div point is on the curve (distance 0mm from curve)
//and is not still away from the end point, then add it to out list
if( distance( divPt, crv)==0mm and distance(divPt, end)>0mm ){
divPoints.Append( divPt)
}
//define the center point again to be last the div point
center = divPt
}

}
//if the user wanted to add the end point, and it is not at the same position as the last point in the list then add it
if includeEnd and distance( end, divPoints.GetItem(divPoints.Size()))>0mm
divPoints.Append(end)

//enable errors
let err(List)
err = EnableErrors()
let poly(Curve)
//if we have no errors, then build a polygon
if(err.Size()==0){
let lines(List)
i=1
let aLine(Line)
for i while i< divPoints.Size(){
aLine =line(divPoints.GetItem(i), divPoints.GetItem(i+1))
lines.Append( aLine)
}
poly=assemble(lines):Curve

}
//otherwise, use the curve it self as a result.
else{
poly=crv
}
//set the output variable to the poly variable
Polyline = poly


### Euclidean Polygonise Curve: Pattern

Combining the above code with the code to loop through a number list, we get

/* Action created by Melkhaldi 2/8/2018 */
//set the local variables
let crv(Curve)
crv  =CurveToDivide

let lengthPattern(List)
lengthPattern =LengthPatternList

let includeStart(Boolean)
includeStart =IncludeStart

let includeEnd(Boolean)
includeEnd = IncludeEnd

let currentLength(Length)

//set the start and end points
let start, end(Point)
let vList(List)
vList = crv.GetSubElements(0, false)
start = extract(vList.GetItem(1)):Point
end = extract(vList.GetItem(vList.Size())):Point

let divPoints(List)

//include start point if required
if includeStart
divPoints.Append(start)

let divPt,center(Point)
let pln(Plane)
let arc(Circle)
let revolveAxis(Line)
let sphere(Surface)
let sorted(List)
let index (Integer)

//set the center to be the start point.
center = start

//disable errors
DisableErrors()

let i=1
for i while true  {
//determine the next length value to use from the list
if(i<=lengthPattern.Size()){
index = i
}
else{
index = ceil(mod(i, lengthPattern.Size())):Integer
}
if(index==0)
index =lengthPattern.Size()

set currentLength =  lengthPattern.GetItem(index)

//exit condition
if(distance( center, end)<  currentLength){
break
}

else{
//create an offset plane at the point
pln = planeoffset( plane(0,0,1,0m), center)
//create a half circle
arc = circleCtrRadius( center, pln, currentLength,0, 0deg, 180deg)
//get the vertexes of the circle
vList=arc.GetSubElements(0,false)
//create a cord connecting the end of the half circle
revolveAxis=line(extract(vList.GetItem(1)):Point, extract(vList.GetItem(2)):Point)

//revolve the arc to make a sphere using the cord.
sphere = revolve(arc, revolveAxis, 0deg, 360 deg)

//intersect the sphere with the curve
let intersections(List)
intersections = disassemble(intersect( crv, sphere), false)

//find the next center
if (intersections.Size()==1){
//if there is only one intersection, then take it
divPt = intersections.GetItem(1):Point
}
else{
//otherwise, take the point closer to the curve end point
sorted= intersections.Sort("<" , "Point", "Length", "y= distance(x, point( "+end.coord(1) + "," + end.coord(2) + "," + end.coord(3) + "))")
divPt =sorted.GetItem(1)
}

//lastly, if the div point is on the curve (distance 0mm from curve)
//and is not still away from the end point, then add it to out list
if( distance( divPt, crv)==0mm and distance(divPt, end)>0mm ){
divPoints.Append( divPt)
}
//define the center point again to be last the div point
center = divPt
}

}
//if the user wanted to add the end point, and it is not at the same position as the last point in the list then add it
if includeEnd and distance( end, divPoints.GetItem(divPoints.Size()))>0mm
divPoints.Append(end)

//enable errors
let err(List)
err = EnableErrors()
let poly(Curve)
//if we have no errors, then build a polygon
if(err.Size()==0){
let lines(List)
i=1
let aLine(Line)
for i while i< divPoints.Size(){
aLine =line(divPoints.GetItem(i), divPoints.GetItem(i+1))
lines.Append( aLine)
}
poly=assemble(lines):Curve

}
//otherwise, use the curve it self as a result.
else{
poly=crv
}
//set the output variable to the poly variable
Polyline = poly



### Geodesic Polygonise Curve: Single Value

/* Action created by melkhaldi 5/18/2019 */
//set variables
let crv(Curve)
crv  =CurveToDivide

let includeStart(Boolean)
includeStart = IncludeStart

let includeEnd(Boolean)
includeEnd = IncludeEnd

let currentLength(Length)
currentLength =Spacing

let index (Integer)
let start, end(Point)
let vList(List)

//get start and end points
vList = crv.GetSubElements(0, false)
start = extract(vList.GetItem(1)):Point
end = extract(vList.GetItem(vList.Size())):Point

//determine the direction whether true or false.
//direction is based on how the curve was drawn.
//so here we confirm by making a test point,
//if the test point is moving on the curve (its distance from curve is zero),
//then we are using the correct boolean value
//otherwise, we have to reverse.
let dir(boolean)
let tstPoint(Point)
tstPoint = pointoncurve(crv, start,  0.01mm,true )
if distance(tstPoint, crv)==0mm{

dir = true
}
else{
dir = false
}

let divPoints(List)
//include start point if needed
if includeStart
divPoints.Append(start)

let divP(Point)
let i(Integer)
i=1
let poly(Curve)
//disable errors
DisableErrors()

for i while true{
divP = pointoncurve(crv, divPoints.GetItem(divPoints.Size()),  currentLength,dir )

//break out of the loop of the generated point is outside the curve
if( distance( divP, crv)<>0mm) break

//if we reached here, this means the point is on the curve, so we add it to the list
divPoints.Append( divP)

}

if includeEnd and distance( end, divPoints.GetItem(divPoints.Size()))>0mm
divPoints.Append(end)

//enable errors again (every DisableErrors call has to have an EnableErrors call)
let err(List)
err = EnableErrors()

//if we have no errors
if(err.Size()==0){

//create a polyline
let lines(List)
i=1
let aLine(Line)
//go over all points, and stop one position before last, because out functions uses i(current point) and i+1 for next point
for i while i< divPoints.Size(){
aLine =line(divPoints.GetItem(i), divPoints.GetItem(i+1))
lines.Append( aLine)
}
//assemble the lines as a single curve
poly=assemble(lines):Curve

}
else{
//if there are errors, then just use the input curve as the result
poly=crv
}
//set the output variable
Polyline = poly



### Geodesic Polygonise Curve: Pattern

/* Action created by melkhaldi 5/18/2019 */
//set local variables
let crv(Curve)
crv  =CurveToDivide

let lengthPattern(List)
lengthPattern = LengthPatternList

let includeStart(Boolean)
includeStart = IncludeStart

let includeEnd(Boolean)
includeEnd = IncludeEnd

let currentLength(Length)

let index (Integer)

let start, end(Point)
let vList(List)
//get start and end points
vList = crv.GetSubElements(0, false)
start = extract(vList.GetItem(1)):Point
end = extract(vList.GetItem(vList.Size())):Point

//confirm direction (boolean) to use for generating points
let dir(boolean)
let tstPoint(Point)
tstPoint = pointoncurve(crv, start,  0.01mm,true )
if distance(tstPoint, crv)==0mm{

dir = true
}
else{
dir = false
}

let divPoints(List)

if includeStart
divPoints.Append(start)

let divP(Point)

let i(Integer)
i=1

let poly(Curve)
//disable errors
DisableErrors()
for i while true{
//loop to get the next length in the pattern
if(i<=lengthPattern.Size())
index = i
else
index = ceil(mod(i, lengthPattern.Size())):Integer
if(index==0)
index =lengthPattern.Size()
//set the current length variable
set currentLength =  lengthPattern.GetItem(index)
//generate a point
divP = pointoncurve(crv, divPoints.GetItem(divPoints.Size()),  currentLength,dir )

//test if point is not on the curve--if so, break the loop
if( distance( divP, crv)<>0mm) break

//add the point to the list
divPoints.Append( divP)

}
if includeEnd and distance( end, divPoints.GetItem(divPoints.Size()))>0mm
divPoints.Append(end)

//enable errors
let err(List)
err = EnableErrors()
//if no errors build a polyline
if(err.Size()==0){

let lines(List)
i=1
let aLine(Line)
for i while i< divPoints.Size(){
aLine =line(divPoints.GetItem(i), divPoints.GetItem(i+1))
lines.Append( aLine)
}
poly=assemble(lines):Curve

}
else{
//else return the input curve
poly=crv
}
//set the output variable
Polyline = poly



### Running The Scripts

You can find the file in this link on Bitbucket!

Tags: