I am importing some lines from autocad (ceiling plan exported from revit, exploded, and imported back).
I want to determine the centerpoints of all the ceilingtiles.
The data i get in is just a list of lines.
I plan using the script to center my lighting fixtures, fire alarm devices, building automation devices and so forth in the ceiling tiles.
Anyone know a good way to do this without slowing down the program significantly?
I created this python script which seems to find the intersections without slowing the script down a crazy amount:
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
#The inputs to this node will be stored as a list in the IN variables.
dataEnteringNode = IN
OUT = []
def line_intersects(p1sp,p1ep,p2sp,p2ep):
xdiff = (p1sp.X - p1ep.X, p2sp.X - p2ep.X)
ydiff = (p1sp.Y - p1ep.Y, p2sp.Y - p2ep.Y)
def det(a1,a2,b1,b2):
return a1 * b2 - a2 * b1
div = det(xdiff[0],xdiff[1],ydiff[0],ydiff[1])
if div <> 0:
d = (det(p1sp.X,p1sp.Y,p1ep.X,p1ep.Y), det(p2sp.X,p2sp.Y,p2ep.X,p2ep.Y))
x = det(d[0],d[1], xdiff[0],xdiff[1]) / div
y = det(d[0],d[1], ydiff[0],ydiff[1]) / div
if x > p1sp.X and x < p1ep.X and y > p2sp.Y and y < p2ep.Y:
OUT.append([x,y])
for l1 in IN[0]:
p1sp = l1.StartPoint
p1ep = l1.EndPoint
for l2 in IN[0]:
if l1 <> l2:
p2sp = l2.StartPoint
p2ep = l2.EndPoint
if p1sp.X < p2sp.X and p1ep.X > p2ep.X or p1sp.Y > p2sp.Y and p1ep.Y < p2ep.Y:
line_intersects(p1sp,p1ep,p2sp,p2ep)
The script takes in a flat list of all the lines and check if they intersect. I couldn’t figure out how to make the points in python, so i just output the values and combined them to points. Easy way to implement this to the python script would be appreciated.
Create paired lists for each index and the following index of each group.
IE: {{1,2},{2,3},{3,4}…}
Drop the first item from the second list in all cases (the lowest Y value) and the list item from each item in the first list (the highest Y value).
Draw a line between each (longest lacing), and draw a line between the matching indexes of each list (index 0 to index 0). They should be diagonal lines across each tile except the end tiles (where you likely don’t want fixtures anyway).
Use a point at parameter to find the midpoint of each of the new diagonal lines.
Thanks for your response, this seems like a good way of going about it.
As you can probably see from the code, I am not very experienced with Python. I have just recently started learning it-
So how do I go forth grouping points by the X line, and pair list for indexes like you said in 3. ?
As of now my code is:
import clr
clr.AddReference('ProtoGeometry')
clr.AddReference('DSCoreNodes')
import DSCore
from DSCore import *
from Autodesk.DesignScript.Geometry import *
#The inputs to this node will be stored as a list in the IN variables.
dataEnteringNode = IN
data = []
OUT = []
def line_intersects(p1sp,p1ep,p2sp,p2ep):
xdiff = (p1sp.X - p1ep.X, p2sp.X - p2ep.X)
ydiff = (p1sp.Y - p1ep.Y, p2sp.Y - p2ep.Y)
def det(a1,a2,b1,b2):
return a1 * b2 - a2 * b1
div = det(xdiff[0],xdiff[1],ydiff[0],ydiff[1])
if div <> 0:
d = (det(p1sp.X,p1sp.Y,p1ep.X,p1ep.Y), det(p2sp.X,p2sp.Y,p2ep.X,p2ep.Y))
x = det(d[0],d[1], xdiff[0],xdiff[1]) / div
y = det(d[0],d[1], ydiff[0],ydiff[1]) / div
if x > p1sp.X and x < p1ep.X and y > p2sp.Y and y < p2ep.Y:
OUT.append(Point.ByCoordinates(x,y))
for l1 in IN[0]:
p1sp = l1.StartPoint
p1ep = l1.EndPoint
for l2 in IN[0]:
if l1 <> l2:
p2sp = l2.StartPoint
p2ep = l2.EndPoint
if p1sp.X < p2sp.X and p1ep.X > p2ep.X or p1sp.Y > p2sp.Y and p1ep.Y < p2ep.Y:
line_intersects(p1sp,p1ep,p2sp,p2ep)
Here are my files so far.
As far as I can tell, the actual Ceiling elements is not needed for the graph to work, so only the dwg and graph are attached:
well… if u want the midpoint of a polygon u can calculate the average point of the polygonpoint.
So u need all points of one mesh and calculate the average.
I am not sure if i am missing something, but:
I only have a list of points, containing all the points shown in the picture in the posts above. I am not sure how to progress to collect and connect the correct sets of points to create a mesh, or a shape for each grid.
I did some testing and got something which almost worked, but had a flaw. Would have posted earlier but had to run to the train and forgot about it in the days that followed.
First I got the direction from each line, and adjusted t so they were all in the +Y quadrants (some were flipped when in autocad). I then grouped each line by the vector, then grouped again by the X value for the start point, then sorted by the Y value of the same point. I then intersected them all with each other to get the points. This produced a series of points which were grouped by common axis line, and orted by their distance from the endpoint.
I finally offset by 1/2 of the distance between points (half a tiles short direction), and then 1/2 the distance along the Y+ vector rotated -90 degrees and the next line extended infinitely (to allow for oddly shaped rooms like circles). This was more accurate than the diagonal as the diagonal produced odd results on end tiles, and the math was simple enough so I let it ride.
The method works on any single grouping of the lines but I was concerned (and verified the issue) with large groupings of lines where differing grids may overlap oddly (I.E. two rooms with the start point off by a fraction of a tile). So I’m now left wondering how to group each pair of lines with each other, or going back to the drawing board and starting another method.
I’ll try to remember to upload the DYN tonight but am out of the office for a good while today.
The last update i did on the python script was to group the points per line.
They are grouped in order, but it seems to be ordered from right to left.
(the random points you see are just lighting fixtures)
New Python Code:
import clr
clr.AddReference('ProtoGeometry')
clr.AddReference('DSCoreNodes')
import DSCore
from DSCore import *
from Autodesk.DesignScript.Geometry import *
#The inputs to this node will be stored as a list in the IN variables.
dataEnteringNode = IN
OUT = []
def line_intersects(p1sp,p1ep,p2sp,p2ep):
xdiff = (p1sp.X - p1ep.X, p2sp.X - p2ep.X)
ydiff = (p1sp.Y - p1ep.Y, p2sp.Y - p2ep.Y)
def det(a1,a2,b1,b2):
return a1 * b2 - a2 * b1
div = det(xdiff[0],xdiff[1],ydiff[0],ydiff[1])
if div <> 0:
d = (det(p1sp.X,p1sp.Y,p1ep.X,p1ep.Y), det(p2sp.X,p2sp.Y,p2ep.X,p2ep.Y))
x = det(d[0],d[1], xdiff[0],xdiff[1]) / div
y = det(d[0],d[1], ydiff[0],ydiff[1]) / div
if x > p1sp.X and x < p1ep.X and y > p2sp.Y and y < p2ep.Y:
return Point.ByCoordinates(x,y)
for l1 in IN[0]:
p1sp = l1.StartPoint
p1ep = l1.EndPoint
data = []
for l2 in IN[0]:
if l1 <> l2:
p2sp = l2.StartPoint
p2ep = l2.EndPoint
if p1sp.X < p2sp.X and p1ep.X > p2ep.X or p1sp.Y > p2sp.Y and p1ep.Y < p2ep.Y:
if not (line_intersects(p1sp,p1ep,p2sp,p2ep) is None):
data.append(line_intersects(p1sp,p1ep,p2sp,p2ep))
if data.Count > 0:
OUT.append(data)
Do you still have the .DYN file?
I am unable to recreate the script the way you said you solved it, and I would love to fiddle around with your solution
Any update on this?
I used your code but it didn’t work and some of it needed to be updated. I’m sure its pretty close but I can seem to get any points.
RVT 2016 but you can update it if you want: Lines Test.rvt (312 KB)