GH JointTools

JointTool is a set of C# components helps user to make flap joints on any complex tesselated surfaces.


Adjacency analyzer

Adjacency analyzer will compuate adjacency status on each edge of tesselated face. Each fase is number coded, and adjacent face numbers are structured in respective order as Brep edges of each faces.

View Code (C#) Adjacency analyzer

private void RunScript(List<Polyline> srfEdgs, ref object A)

List<Polyline> srfEdges = new List<Polyline>(srfEdgs);
DataTree<int> adjSrfs = new DataTree<int>();

//find adjacent face from each edges
for(int i = 0;i < srfEdges.Count;i++){

Polyline pl = srfEdges[i];
List<int> adjSrfNo = new List<int>();
for(int j = 0;j < pl.SegmentCount;j++){

Line ln = srfEdges[i].SegmentAt(j);
Point3d ptM = new Point3d((ln.From + ln.To) / 2);
//find closest face from this edge and get index number
for(int k = 0;k < srfEdges.Count;k++){

double distance = ptM.DistanceTo(srfEdges[k].ClosestPoint(ptM));
if(distance < 0.1 && k != i){

GH_Path path = new GH_Path(i, j);
adjSrfs.Add(k, path)




A = adjSrfs;




Creates flaps on edges with adjacent faces. Edge with no adjacent face will be omitted. Edge aligned frame is also returned for additional details or text marking purpose.

View Code (C#) FlapGen

private void RunScript(List<Brep> faces, double offset, double taperAngle, object fillet, ref object flap, ref object frame)

List<Brep> faceList = new List<Brep>(faces);
DataTree<Curve> flaps = new DataTree<Curve>();
DataTree<Plane> planes = new DataTree<Plane>();

for(int i = 0;i < faceList.Count;i++){

Brep face = faceList[i];
//get outer boarders as polyline
Polyline pl;
Curve.JoinCurves(faceList[i].DuplicateNakedEdgeCurves(true, false))[0].TryGetPolyline(out pl);
//get edges
for(int j = 0;j < pl.SegmentCount;j++){

Line ln = pl.SegmentAt(j);
Point3d ptM = ln.PointAt(0.5);
//make base plane for text tags
Plane pln = new Plane(new Point3d(0, 0, 0), Vector3d.ZAxis);
Plane tempPln = new Plane(new Point3d(0, 0, 0), Vector3d.ZAxis);
foreach(Surface srf in face.Surfaces){

if(ptM.DistanceTo(srf.ToBrep().ClosestPoint(ptM)) < 0.1){

srf.FrameAt(0.5, 0.5, out tempPln);



pln.Origin = ptM;
Vector3d xVec = new Vector3d(ln.To – ln.From);
Vector3d yVec = new Vector3d(ln.To – ln.From);
yVec.Rotate(0.5 * Math.PI, tempPln.ZAxis);
pln = new Plane(ptM, xVec, yVec);

//check if the edge is adjacent to another face
int adjacentCount = 0;
for(int k = 0;k < faceList.Count;k++){

double distance = ptM.DistanceTo(faceList[k].ClosestPoint(ptM));
if(distance < 0.1 && k != i){




if(adjacentCount > 0){

//offset edge towards opposite direction of centerPoint
List<Curve> offsetCrvs = ln.ToNurbsCurve().Offset(pl.CenterPoint(), pln.ZAxis, -offset, 0.1, 0).ToList();
//check if line direction is reversed
foreach(Curve offsetCrv in offsetCrvs){

List<Point3d> interpolatePts = new List<Point3d>();
Vector3d dirVec = new Vector3d(ln.To – ln.From);
double taper = taperAngle;
Vector3d testVec = new Vector3d(offsetCrv.PointAtStart – ln.From);
testVec.Rotate(taperAngle, pln.ZAxis);
double dotProduct = Vector3d.Multiply(dirVec, testVec);
if(dotProduct < 0){

taper = -taper;

//tapered line at Start
Vector3d toSVec = new Vector3d(offsetCrv.PointAtStart – ln.From);
toSVec.Rotate(taper, pln.ZAxis);
Line lnS = new Line(ln.From, toSVec);
//tapered line at End
Vector3d toEVec = new Vector3d(offsetCrv.PointAtEnd – ln.To);
toEVec.Rotate(-taper, pln.ZAxis);
Line lnE = new Line(ln.To, toEVec);
//get intersection pt
double paramA;
double paramB;
Rhino.Geometry.Intersect.Intersection.LineLine(lnS, new Line(offsetCrv.PointAtStart, offsetCrv.PointAtEnd), out paramA, out paramB);
Point3d ptS = lnS.PointAt(paramA);
Rhino.Geometry.Intersect.Intersection.LineLine(lnE, new Line(offsetCrv.PointAtStart, offsetCrv.PointAtEnd), out paramA, out paramB);
Point3d ptE = lnE.PointAt(paramA);
//Add pts to list and create polyline
Curve polyline = Curve.CreateInterpolatedCurve(interpolatePts, 1);
//add to matching branch
GH_Path path = new GH_Path(i, j);
flaps.Add(polyline, path);
planes.Add(pln, path)




flap = flaps;
frame = planes;



Unroll Brep and project frames along unrolled Brep

View Code (C#) Unroller

private void RunScript(Brep brep, List<Plane> frame, ref object unrolled, ref object Frame)

Brep srf = brep;
//initialize unroller object
Unroller unroll = new Unroller(srf);
unroll.ExplodeOutput = false;
//add frame center and x axis point
foreach(Plane f in frame){

unroll.AddFollowingGeometry(f.XAxis + f.Origin);

//out params
Curve[] crvs;
Point3d[] points;
TextDot[] tdots;
//perform unroll
unrolled = Rhino.Geometry.Brep.JoinBreps(unroll.PerformUnroll(out crvs, out points, out tdots), Rhino.RhinoDoc.ActiveDoc.ModelAbsoluteTolerance);
//construct frame from oriented points
List<Plane> textFrames = new List<Plane>();
for(int i = 0;i < points.Count();i += 2){

Vector3d x = points[i + 1] – points[i];
Vector3d y = x;
y.Rotate(0.5 * Math.PI, Vector3d.ZAxis);
Point3d orgn = points[i];
Plane textFrame = new Plane(orgn, x, y);

Frame = textFrames;


Leave a Reply