A blog for developers programming with Autodesk platforms, particularly AutoCAD and Forge. With a special focus on AR/VR and IoT.

April 08, 2015

AutoCAD 2016: Extracting floorplans from point clouds using .NET

A little while ago you may remember an HTML progress meter I created while looking at “future API features”. The API feature in question was of course for AutoCAD 2016, and related to the extraction of floorplans programmatically using .NET, a topic we’re covering in today’s post.

We’re going to see some fairly basic code that asks AutoCAD to analyse a point cloud – that we’re going to attach from an RCS or RCP file – and generate polyline boundaries for its floorplan.

Now I didn’t actually have a great point cloud to test this, so I ended up using one I’d captured when testing the Kinect v2 sensor:

[On a related note, I’ve been working with a FARO Freestyle3D scanner for the last few weeks: once I publish more on using that I’ll hopefully revisit this code to see how it performs on a more real-world dataset.]

The .NET API has a more rudimentary set of extraction features than the C++ API, during this release: in ObjectARX you have the AcPointCloudExtractedCylinder class, for instance, which presumably means you can use the extraction feature also to extract cylinders rather than just polylines.

Here’s some C# code implementing the EFP command (for ExtractFloorPlan) that makes use of the code in this previous post as well as the HTML progress meter file you can find here:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.Colors;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.Geometry;

using Autodesk.AutoCAD.Runtime;

using System;

namespace PointCloudAnalysis

{

publicclassCommands

{

[CommandMethod("EFP")]

publicvoid ExtractFloorPlan()

{

var doc = Application.DocumentManager.MdiActiveDocument;

var db = doc.Database;

var ed = doc.Editor;

using (var tr = db.TransactionManager.StartTransaction())

{

var msId = SymbolUtilityServices.GetBlockModelSpaceId(db);

// First let's attach the point cloud from the RCS (or RCP)

var pcId =

PointCloudEx.AttachPointCloud(

"c:\\temp\\pc.rcs",

newPoint3d (0,0,1),

1,

0,

db

);

// And get it as a PointCloudEx object

var pc =

tr.GetObject(pcId, OpenMode.ForRead) asPointCloudEx;

// Might also want to adjust MiniumSegmentLength and FillGap

var eo = newExtractOption();

eo.ExtractType = ExtractionType.AllLine;

// Attempt an extraction

try

{

var res =

PointCloudExtractor.Extract(

pc,

Vector3d.ZAxis,

Vector3d.XAxis,

Point3d.Origin,

eo,

newDisplayPointCloudExtractionProgress()

);

// If we have results...

if (res != null)

{

// Add the various polyline profiles to the modelspace

// (and make them red)

var col = Color.FromColorIndex(ColorMethod.ByAci, 1);

var ids =

PointCloudExtractor.AppendPolylineProfile(

res, msId, "0", col, 0.0

);

}

}

catch

{

pc.UpgradeOpen();

pc.Erase();

}

tr.Commit();

}

}

}

publicclassDisplayPointCloudExtractionProgress

: IPointCloudExtractionProgressCallback

{

privateProgressMeterHtml _pm;

privateint _ticks;

privatebool _started;

public DisplayPointCloudExtractionProgress()

{

_pm = newProgressMeterHtml();

_pm.SetLimit(100);

_ticks = 0;

_started = false;

}

publicvoid End()

{

_pm.Stop();

}

publicvoid Cancel()

{

_pm.Cancel();

}

publicbool Cancelled()

{

if (_pm.Cancelled)

{

_pm.AdditionalInfo(" ");

_pm.Stop();

returntrue;

}

returnfalse;

}

publicvoid UpdateRemainTime(double t)

{

if (t > 0)

{

_pm.AdditionalInfo(

Math.Round(t, 2).ToString() + " seconds remaining."

);

}

}

publicvoid UpdateCaption(string s)

{

if (_started)

{

_pm.Caption(s);

}

else

{

_pm.Start(s);

_started = true;

}

}

publicvoid UpdateProgress(int i)

{

while (_ticks < i)

{

_pm.MeterProgress();

System.Windows.Forms.Application.DoEvents();

_ticks++;

}

System.Windows.Forms.Application.DoEvents();

if (i == 100)

{

End();

}

}

}

}

Here’s how the EFP command works when run against the above-mentioned point cloud.

Now let’s take a closer look at the results. You can at least see we have some manner of boundary extracted: if we tweak the extraction options we can presumably increase the accuracy (something we’ll try to look at when we have a properly-captured point cloud of an office space to work with).