I’ve a 2d drawing of an atrium roof. I’ve imported the 2d curves and added points to each end points. The idea is to group these points by sets of 3 and place a three point adaptive component family. However, each point number is scattered through a out the roof, which makes it almost impossible to group. If it’s even possible to renumber or reset all points, how can you group them by three if there isn’t any orthogonal logic to run a slice, indices or split node?

# Atrium roof: Grouping points for adaptive components

**Thomas_Mahon**#2

Its practically impossible because of the sheer number of possible solutions: for example, there is more than one type of Isosceles, meaning what is invalid to you, would not be invalid to a program (i.e. Dynamo/a script) which makes rule definition a minefield as one rule that’s required may invalidate another that’s required and so forth. If you did try it, visual programming is a no-go as it will require iteration, so you’ll also need good coding skills.

To conclude, you will spend less time manually drafting it then trying to program it to work they way you need. A simple and quick way to understand why this is almost impossible (in theory it is technically solvable, hence the ‘almost’) is to do the following: using your imagination, remove all the lines from your diagram so you are left with just the points. Now go ahead and join the dots without making a single mistake. This is what the computer will be using! Although this doesn’t fully respect the complexity of the task since you’ll be working from what you saw - i.e. you have a visual reference. A computer has no such capability.

It does however give a few suggestions as to how it could be solved: for example, importing a jpg as a reference then using its pixels to help validate a solution…but unless you have to do this task until the end of time, I would park the idea.

Perhaps I dont understand fully, but why dont you get the surface bounds (a rectangle encapsulating your lines). Then scale this from the centroid a significant enough amount, so that after you project your curves to this srf, you can split and remove the left over srf (would be the largest area).

now you have a bunch of triangular surfaces in dynamo, grab the vertices and you’re good to go.

I think you just answered your own question. If there’s no logic, how can anything be determined? Randomly? Artistically? The first maybe doable in Dynamo. The second… not likely anytime soon. (Now, where did I put that machine learning script?)

**Thomas_Mahon**#5

Ok, so you have the curves, that does simplify the problem quite significant (I jumped the gun and thought you were only working with points).

Here’s a concept but you’re still going to be faced with more challenges than this:

- List all the known angles for every type of isosceles
- Select any line and find another other line that it joins
- Validate the angle between the two then select the line that’s bound by the points of the selected lines that aren’t coincident
- Create a face from the three lines
- Create a centre point and store it (it will be needed to prevent against duplicates as the rest of the lines are iterated and processes using this method
- Select any one of the edges and repeat steps 1-6

That process is by no means a solution as it fails to deal with the multitude of other challenges, for example ending up in circular references. You would need to find a way of checking if lines overlap (i.e. not a perimeter curve) and only use lines once or twice based on which of these conditions apply. That way you could navigate the entire patern, however you may end up in a dead end (creating culdesacs would be a common occurrence), which means more exceptions to the rule…if curves remain unprocessed, find and continue etc.

As you can see, it’s still a minefield even with the complexity of the problem greatly reduced by having curves. There are much smarter ways of solving this too, but that’s ultimately in the eye (and capacity of the mind) of the beholder

**JacobSmall**#6

A **possible** workaround:

- Push the line to DWG format and open the result in autocad.
- Generate a hatch for each triangle by simply clicking the midpoint of each panel. Make sure the hatch associates to a new polyline.
- Export the new polylines with a data extraction (
**never tried this before so this may be a hickup**) - Read the CSV created with dynamo, extract the points of each polyline from the exported data and have at it.

If the polylines don’t have the required function in the export, maybe read the dwg directly with studio to pull the triangle points that way, and then export to csv to work with them.

are there overlapping lines? if so one can remove coincedent lines, if the split routine fails because of this, but i would just see if the split operation works with the current line drawing. either way, once you have more or less the triangles split up, you can get the centroid and find the 3 closest points from that, if you want super clean geo, vs perhaps relying on the split surfaces.

**Thomas_Mahon**#8

That could work too; just mesh it using countours. You could even try a toposurface in Revit then extract the faces assuming it would work.

Just a proof of concept. Figured grasshopper/Rhino was better at this, and it was. Using flux to transfer the data back and forth and presto!

**Andrew_Page1**#10

The roof structure wae actually created in Grasshopper. and then exported to Autocad. Unfortunately the Grasshopper file is gone missing. In either case, I imported the DWG in a conceptual massing family and exploded it so that I can select the lines in Dynamo. In Dynamo I’ve removed the duplicate/overlapping curves. I do see the complexity with the suggestion you gave. How would you model this from scratch?

**Andrew_Page1**#11

What are the nodes in Grasshopper that are missing in Dynamo which makes Grasshopper the usual easier (better) solution?

**jostein_olsen**#12

the Split functions I’ve come across in Dynamo doesn’t really work so well with “iterative” splitting like the Surface Split in grasshopper.

**jostein_olsen**#13

aaand when I see @Thomas_Mahon answer, maybe this could suffice.

- link dwg in Revit
- create toposurface from import

There will probably be some edging problems due to the outer perimeter of you geometry, but possibly some split toposurfaces could do?

Convert Watertight Mesh to Solid

**Vikram_Subbaiah**#15

@Andrew_Page1 You’ll need to figure out a way to crop the boundary as required

Pattern.dyn (4.9 KB)

```
a = side/(2*Math.Tan(180/8));
r = a/(Math.Cos(180/8));
//Triangulation
pnt01 = Point.ByCoordinates({2*a,-2*a,-2*a,2*a},{2*a,2*a,-2*a,-2*a});
pnt02 = (Point.Origin()).Translate(Vector.XAxis(),2*a).Rotate(Point.Origin(),Vector.ZAxis(),45..360..45);
pnt03 = (Point.Origin()).Translate(Vector.XAxis(),2*r).Rotate(Point.Origin(),Vector.ZAxis(),22.5..337.5..45);
pnt04 = (Point.Origin()).Translate(Vector.XAxis(),r).Rotate(Point.Origin(),Vector.ZAxis(),22.5..337.5..45);
tri11 = Transpose({List.TakeEveryNthItem(pnt03,2,1),List.TakeEveryNthItem(pnt02,2,1),pnt01});
tri12 = Transpose({List.TakeEveryNthItem(pnt02,2,1),pnt01,List.TakeEveryNthItem(pnt03,2,0)});
tri13 = Transpose({pnt02,pnt03,pnt04});
tri14 = Transpose({List.ShiftIndices(pnt03,-1),List.ShiftIndices(pnt02,-1),List.ShiftIndices(pnt04,-1)});
tri15 = Transpose({pnt02,pnt04,List.ShiftIndices(pnt04,-1)});
tri16 = Transpose({List.ShiftIndices(pnt03,-1),List.ShiftIndices(pnt02,0),List.ShiftIndices(pnt04,-1)});
tri17 = List.AddItemToFront(Point.Origin(),Transpose({pnt04,List.ShiftIndices(pnt04,1)})<1>);
triPt = List.Flatten({tri11,tri12,tri13,tri14,tri15,tri16,tri17},1);
pnts1 = Point.ByCoordinates((2*a..#nx..4*a)<1>,(2*a..#ny..4*a)<2>);
cdSy1 = CoordinateSystem.ByOrigin(pnts1);
pat01 = triPt.Transform(cdSy1<1><2>);
```

Hide/compile Dynamo scripts from end users?

**Marcel_Rijsmus**#16

Subbaiahawesomeness

Can you explain whats hapening here?

It would benefit others aswell.

Marcel

**Vikram_Subbaiah**#18

Thanks @Marcel_Rijsmus

Hope this elaboration helps

```
//Length of smallest side
side = 1;
//Number of modules (X)
nx = 8;
//Number of modules (Y)
ny = 8;
//The module is a square with an inscribed regular Octagon and another smaller Octagon within
//The dimension of the square side is equal to twice the Apothem of the Larger Octagon
//The length of the large Octagon side is twice the length of the smaller Octagon
//The Apothem of the larger Octagon is calculated
a = side/(2*Math.Tan(180/8));
//The circumradius of the large Octagon
r = a/(Math.Cos(180/8));
//Points for one module
//Corner Points of Bounding Square
pnt01 = Point.ByCoordinates({2*a,-2*a,-2*a,2*a},{2*a,2*a,-2*a,-2*a});
//Midpoints of large Octagon sides
pnt02 = (Point.Origin()).Translate(Vector.XAxis(),2*a).Rotate(Point.Origin(),Vector.ZAxis(),45..360..45);
//Corner Points of Large Octagon
pnt03 = (Point.Origin()).Translate(Vector.XAxis(),2*r).Rotate(Point.Origin(),Vector.ZAxis(),22.5..337.5..45);
//Corner Points of Small Octagon
pnt04 = (Point.Origin()).Translate(Vector.XAxis(),r).Rotate(Point.Origin(),Vector.ZAxis(),22.5..337.5..45);
//Square Corner Triangulation
tri11 = Transpose({List.TakeEveryNthItem(pnt03,2,1),List.TakeEveryNthItem(pnt02,2,1),pnt01});
tri12 = Transpose({List.TakeEveryNthItem(pnt02,2,1),pnt01,List.TakeEveryNthItem(pnt03,2,0)});
//Large Octagon Triangulation
tri13 = Transpose({pnt02,pnt03,pnt04});
tri14 = Transpose({List.ShiftIndices(pnt03,-1),List.ShiftIndices(pnt02,-1),List.ShiftIndices(pnt04,-1)});
tri15 = Transpose({pnt02,pnt04,List.ShiftIndices(pnt04,-1)});
tri16 = Transpose({List.ShiftIndices(pnt03,-1),List.ShiftIndices(pnt02,0),List.ShiftIndices(pnt04,-1)});
//Small Octagon Triangulation
tri17 = List.AddItemToFront(Point.Origin(),Transpose({pnt04,List.ShiftIndices(pnt04,1)})<1>);
//Three point groups for module
triPt = List.Flatten({tri11,tri12,tri13,tri14,tri15,tri16,tri17},1);
//Grid
pnts1 = Point.ByCoordinates((2*a..#nx..4*a)<1>,(2*a..#ny..4*a)<2>);
//Place instances of the points module at grid points.
cdSy1 = CoordinateSystem.ByOrigin(pnts1);
pat01 = triPt.Transform(cdSy1<1><2>);
```