- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Taking on another brain crushing task, auto modeling from a point cloud using a simple modeled in place box. I had something similar to this working for topography, looking down in the Z and finding points to generate a topo. Then I thought, well if this can be done in 1 direction why not 6, so, as a test of concept, I created a grid of circles on a box face and use the center points to project into the cloud to generate a mesh. Got that working, now I am trying to programmatically generate a grid of points on each face of my box . Was able to generate equidistant points along the edges, just stuck on how to fill in the area between. Thought divided surface might work, but that seems tied to a pattern, where I just need a grid that I can pull world coords from every point, and have a normal associated so I know which way to look for cloud points. Incrementing circle size on test box just to see where things are starting and ending. Will look at cleaning up the mesh and how to stitch the multiple sides in the future. Also noticed the mesh is flipped inside/out, not sure how to flip the face direction of a mesh, or assign smoothing if that's possible.
Attaching some images, and the code so far.
Manually created field of circles on a plane adjacent to cloud model:
The resulting meshes from the test points, projected from each side:
Current progress on auto generation of points on the box faces:
You just need a point cloud and a modeled in place box, also will need triangulate form GitHub, everything else is out of box Revit API.
The box can have any rotations on any axis.
The icnt and iicnt counters are just to limit the box face receiving the grid for troubleshooting.
For now, until I get it working, I cancel the script after the generation of points on box portion of the code has ran.
public void ModelFromCloudPointsBOX()
{
UIDocument uidoc = this.ActiveUIDocument;
Document doc = uidoc.Document;
Autodesk.Revit.DB.View activev = doc.ActiveView;
Autodesk.Revit.ApplicationServices.Application app = uidoc.Application.Application;
ElementId elementid = null;
elementid = uidoc.Selection.PickObject(ObjectType.Element, "Select Point Cloud To Surface").ElementId;
Element e = doc.GetElement(elementid);
Instance ei = e as Instance;
PointCloudInstance pcInstance = ei as PointCloudInstance;
ElementId belementid = uidoc.Selection.PickObject(ObjectType.Element, "Select BOX enclosing EQUIPMENT to model").ElementId;
Element be = doc.GetElement(belementid);
Instance bei = be as Instance;
using (Autodesk.Revit.DB.Transaction t0 = new Autodesk.Revit.DB.Transaction(doc, "Auto Model Equipment from Point Cloud"))
{
t0.Start();
var geE = (be as FamilyInstance).get_Geometry(new Options() {ComputeReferences = true});
foreach (var geO in geE)
{
if (geO is GeometryInstance)
{
var geI = geO as GeometryInstance;
foreach (var g in geI.GetSymbolGeometry(geI.Transform))
{
var solid = g as Solid;
if (solid != null && solid.Volume>0)
{
int icnt = 0;
foreach (Face geomFace in solid.Faces)
{
if (icnt == 0)
{
XYZ e00 = new XYZ(0,0,0);
XYZ e01 = new XYZ(0,0,0);
double l0 = 0;
EdgeArrayArray earrayarray = geomFace.EdgeLoops;
int iicnt = 0;
foreach (EdgeArray earray in earrayarray)
{
if (iicnt == 0)
{
List<XYZ> allpts = new List<XYZ>();
int counter = 0;
while (counter < earray.Size)
{
Autodesk.Revit.DB.Edge eg = earray.get_Item(counter);
Curve ecurv = eg.AsCurve();
e00 = ecurv.GetEndPoint(0);
e01 = ecurv.GetEndPoint(1);
l0 = ecurv.Length;
UV fuv = new UV(e00.X, e00.Y);
XYZ fnorm = geomFace.ComputeNormal(fuv);
//XYZ midpt = new XYZ((e00.X + e01.X) / 2, (e00.Y + e01.Y) / 2, (e00.Z + e01.Z) / 2);
double dist0 = 1 / l0;
double dist = 0;
XYZ xyz1 = new XYZ(0,0,0);
List<XYZ> pts = new List<XYZ>();
while (dist <= (1 *1.001))
{
xyz1 = new XYZ(((1 - dist) * e00.X + dist * e01.X), ((1 - dist) * e00.Y + dist * e01.Y), ((1 - dist) * e00.Z + dist * e01.Z));
bool pfound = false;
foreach (XYZ point in allpts)
{
if (Math.Round(point.X,2) == Math.Round(xyz1.X,2) & Math.Round(point.Y,2) == Math.Round(xyz1.Y,2) & Math.Round(point.Z,2) == Math.Round(xyz1.Z,2))
{
pfound = true;
}
}
if (pfound == false)
{
allpts.Add(xyz1);
pts.Add(xyz1);
}
dist = dist + dist0;
}
double rad = .05;
foreach (XYZ xyzpt in pts)
{
Autodesk.Revit.DB.Plane plane = Autodesk.Revit.DB.Plane.CreateByNormalAndOrigin(fnorm,xyzpt);
SketchPlane sp = SketchPlane.Create(doc, plane);
doc.ActiveView.SketchPlane = sp;
ModelArc arc = null;
Arc geomarc = Arc.Create(plane, rad, 0, 360);
arc = doc.Create.NewModelCurve(geomarc, sp) as ModelArc;
rad = rad + .05;
}
counter +=1;
}
}
iicnt +=1;
}
}
icnt +=1;
}
}
}
}
}
t0.Commit();
}
// to be replaced by point generation on each box face-----------------------------------------------------------------------------------
IList<Reference> felems = uidoc.Selection.PickObjects(ObjectType.Element, "Select Model Line Circles to Generate Topo Points From");
List<XYZ> tpoints = new List<XYZ>();
using (Autodesk.Revit.DB.Transaction t1 = new Autodesk.Revit.DB.Transaction(doc, "Record Topo Points"))
{
t1.Start();
foreach (Reference eref in felems)
{
ElementId elid = eref.ElementId;
Element el = doc.GetElement(elid);
if (el.Category.Name.Contains("Lines"))
{
ModelArc elfi = el as ModelArc;
Arc arcy = elfi.GeometryCurve as Arc;
if (null != arcy)
{
List<Autodesk.Revit.DB.Plane> planes = new List<Autodesk.Revit.DB.Plane>();
XYZ searchpoint = new XYZ(0, 0, 0);
XYZ adjust = new XYZ(.04, 0, .04);
XYZ adjustz = new XYZ(0, 8, 0);
XYZ adjustmod = new XYZ(.01, 0, .01);
bool pointfound = false;
int counter = 0;
while (counter < 3 & pointfound == false)
{
counter += 1;
pointfound = false;
planes.Clear();
searchpoint = arcy.Center;
// X boundaries
planes.Add(Autodesk.Revit.DB.Plane.CreateByNormalAndOrigin(XYZ.BasisX, searchpoint - adjust));
planes.Add(Autodesk.Revit.DB.Plane.CreateByNormalAndOrigin(-XYZ.BasisX, (searchpoint + adjust)));
// Y boundaries
planes.Add(Autodesk.Revit.DB.Plane.CreateByNormalAndOrigin(XYZ.BasisY, searchpoint - adjustz));
planes.Add(Autodesk.Revit.DB.Plane.CreateByNormalAndOrigin(-XYZ.BasisY, (searchpoint + adjustz)));
// Z boundaries
planes.Add(Autodesk.Revit.DB.Plane.CreateByNormalAndOrigin(XYZ.BasisZ, searchpoint - adjust));
planes.Add(Autodesk.Revit.DB.Plane.CreateByNormalAndOrigin(-XYZ.BasisZ, (searchpoint + adjust)));
// Create filter
PointCloudFilter pcf = PointCloudFilterFactory.CreateMultiPlaneFilter(planes);
var points = pcInstance.GetPoints(pcf, .01, 100);
if (points.Count > 0)
{
pointfound = true;
double zlowpoint = 10000;
foreach (CloudPoint cp in points)
{
if (cp.Y < zlowpoint)
{
zlowpoint = cp.Y;
}
}
double zpoint = zlowpoint * 3.2808;
XYZ tpoint = new XYZ(searchpoint.X, zpoint, searchpoint.Z);
if (tpoints.Count == 0)
{
tpoints.Add(tpoint);
}
var p = tpoints.Count;
p-=1;
bool pmatch = false;
while (p >= 0 & pmatch == false)
{
if (Math.Round(tpoints[p].Z, 6) == Math.Round(tpoint.Z, 6))
{
if (Math.Round(tpoints[p].X, 6) == Math.Round(tpoint.X, 6))
{
pmatch = true;
}
}
p-=1;
}
if (pmatch != true)
{
tpoints.Add(tpoint);
break;
}
}
adjust = adjust + adjustmod;
}
}
}
}
t1.Commit();
}
// Build the Surface ----------------------------------------------------------------------------------------------------------------
FilteredElementCollector collector = new FilteredElementCollector( doc ).OfClass( typeof( Material ) );
IEnumerable<Material> materialsEnum = collector.ToElements().Cast<Material>();
var materialReturn1 = from materialElement in materialsEnum where materialElement.Name == "Default" select materialElement;
Element mat1 = materialReturn1.First();
ElementId materialId = mat1.Id;
List<Triangulator.Geometry.Point> Vertices = new List<Triangulator.Geometry.Point>();
foreach (XYZ coord in tpoints)
{
Triangulator.Geometry.Point pNew = new Triangulator.Geometry.Point(coord.X, coord.Z, coord.Y);
Vertices.Add(pNew);
}
List<Triangulator.Geometry.Triangle> tris = Triangulator.Delauney.Triangulate(Vertices);
List<XYZ> loopVertices = new List<XYZ>(3);
TessellatedShapeBuilder builder = new TessellatedShapeBuilder();
builder.OpenConnectedFaceSet(true);
foreach (Triangle t in tris)
{
loopVertices.Clear();
XYZ newp = new XYZ( ((float)Vertices[t.p1].X),((float)Vertices[t.p1].Z),((float)Vertices[t.p1].Y));
loopVertices.Add(newp);
newp = new XYZ( ((float)Vertices[t.p2].X),((float)Vertices[t.p2].Z),((float)Vertices[t.p2].Y));
loopVertices.Add(newp);
newp = new XYZ( ((float)Vertices[t.p3].X),((float)Vertices[t.p3].Z),((float)Vertices[t.p3].Y));
loopVertices.Add(newp);
builder.AddFace(new TessellatedFace(loopVertices, materialId));
}
builder.CloseConnectedFaceSet();
builder.Build();
TessellatedShapeBuilderResult result = builder.GetBuildResult();
using (Autodesk.Revit.DB.Transaction t3 = new Autodesk.Revit.DB.Transaction(doc, "Create tessellated direct shape"))
{
t3.Start();
DirectShape ds = DirectShape.CreateElement(doc, new ElementId(BuiltInCategory.OST_GenericModel));
ds.ApplicationId = "Application id";
ds.ApplicationDataId = "Geometry object id";
ds.SetShape(result.GetGeometricalObjects());
t3.Commit();
}
}
public void DivideSurface(Document document, Autodesk.Revit.DB.Form form)
{
Autodesk.Revit.ApplicationServices.Application application = document.Application;
Options opt = application.Create.NewGeometryOptions();
opt.ComputeReferences = true;
Autodesk.Revit.DB.GeometryElement geomElem = form.get_Geometry(opt);
foreach (GeometryObject geomObj in geomElem)
{
Solid solid = geomObj as Solid;
foreach (Face face in solid.Faces)
{
if (face.Reference != null)
{
DividedSurface ds = DividedSurface.Create(document,face.Reference);
// create a divided surface with fixed number of U and V grid lines
SpacingRule srU = ds.USpacingRule;
srU.SetLayoutFixedNumber(16, SpacingRuleJustification.Center, 0, 0);
SpacingRule srV = ds.VSpacingRule;
srV.SetLayoutFixedNumber(24, SpacingRuleJustification.Center, 0, 0);
break; // just divide one face of form
}
}
}
}
Solved! Go to Solution.