/// <summary> /// Process point below over the scanLine /// </summary> /// <param name="scanLine">Eeference line used to generate /// points</param> /// <param name="densityOfPoints">Number of points /// per AutoCAD unit of drawing</param> /// <param name="increaseOnStep">Reprocess when a step /// is identified. Used to control recursion</param> private static void ProcessScanLine(LineSegment3d scanLine, int densityOfPoints, bool increaseOnStep) { PointOnCurve3d[] pointsOnDatum = scanLine.GetSamplePoints( (int)(scanLine.Length * densityOfPoints)); Point3d lastPointAdded = Point3d.Origin; foreach (PointOnCurve3d pointOnDatumCurve in pointsOnDatum) { Point3d pointOnDatum = new Point3d( pointOnDatumCurve.Point.ToArray()); double elevationOnSurface = (_surface != null ? _surface.FindElevationAtXY(pointOnDatum.X, pointOnDatum.Y) : // up to elevation of the reference surface _upperLimit); // up to the limit Point3d pointOnSurface = new Point3d( pointOnDatum.X, pointOnDatum.Y, elevationOnSurface); // check if this point is below the solid // by how many hits a vertical line from // this point hit the solid. The lower // Z value is the one. LinearEntity3d lineEnt = new LineSegment3d( pointOnDatum, pointOnSurface); Hit[] hits = _brepSolid.GetLineContainment(lineEnt, 1); if (hits != null) { double lowerZ = hits[0].Point.Z; //double.MaxValue; //foreach (Hit h in hits) //{ // if (h.Point.Z < lowerZ) // lowerZ = h.Point.Z; // h.Dispose(); //} Point3d pointToAdd = new Point3d( pointOnDatum.X, pointOnDatum.Y, lowerZ); _newPoints.Add(pointToAdd); // increase density on steps (big change on elevation)? // ToDo: Need to implement that on the other direction. // This is working only over the scan line direction, // but is also required on the perpendicular if (increaseOnStep) { //skip very first point if (lastPointAdded.DistanceTo(Point3d.Origin) != 0) { if (pointToAdd.DistanceTo(lastPointAdded) > ((1.0 / densityOfPoints) * 10)) { double scanLineElevation = scanLine.StartPoint.Z; Point3d scanLinePt1 = new Point3d( lastPointAdded.X, lastPointAdded.Y, scanLineElevation); Point3d scanLinePt2 = new Point3d( pointToAdd.X, pointToAdd.Y, scanLineElevation); LineSegment3d increaseScanLine = new LineSegment3d( scanLinePt1, scanLinePt2); ProcessScanLine(increaseScanLine, densityOfPoints * 10, false); increaseScanLine.Dispose(); } } lastPointAdded = pointToAdd; } } pointOnDatumCurve.Dispose(); } }
public override void Dispose() => ncadSegment.Dispose();
/// <summary> /// Scan the solid from bottom, identify points and create /// a surface /// </summary> /// <param name="solidId">Solid to scan</param> /// <param name="tinSurfaceToCutId">Referecen surface</param> /// <param name="solidSurfaceName">Name of the new /// surface that will be created</param> /// <param name="densityOfPoints">Number of points per /// AutoCAD unit used on scan</param> /// <param name="simplifySurface">Whether o not simplify /// the surface at the end (using Civil 3D /// built-in operation)</param> private static void GenerateSurfaceByScan( ObjectId solidId, ObjectId tinSurfaceToCutId, string solidSurfaceName, int densityOfPoints, bool simplifySurface) { _db = Application.DocumentManager.MdiActiveDocument.Database; using (_trans = _db.TransactionManager.StartTransaction()) { try { // open entities _solid = _trans.GetObject(solidId, OpenMode.ForRead) as Solid3d; if (!tinSurfaceToCutId.IsNull) { _surface = _trans.GetObject(tinSurfaceToCutId, OpenMode.ForRead) as TinSurface; } // extract the Brep of the solid _brepSolid = new Brep(_solid); _newPoints = new Point3dCollection(); // get the extend of the solid Extents3d extends = _solid.GeometricExtents; // and expand by 20% to increase accuracy // on the solid edges/borders extends.TransformBy(Matrix3d.Scaling(1.2, _solid.MassProperties.Centroid)); // geometric line at the bottom (virtual datum) // this line is the scan line // // x--------------------------x // | pt2 ^ pt3 // | direction // | of scan progress // | // | <-scan line // | // x pt1 // Point3d scanLinePt1 = extends.MinPoint; Point3d scanLinePt2 = new Point3d( scanLinePt1.X, extends.MaxPoint.Y, scanLinePt1.Z); LineSegment3d scanLine = new LineSegment3d( scanLinePt1, scanLinePt2); Point3d scanLinePt3 = new Point3d( extends.MaxPoint.X, extends.MaxPoint.Y, scanLinePt1.Z); _upperLimit = extends.MaxPoint.Z; // scan upper limit int numberOfScanLines = ((int) Math.Round(scanLinePt2.DistanceTo(scanLinePt3), MidpointRounding.ToEven)) * densityOfPoints; ProgressMeter progressBar = new ProgressMeter(); progressBar.SetLimit(numberOfScanLines); progressBar.Start("Scanning solid..."); for (int i = 0; i < numberOfScanLines; i++) { ProcessScanLine(scanLine, densityOfPoints, true); // move the scan line over the scane direction // get direction vector Vector3d scanLineDisplacementDirection = scanLinePt2.GetVectorTo(scanLinePt3); // make unit vector scanLineDisplacementDirection /= scanLineDisplacementDirection.Length; // adjust size scanLineDisplacementDirection *= (1.0 / densityOfPoints); scanLine.TransformBy(Matrix3d.Displacement( scanLineDisplacementDirection)); progressBar.MeterProgress(); Util.AvoidNotResponding(); } progressBar.Stop(); scanLine.Dispose(); #region For testing only #if DEBUG BlockTableRecord mSpace = _trans.GetObject(_db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord; foreach (Point3d pt in _newPoints) { DBPoint p = new DBPoint(pt); mSpace.AppendEntity(p); _trans.AddNewlyCreatedDBObject(p, true); } #endif #endregion CreateSolidSurface(solidSurfaceName, simplifySurface); _trans.Commit(); } catch (System.Exception ex) { Application.DocumentManager.MdiActiveDocument. Editor.WriteMessage("Error: Operation aborted ({0})", ex.Message); _trans.Abort(); } finally { // final cleanup if (!_brepSolid.IsDisposed) { _brepSolid.Dispose(); } if (!_newPoints.IsDisposed) { _newPoints.Dispose(); } _solid = null; _surface = null; _brepSolid = null; _newPoints = null; } } }