Deviation between set of Points from a Point cloud

Deviation between set of Points from a Point cloud

MiguelGT17
Advocate Advocate
1,071 Views
4 Replies
Message 1 of 5

Deviation between set of Points from a Point cloud

MiguelGT17
Advocate
Advocate

Greetings to all, I want to let you know a small issue I am facing when writing a set of points from a pointcloud into a text file, performing some operations between them, and later when I'm reading this data and placing some generic models at their location, the items appear close to the location they are suppose to be but not at the exact position.

1°Script to export the set of points projected onto the XY plane

 

 

"1) get the point cloud instance"
ptCloud=doc.GetElement(ElementId(297061))
bb=ptCloud.get_BoundingBox(doc.ActiveView) 
planes=[]

"2) Get the points that visible fromt he active view"
#X boundaries
planes.append(Plane.CreateByNormalAndOrigin(XYZ.BasisX,bb.Min))
planes.append(Plane.CreateByNormalAndOrigin(-XYZ.BasisX,bb.Max))

#Y boundaries
planes.append(Plane.CreateByNormalAndOrigin(XYZ.BasisY,bb.Min))
planes.append(Plane.CreateByNormalAndOrigin(-XYZ.BasisY,bb.Max))

#Z boundaries
planes.append(Plane.CreateByNormalAndOrigin(XYZ.BasisZ,bb.Min))
planes.append(Plane.CreateByNormalAndOrigin(-XYZ.BasisZ,bb.Max))

filter=PointClouds.PointCloudFilterFactory.CreateMultiPlaneFilter(planes)

points=ptCloud.GetPoints(filter,0.001,999999) #Enumerator
OUT= points.Count      

pointList=[]
for pt in points:
    pointList.append(XYZ(pt.X,pt.Y,0)) 



import System
import clr 
clr.AddReference("System.Windows.Forms")
from System.Windows.Forms import OpenFileDialog, SaveFileDialog

"3). Create a new Text File and get its path: SaveFileDialog()"
dialogSave=System.Windows.Forms.SaveFileDialog()
dialogSave.Filter="File TXT|*.txt" #dialog.Filter="Archivos TXT|*.txt |Archivos CSV|*.csv"
dialogSave.Title= "Select a Text file"
dialogSave.OverwritePrompt= False #You are not overwritting a new file because it is just new!
result =dialogSave.ShowDialog()
if result== System.Windows.Forms.DialogResult.Cancel: #In case you choose to not open any file, Let the system know to do nothing
    pass

#3.1) Write the data:

string=[]
#string.append("Xcoord,Ycoord,Zcoord")
for i in range(0,len(pointList),1):
    a=str(i) + "," + str(pointList[i][0])+","+str(pointList[i][1]) +","+str(pointList[i][2])
    string.append(a)

path=dialogSave.FileName
"4) A Method to write data"
System.IO.File.WriteAllLines(path,string,System.Text.Encoding.UTF8)

 

 

2°Script to get the boundary by using alphashape algorithm

...Using Open3D library among others...

3°Importing the data into Revit

 

 

"2) 1°method to Read the file "
list=System.IO.File.ReadAllLines(path) #read all the lines and keeps it in a list

"2)Place ball element"
boundaryCoord=[]
for line in list:
	listI=map(lambda X: float(X)*3.28084,line.split(","))
	boundaryCoord.append(listI)

famylies=FilteredElementCollector(doc).OfClass(FamilySymbol).ToElements()
ball=None
for f in famylies:
    if f.get_Parameter(BuiltInParameter.SYMBOL_NAME_PARAM).AsString() == "ballXYZ":
        ball=f
tr=Transaction(doc,"placing families")
tr.Start()
for coord in boundaryCoord:
	
	Loc=XYZ(coord[0],coord[1],0)
	doc.Create.NewFamilyInstance(Loc,ball,StructuralType.NonStructural)
tr.Commit()

 

 

 

4). Here is the deviation between the boundaries. 

MiguelGT17_0-1647474462400.png

 

 

The same deal occurred in a previous task that has to be with surface reconstruction. The mesh was placed 30 feet away from the original point cloud data (PCD) location.

MiguelGT17_1-1647474699438.png

We do also deployed the ConvertToInternalUnits method at step (3) to perform units conversion. Any thoughts on this one that heads me into the right direction to import my data correctly?

 

Best Regards,

Miguel G.

 

0 Likes
Accepted solutions (1)
1,072 Views
4 Replies
Replies (4)
Message 2 of 5

mhannonQ65N2
Collaborator
Collaborator

It looks like when you export the points you don't do any conversions from internal units, meaning that the points are exported in internal units. So using ConvertToInternalUnits on data that is already in internal units may produce invalid results. However, I don't see you using that method in the code you posted; it actually looks like you are exporting data in feet then scaling it so that one foot becomes one meter.

 

Another thing to consider is the Transform of the PointCloud. It is possible that the points are defined relative to the point cloud's position. 

Message 3 of 5

MiguelGT17
Advocate
Advocate

Actually, the cloudpoint is using revit system coordinates so it gets exported in Meters as that is the system unit  that has been set to my project.  

MiguelGT17_0-1647646511234.png

I was looking up the GetUnitsToFeetConversionFactor() method as it might have something to do with the deviation issue but I'm confused where the GetScale() method comes from in Jeremy's samples:

https://github.com/jeremytammik/RevitSdkSamples/blob/master/SDK/Samples/PointCloudEngine/CS/FileBase...

MiguelGT17_1-1647647399769.png

Hi @jeremy_tammik !, is there any particular command that gets Revit to pull the exact coordinates from the point cloud data?  I was implementing the implicit operator that converts cloudpoint into an XYZ point but not did not succeed at this: XYZ(Cloudpoint)

MiguelGT17_2-1647648157611.png

and XYZ(cloudpoint.X,cloudpoint.Y,cloudpoint.Z) place the data close to the exact location

MiguelGT17_3-1647648332533.png

 

0 Likes
Message 4 of 5

mhannonQ65N2
Collaborator
Collaborator
Accepted solution

So I looked into Revit point clouds a bit and it looks like different point clouds can define their own units. I can't tell if Revit does any unit conversion when you request points from a point cloud but its possible that Revit will give you the points in whatever units the point cloud is in. However, the NewFamilyInstance method requires an XYZ in feet. In your code (bellow) make sure that Loc is in feet.

	Loc=XYZ(coord[0],coord[1],0)
	doc.Create.NewFamilyInstance(Loc,ball,StructuralType.NonStructural)

 

I suspect that Revit does not take into consideration the transform of the point cloud when it gives you the points data. To quickly test this you could rotate your point cloud by 90° (via the Revit UI) before running your code. If the family instances are still placed where they were when the point cloud isn't rotated, that means that Revit doesn't transform the points into Revit's global coordinate system and you need to either do that yourself before exporting them or transform the location where you place the family instances.

 

The PointCloudType also has an Offset property so I recommend looking into that too. If that property of your point cloud's PointCloudType is about 30 feet, then this is possibly the source of your problem.

Message 5 of 5

MiguelGT17
Advocate
Advocate

Thanks for replying me mhannon! I was not aware of the PointCloudType class. I'm very thankful to you for noticing me that. So far Scale property seems to throw back a pretty curious value. 

MiguelGT17_1-1647878776054.png

The offset property scared me a little bit, but I will see what I can come up with it

MiguelGT17_0-1647878755092.png

 

Actually it's my bad, I assumed that the pointcloud origin was placed at 0,0,0 coordinate but somehow when I import the cloud it gets fit at slightly different origin:

MiguelGT17_0-1647881724469.png

by considering that vector, the points are placed correctly 

MiguelGT17_1-1647881780728.png