# EKL Finding Hole Centers From a Non-Connex Curve

## EKL Finding Hole Centers From a Non-Connex Curve

This something I have done several times over the years and its demonstrates some useful techniques.

### Disassembley

I typically will work from in an Action first then move the code to the required Knowledgeware object, Rule, reaction, Knowledge Pattern etc. This way I can control when the code runs and what the inputs and outputs are in the specification tree.

First step is to disassemble the non-connex curve that represents all of the boundaries. However we want to maintain each connex boundary as a whole. This is done by using the Boolean value “True”, in the disassemble method, to maintain closed boundaries.

//Let iCurve ( Curve )
//iCurve = 'GeoemtricalSet.1/Boundary.1'

Let ioCurveList ( List )
ioCurveList = disassemble( iCurve , True )

### Finding Holes

Now that we have the curves, we need to find curves that are specifically round or close to round depending on where the geometry came from. To do this we will compare the surface area of each hole to the mathematical definition of the hole area based on the minimum curvature radius of the curve.

//Let iCurve ( Curve )
//iCurve = 'GeoemtricalSet.1/Boundary.1'

// Create a List of Closed Curves
Let ioCurveList ( List )
ioCurveList = disassemble( iCurve , True )

// Loop Through and Find The Round Holes
Let ioIndex ( Integer )
ioIndex = 1

For ioIndex While IoIndex <= ioCurvesList->Size()
{
// Get Each Curve in the List
Let ioCurve ( Curve )
ioCurve = ioCurveList[ ioIndex ]

// Calculate the Areas Geometrically and Mathmatically
Let ioArea1, ioArea2 ( Area )
ioArea1 = area( fill( ioCurve ))
ioArea2 = PI*(( minimumcurvateRadius( ioCurve ))**2)

// Compare the Areas
Let ioCompare ( Real )
ioCompare = abs(( ioArea1/1mm2 ) - ( ioArea2/1mm2 ))

// Compare With a Tollerance
If( ioCompare < 2 )
{
// We Found a Round Hole.
}
Else
{
Notify( "#" , "Curve is not a Circle." )
}
}

### Outputting the Hole Centers

Now that we know what is round (in air quotes, based on tolerance) we can get the center of gravity point and output this as a comma, semi-colon separated list as a string. So we will need a string parameter in the specification tree to receive the value, this can then be manipulated in excel to get the center points.

First we need to add a New output String which we can equate to the string in the specification tree. Then we will add a counter to keep track of the number of found circles and initialize the value to 1.

Finally we can then extract the hole position and add it to the output string.

//Let iCurve ( Curve )
//iCurve = 'GeoemtricalSet.1/Boundary.1'
//Let oString ( String )

// Create a List of Closed Curves
Let ioCurveList ( List )
ioCurveList = disassemble( iCurve , True )

// Loop Through and Find The Round Holes
Let ioIndex , ioCounter( Integer )
ioIndex = 1
ioCounter = 1
For ioIndex While IoIndex <= ioCurvesList->Size()
{

// Get Each Curve in the List
Let ioCurve ( Curve )
ioCurve = ioCurveList[ ioIndex ]

// Calculate the Areas Geometrically and Mathmatically
Let ioArea1, ioArea2 ( Area )
ioArea1 = area( fill( ioCurve ))
ioArea2 = PI*(( minimumcurvateRadius( ioCurve ))**2)

// Compare the Areas
Let ioCompare ( Real )
ioCompare = abs(( ioArea1/1mm2 ) - ( ioArea2/1mm2 ))

// Compare With a Tollerance
If( ioCompare < 2 )
{
// Create a Center Point
Let ioCoG ( Point )
ioCoG = centerofGravity( ioCurve )

// Add Semi Colon Seperator Once Counter is Greater Than 2
oString = ( ioCounter > 2 ) ? oString + ";" ; oString

// Build the String by Concatination
oString = oString + ioCoG->coord(1) + "," + ioCoG->coord(2) + "," + ioCoG->coord(3)

// Increment the Counter
ioCounter = ioCounter + 1
}
Else
{
Notify( "#" , "Curve is not a Circle." )
}
}