public static Solid CreateSphereAt(XYZ center, double radius) { Frame frame = new Frame(center, XYZ.BasisX, XYZ.BasisY, XYZ.BasisZ); // Create a vertical half-circle loop; // this must be in the frame location. Arc arc = Arc.Create( center - radius * XYZ.BasisZ, center + radius * XYZ.BasisZ, center + radius * XYZ.BasisX); Line line = Line.CreateBound( arc.GetEndPoint(1), arc.GetEndPoint(0)); CurveLoop halfCircle = new CurveLoop(); halfCircle.Append(arc); halfCircle.Append(line); List <CurveLoop> loops = new List <CurveLoop>(1); loops.Add(halfCircle); return(GeometryCreationUtilities .CreateRevolvedGeometry( frame, loops, 0, 2 * Math.PI)); }
// Here's a snippet. // It was uploaded to the preview release: // https://feedback.autodesk.com/project/forum/thread.html?cap=cb0fd5af18bb49b791dfa3f5efc[…]01b3deb82a76}&topid={9C3D609F-0A86-4766-BB12-6315F49BCF03} /* * Sample - Edit Floor Sketch.cs * Created by SharpDevelop. * User: t_matva * Date: 11/17/2020 * Time: 11:18 AM * * To change this template use Tools | Options | Coding | Edit Standard Headers. */ //using System; //using Autodesk.Revit.UI; //using Autodesk.Revit.DB; //using Autodesk.Revit.UI.Selection; //using System.Collections.Generic; //using System.Linq; // //namespace Sample //{ // [Autodesk.Revit.Attributes.Transaction( Autodesk.Revit.Attributes.TransactionMode.Manual )] // [Autodesk.Revit.DB.Macros.AddInId( "994A64E6-839B-4C1F-B473-1E7C614A5455" )] // public partial class ThisDocument // { // private void Module_Startup( object sender, EventArgs e ) // { // } // // private void Module_Shutdown( object sender, EventArgs e ) // { // } // // #region Revit Macros generated code // private void InternalStartup() // { // this.Startup += new System.EventHandler( Module_Startup ); // this.Shutdown += new System.EventHandler( Module_Shutdown ); // } // #endregion public void CreateFloor(Document doc) { Curve left = Line.CreateBound(new XYZ(0, 0, 0), new XYZ(0, 100, 0)); Curve upper = Line.CreateBound(new XYZ(0, 100, 0), new XYZ(100, 100, 0)); Curve right = Line.CreateBound(new XYZ(100, 100, 0), new XYZ(100, 0, 0)); Curve lower = Line.CreateBound(new XYZ(100, 0, 0), new XYZ(0, 0, 0)); CurveLoop floorProfile = new CurveLoop(); floorProfile.Append(left); floorProfile.Append(upper); floorProfile.Append(right); floorProfile.Append(lower); ElementId levelId = Level.GetNearestLevelId(doc, 0.0); using (Transaction transaction = new Transaction(doc)) { transaction.Start("Create floor"); ElementId floorTypeId = Floor.GetDefaultFloorType(doc, false); Floor floor = Floor.Create(doc, new List <CurveLoop>() { floorProfile }, floorTypeId, levelId); transaction.Commit(); } }
/// <summary> /// Create a centerbased cylinder, only on X, Y, Z three axes forward direction /// </summary> /// <param name="center">The given cylinder center</param> /// <param name="bottomradius">The given cylinder's bottom radius</param> /// <param name="height">The given cylinder's height</param> /// <param name="cylinderdirection">Cylinder's extrusion direction</param> /// <returns>The created cylinder</returns> public Solid CreateCenterbasedCylinder(XYZ center, double bottomradius, double height, CylinderDirection cylinderdirection) { double halfheight = height / 2.0; XYZ bottomcenter = new XYZ( cylinderdirection == CylinderDirection.BasisX ? center.X - halfheight : center.X, cylinderdirection == CylinderDirection.BasisY ? center.Y - halfheight : center.Y, cylinderdirection == CylinderDirection.BasisZ ? center.Z - halfheight : center.Z); XYZ topcenter = new XYZ( cylinderdirection == CylinderDirection.BasisX ? center.X + halfheight : center.X, cylinderdirection == CylinderDirection.BasisY ? center.Y + halfheight : center.Y, cylinderdirection == CylinderDirection.BasisZ ? center.Z + halfheight : center.Z); CurveLoop sweepPath = new CurveLoop(); sweepPath.Append(Line.CreateBound(bottomcenter, topcenter)); List <CurveLoop> profileloops = new List <CurveLoop>(); CurveLoop profileloop = new CurveLoop(); Ellipse cemiEllipse1 = Ellipse.Create(bottomcenter, bottomradius, bottomradius, cylinderdirection == CylinderDirection.BasisX ? Autodesk.Revit.DB.XYZ.BasisY : Autodesk.Revit.DB.XYZ.BasisX, cylinderdirection == CylinderDirection.BasisZ ? Autodesk.Revit.DB.XYZ.BasisY : Autodesk.Revit.DB.XYZ.BasisZ, -Math.PI, 0); Ellipse cemiEllipse2 = Ellipse.Create(bottomcenter, bottomradius, bottomradius, cylinderdirection == CylinderDirection.BasisX ? Autodesk.Revit.DB.XYZ.BasisY : Autodesk.Revit.DB.XYZ.BasisX, cylinderdirection == CylinderDirection.BasisZ ? Autodesk.Revit.DB.XYZ.BasisY : Autodesk.Revit.DB.XYZ.BasisZ, 0, Math.PI); profileloop.Append(cemiEllipse1); profileloop.Append(cemiEllipse2); profileloops.Add(profileloop); return(GeometryCreationUtilities.CreateSweptGeometry(sweepPath, 0, 0, profileloops)); }
public void solidBeamFinder(Document doc, XYZ startOfInterest, double solidHeight, out List <ElementId> beamIds) { beamIds = new List <ElementId>(); double radius = 0.1; XYZ arcCenter = new XYZ(startOfInterest.X, startOfInterest.Y, startOfInterest.Z); //Build a solid cylinder // Create a vertical half-circle loop in the frame location. List <CurveLoop> curveloops = new List <CurveLoop>(); CurveLoop circle = new CurveLoop(); circle.Append(Arc.Create(arcCenter, radius, 0, Math.PI, XYZ.BasisX, XYZ.BasisY)); circle.Append(Arc.Create(arcCenter, radius, Math.PI, 2 * Math.PI, XYZ.BasisX, XYZ.BasisY)); curveloops.Add(circle); Solid cylinder = GeometryCreationUtilities.CreateExtrusionGeometry(curveloops, XYZ.BasisZ, (solidHeight)); //PaintSolid(commandData, cylinder, 5); //Find beam IEnumerable <Element> beams = new FilteredElementCollector(doc) .OfClass(typeof(FamilyInstance)) .OfCategory(BuiltInCategory.OST_StructuralFraming) .WherePasses(new ElementIntersectsSolidFilter(cylinder)); if (beams.Count() > 0) { foreach (Element e in beams) { beamIds.Add(e.Id); } } }
/// <summary> /// Create and return a solid sphere with /// a given radius and centre point. /// </summary> public static Solid CreateSphereAt(XYZ centre, double radius) { // Use the standard global coordinate system // as a frame, translated to the sphere centre. Frame frame = new Frame(centre, XYZ.BasisX, XYZ.BasisY, XYZ.BasisZ); // Create a vertical half-circle loop; // this must be in the frame location. Arc arc = Arc.Create( centre - radius * XYZ.BasisZ, centre + radius * XYZ.BasisZ, centre + radius * XYZ.BasisX); Line line = Line.CreateBound( arc.GetEndPoint(1), arc.GetEndPoint(0)); CurveLoop halfCircle = new CurveLoop(); halfCircle.Append(arc); halfCircle.Append(line); List <CurveLoop> loops = new List <CurveLoop>(1); loops.Add(halfCircle); return(GeometryCreationUtilities .CreateRevolvedGeometry( frame, loops, 0, 2 * Math.PI)); }
/// <summary> /// Find the nearby walls on specific point and in specific height /// </summary> /// <param name="point">The given point</param> /// <param name="height">The given height</param> /// <param name="radius">The radius in which walls can be detected</param> /// <returns>The detection result</returns> private FilteredElementCollector nearbyWallsFilter(XYZ point, double height, double radius) { // build cylindrical shape around wall endpoint List <CurveLoop> curveloops = new List <CurveLoop>(); CurveLoop circle = new CurveLoop(); circle.Append(Arc.Create(point, radius , 0, Math.PI, XYZ.BasisX, XYZ.BasisY)); circle.Append(Arc.Create(point, radius , Math.PI, 2 * Math.PI, XYZ.BasisX, XYZ.BasisY)); curveloops.Add(circle); Solid wallEndCylinder = GeometryCreationUtilities.CreateExtrusionGeometry(curveloops, XYZ.BasisZ, height); // Iterate document to find walls FilteredElementCollector collector = new FilteredElementCollector(m_doc); collector.OfCategory(BuiltInCategory.OST_Walls); // Apply geometric filter ElementIntersectsSolidFilter testElementIntersectsSolidFilter = new ElementIntersectsSolidFilter(wallEndCylinder); collector.WherePasses(testElementIntersectsSolidFilter); return(collector); }
public static Solid Box( ) { XYZ btmLeft = new XYZ(-0.5, -0.5, 0); XYZ topRight = new XYZ(0.5, 0.5, 0); XYZ btmRight = new XYZ(topRight.X, btmLeft.Y, 0); XYZ topLeft = new XYZ(btmLeft.X, topRight.Y, 0); Curve btm = Line.CreateBound(btmLeft, btmRight) as Curve; Curve right = Line.CreateBound(btmRight, topRight) as Curve; Curve top = Line.CreateBound(topRight, topLeft) as Curve; Curve left = Line.CreateBound(topLeft, btmLeft) as Curve; CurveLoop crvLoop = new CurveLoop(); crvLoop.Append(btm); crvLoop.Append(right); crvLoop.Append(top); crvLoop.Append(left); IList <CurveLoop> cl = new List <CurveLoop>(); cl.Add(crvLoop); Solid box = GeometryCreationUtilities.CreateExtrusionGeometry(cl, XYZ.BasisZ, 1); return(box); }
public static Solid Sphere() { XYZ center = new XYZ(0, 0, 0.5); double radius = 0.75; // Use the standard global coordinate system // as a frame, translated to the sphere bottom. Frame frame = new Frame(center, XYZ.BasisX, XYZ.BasisY, XYZ.BasisZ); // Create a vertical half-circle loop; // this must be in the frame location. XYZ start = center - radius * XYZ.BasisZ; XYZ end = center + radius * XYZ.BasisZ; XYZ XyzOnArc = center + radius * XYZ.BasisX; Arc arc = Arc.Create(start, end, XyzOnArc); Line line = Line.CreateBound(arc.GetEndPoint(1), arc.GetEndPoint(0)); CurveLoop halfCircle = new CurveLoop(); halfCircle.Append(arc); halfCircle.Append(line); List <CurveLoop> loops = new List <CurveLoop>(1); loops.Add(halfCircle); return(GeometryCreationUtilities.CreateRevolvedGeometry(frame, loops, 0, 2 * Math.PI)); }
/// <summary> /// Creates an Analytiocal Panel /// </summary> /// <param name="revitDoc">Revit documenr</param> /// <returns></returns> public static AnalyticalPanel CreateAMPanel(Document revitDoc) { AnalyticalPanel analyticalPanel = null; using (Transaction transaction = new Transaction(revitDoc, "Create Analytical Panel")) { transaction.Start(); //create curveloop which will be assigned to the analytical panel CurveLoop profileloop = new CurveLoop(); profileloop.Append(Line.CreateBound( new XYZ(0, 0, 0), new XYZ(5, 0, 0))); profileloop.Append(Line.CreateBound( new XYZ(5, 0, 0), new XYZ(5, 5, 0))); profileloop.Append(Line.CreateBound( new XYZ(5, 5, 0), new XYZ(0, 5, 0))); profileloop.Append(Line.CreateBound( new XYZ(0, 5, 0), new XYZ(0, 0, 0))); //create the AnalyticalPanel analyticalPanel = AnalyticalPanel.Create(revitDoc, profileloop); analyticalPanel.StructuralRole = AnalyticalStructuralRole.StructuralRoleFloor; analyticalPanel.AnalyzeAs = AnalyzeAs.SlabOneWay; transaction.Commit(); } return(analyticalPanel); }
/// <summary> /// creates an AnalyticalOpening element which will be placed on the AnalyticalPanel /// with id = panelId /// </summary> public static AnalyticalOpening CreateAMOpening(Document revitDoc, ElementId panelId) { if (panelId == ElementId.InvalidElementId) { return(null); } AnalyticalOpening opening = null; using (Transaction transaction = new Transaction(revitDoc, "Create Analytical Opening")) { transaction.Start(); //create the curveLoop for the AnalyticalOpening element CurveLoop profileloop = new CurveLoop(); profileloop.Append(Line.CreateBound( new XYZ(1, 1, 0), new XYZ(2, 1, 0))); profileloop.Append(Line.CreateBound( new XYZ(2, 1, 0), new XYZ(2, 2, 0))); profileloop.Append(Line.CreateBound( new XYZ(2, 2, 0), new XYZ(-1, 2, 0))); profileloop.Append(Line.CreateBound( new XYZ(-1, 2, 0), new XYZ(1, 1, 0))); if (AnalyticalOpening.IsCurveLoopValidForAnalyticalOpening(profileloop, revitDoc, panelId)) { //create the AnalyticalOpening opening = AnalyticalOpening.Create(revitDoc, profileloop, panelId); } transaction.Commit(); } return(opening); }
private void AddCurveToLoopInternal(CurveLoop curveLoop, Curve curve, bool initialReverse, bool tryReversed) { try { if (tryReversed != initialReverse) { curveLoop.Append(curve.CreateReversed()); } else { curveLoop.Append(curve); } } catch (Exception ex) { if (ex.Message.Contains("not contiguous")) { if (!tryReversed) { AddCurveToLoopInternal(curveLoop, curve, initialReverse, true); } else { throw ex; } } } }
//Build solid public void incrementIntercetor(Document doc, XYZ startOfInterest, Parameter zOffsetVar, out ElementId columnId, out ElementId beamId) { columnId = null; beamId = null; double radius = 0; double limit = 0.75; double zOffset = zOffsetVar.AsDouble(); //lower arc center double centerZ = (startOfInterest.Z + zOffset) - 0.25; XYZ arcCenter = new XYZ(startOfInterest.X, startOfInterest.Y, centerZ); //Build a solid cylinder for (radius = .125; radius < limit; radius = radius + 0.1) { // Create a vertical half-circle loop in the frame location. List <CurveLoop> curveloops = new List <CurveLoop>(); CurveLoop circle = new CurveLoop(); circle.Append(Arc.Create(arcCenter, radius, 0, Math.PI, XYZ.BasisX, XYZ.BasisY)); circle.Append(Arc.Create(arcCenter, radius, Math.PI, 2 * Math.PI, XYZ.BasisX, XYZ.BasisY)); curveloops.Add(circle); Solid cylinder = GeometryCreationUtilities.CreateExtrusionGeometry(curveloops, XYZ.BasisZ, (0.25)); //PaintSolid(commandData, cylinder, 5); //Find column IEnumerable <Element> columns = new FilteredElementCollector(doc) .OfClass(typeof(FamilyInstance)) .OfCategory(BuiltInCategory.OST_StructuralColumns) .WherePasses(new ElementIntersectsSolidFilter(cylinder)); if (columns.Count() > 0) { foreach (Element e in columns) { FamilyInstance fi = e as FamilyInstance; FamilySymbol fs = fi.Symbol; columnId = e.Id; } break; } //Find beam IEnumerable <Element> beams = new FilteredElementCollector(doc) .OfClass(typeof(FamilyInstance)) .OfCategory(BuiltInCategory.OST_StructuralFraming) .WherePasses(new ElementIntersectsSolidFilter(cylinder)); if (beams.Count() > 0) { foreach (Element e in beams) { FamilyInstance fi = e as FamilyInstance; FamilySymbol fs = fi.Symbol; beamId = e.Id; } break; } } //End of loop }
/// <summary> /// Create a centerbased box /// </summary> /// <param name="center">The given box center</param> /// <param name="edgelength">The given box's edge length</param> /// <returns>The created box</returns> public Solid CreateCenterbasedBox(XYZ center, double edgelength) { double halfedgelength = edgelength / 2.0; List <CurveLoop> profileloops = new List <CurveLoop>(); CurveLoop profileloop = new CurveLoop(); profileloop.Append(Line.CreateBound( new XYZ(center.X - halfedgelength, center.Y - halfedgelength, center.Z - halfedgelength), new XYZ(center.X - halfedgelength, center.Y + halfedgelength, center.Z - halfedgelength))); profileloop.Append(Line.CreateBound( new XYZ(center.X - halfedgelength, center.Y + halfedgelength, center.Z - halfedgelength), new XYZ(center.X + halfedgelength, center.Y + halfedgelength, center.Z - halfedgelength))); profileloop.Append(Line.CreateBound( new XYZ(center.X + halfedgelength, center.Y + halfedgelength, center.Z - halfedgelength), new XYZ(center.X + halfedgelength, center.Y - halfedgelength, center.Z - halfedgelength))); profileloop.Append(Line.CreateBound( new XYZ(center.X + halfedgelength, center.Y - halfedgelength, center.Z - halfedgelength), new XYZ(center.X - halfedgelength, center.Y - halfedgelength, center.Z - halfedgelength))); profileloops.Add(profileloop); XYZ extrusiondir = new XYZ(0, 0, 1); // orthogonal double extrusiondist = edgelength; return(GeometryCreationUtilities.CreateExtrusionGeometry(profileloops, extrusiondir, extrusiondist)); }
/// <summary> /// Converts the CurveArray to the CurveLoop. /// </summary> /// <param name="curves"></param> /// <returns></returns> public static CurveLoop ToCurveLoop <T>(this IEnumerable <T> curves) where T : Curve { var newCurves = curves.ToList(); if (curves == null || newCurves.Count == 0) { throw new NullReferenceException(nameof(newCurves)); } var results = new CurveLoop(); var endPt = newCurves[0]?.GetEndPoint(1); results.Append(newCurves[0]); newCurves[0] = null; // If computing count equals curveLoop count, it should break. // Because, the curveLoop cannot find valid curve to append. var count = 0; while (count < newCurves.Count && results.Count() < newCurves.Count) { for (var i = 0; i < newCurves.Count; i++) { if (newCurves[i] == null) { continue; } var p0 = newCurves[i].GetEndPoint(0); var p1 = newCurves[i].GetEndPoint(1); if (p0.IsAlmostEqualTo(endPt)) { endPt = p1; results.Append(newCurves[i]); newCurves[i] = null; } // The curve should be reversed. else if (p1.IsAlmostEqualTo(endPt)) { endPt = p0; results.Append(newCurves[i].CreateReversed()); newCurves[i] = null; } } count++; } return(results); }
static public CurveLoop CreateCurveLoop(this Curve firstCurve, Curve secondCurve) { CurveLoop curveLoop = new CurveLoop(); curveLoop.Append(firstCurve.CreateReversed()); curveLoop.Append(Line.CreateBound(firstCurve.GetEndPoint(0), secondCurve.GetEndPoint(0))); curveLoop.Append(secondCurve); curveLoop.Append(Line.CreateBound(secondCurve.GetEndPoint(1), firstCurve.GetEndPoint(1))); return(curveLoop); }
public static CurveLoop CreateCurveLoop(List <XYZ> pts) { int n = pts.Count; CurveLoop curveLoop = new CurveLoop(); for (int i = 1; i < n; ++i) { curveLoop.Append(Line.CreateBound(pts[i - 1], pts[i])); } curveLoop.Append(Line.CreateBound(pts[n], pts[0])); return(curveLoop); }
public static Solid CreateSphereAt(XYZ centre, double radius) { Frame coordinateFrame = new Frame(centre, XYZ.BasisX, XYZ.BasisY, XYZ.BasisZ); Arc arc = Arc.Create(centre - radius * XYZ.BasisZ, centre + radius * XYZ.BasisZ, centre + radius * XYZ.BasisX); Line curve = Line.CreateBound(arc.GetEndPoint(1), arc.GetEndPoint(0)); CurveLoop curveLoop = new CurveLoop(); curveLoop.Append(arc); curveLoop.Append(curve); List<CurveLoop> list = new List<CurveLoop>(1); list.Add(curveLoop); return GeometryCreationUtilities.CreateRevolvedGeometry(coordinateFrame, list, 0.0, 6.2831853071795862); }
public static IList <Solid> CreateSolid(Document doc, FamilyInstance familyInstance, Transform transform) { IList <Solid> solids = new List <Solid>(); try { Curve curve = GetCurvemaxfamily(familyInstance); Element ele = doc.GetElement(familyInstance.Id); string[] parameters = new string[] { "DIM_WWF_YY", "DIM_LENGTH" }; Parameter pa = LookupElementParameter(ele, parameters); double lengthcurve = pa.AsDouble(); XYZ starpointfa = new XYZ(lengthcurve / 2, 0, 0); XYZ endpointfa = new XYZ(-lengthcurve / 2, 0, 0); XYZ startpoint = transform.OfPoint(starpointfa); XYZ endpoint = transform.OfPoint(endpointfa); XYZ norm = new XYZ((startpoint.X - endpoint.X), (startpoint.Y - endpoint.Y), (startpoint.Z - endpoint.Z)); Plane plane = Plane.CreateByNormalAndOrigin(norm, startpoint); Transaction newtran = new Transaction(doc, "ss"); newtran.Start(); SketchPlane stk = SketchPlane.Create(doc, plane); XYZ pt1 = startpoint.Add(0.01 * plane.XVec).Add(0.01 * plane.YVec); XYZ pt2 = startpoint.Add(0.01 * plane.YVec); XYZ pt3 = startpoint.Add(-0.01 * plane.YVec); XYZ pt4 = startpoint.Add(0.01 * plane.XVec).Add(-0.01 * plane.YVec); XYZ pt5 = (-1) * norm; Line lineleft = Line.CreateBound(pt1, pt2); Line linetop = Line.CreateBound(pt2, pt3); Line lineright = Line.CreateBound(pt3, pt4); Line linebot = Line.CreateBound(pt4, pt1); CurveLoop profile = new CurveLoop(); profile.Append(lineleft); profile.Append(linetop); profile.Append(lineright); profile.Append(linebot); IList <CurveLoop> listloop1 = new List <CurveLoop>(); listloop1.Add(profile); Solid solid = GeometryCreationUtilities.CreateExtrusionGeometry(listloop1, pt5, lengthcurve); newtran.Commit(); solids.Add(solid); } catch { solids = null; } return(solids); }
public static Solid CreateSphereAt(XYZ centre, double radius) { Frame frame = new Frame(centre, XYZ.BasisX, XYZ.BasisY, XYZ.BasisZ); Arc arc = Arc.Create(centre - radius * XYZ.BasisZ, centre + radius * XYZ.BasisZ, centre + radius * XYZ.BasisX); Line line = Line.CreateBound(arc.GetEndPoint(1), arc.GetEndPoint(0)); CurveLoop curveLoop = new CurveLoop(); curveLoop.Append(arc); curveLoop.Append(line); return(GeometryCreationUtilities.CreateRevolvedGeometry(frame, new List <CurveLoop>(1) { curveLoop }, 0.0, 6.2831853071795862)); }
private static Solid CreateSphereAt(XYZ centre, double radius) { Frame frame = new Frame(centre, XYZ.get_BasisX(), XYZ.get_BasisY(), XYZ.get_BasisZ()); Arc arc = Arc.Create(XYZ.op_Subtraction(centre, XYZ.op_Multiply(radius, XYZ.get_BasisZ())), XYZ.op_Addition(centre, XYZ.op_Multiply(radius, XYZ.get_BasisZ())), XYZ.op_Addition(centre, XYZ.op_Multiply(radius, XYZ.get_BasisX()))); Line bound = Line.CreateBound(((Curve)arc).GetEndPoint(1), ((Curve)arc).GetEndPoint(0)); CurveLoop curveLoop = new CurveLoop(); curveLoop.Append((Curve)arc); curveLoop.Append((Curve)bound); List <CurveLoop> curveLoopList = new List <CurveLoop>(1); curveLoopList.Add(curveLoop); return(GeometryCreationUtilities.CreateRevolvedGeometry(frame, (IList <CurveLoop>)curveLoopList, 0.0, 2.0 * Math.PI)); }
private DirectShape RunBuilding(Document doc, Way building, Dictionary <long?, OsmGeo> allNodes) { var points = this.geometryService.GetPointsFromNodes(building.Nodes, allNodes); if (points == null) { return(null); } var curveLoop = new CurveLoop(); for (int i = 0; i < points.Count - 1; i++) { Line line = Line.CreateBound(points[i], points[i + 1]); curveLoop.Append(line); } var heightTag = building.Tags.FirstOrDefault(tag => tag.Key == "height"); var heightFeet = UnitUtils.ConvertToInternalUnits(3, DisplayUnitType.DUT_METERS); if (double.TryParse(heightTag.Value, out double heightMeters)) { heightFeet = UnitUtils.ConvertToInternalUnits(heightMeters, DisplayUnitType.DUT_METERS); } return(shapeService.Build(doc, new List <CurveLoop> { curveLoop }, heightFeet, new ElementId(BuiltInCategory.OST_GenericModel))); }
public static Autodesk.Revit.DB.CurveLoop ToRevitType(this Autodesk.DesignScript.Geometry.PolyCurve pcrv, bool performHostUnitConversion = true) { if (!pcrv.IsClosed) { throw new Exception("The input PolyCurve must be closed"); } Autodesk.DesignScript.Geometry.Curve[] crvs = null; if (performHostUnitConversion) { pcrv = pcrv.InHostUnits(); crvs = pcrv.Curves(); pcrv.Dispose(); } else { crvs = pcrv.Curves(); } var cl = new CurveLoop(); foreach (Autodesk.DesignScript.Geometry.Curve curve in crvs) { using (var nc = curve.ToNurbsCurve()) { Autodesk.Revit.DB.Curve converted = nc.ToRevitType(false); cl.Append(converted); } } crvs.ForEach(x => x.Dispose()); return(cl); }
private static void CreateFilledRegion(Document doc, SpatialObjectWrapper so) { try { var filledRegionType = new FilteredElementCollector(doc).OfClass(typeof(FilledRegionType)).FirstElementId(); if (filledRegionType == null || filledRegionType == ElementId.InvalidElementId) { return; } var curves = new List <CurveLoop>(); var loop = new CurveLoop(); foreach (var curve in so.Room2D.FloorBoundary.GetCurves(so.Level.Elevation)) { //doc.Create.NewDetailCurve(doc.ActiveView, curve); loop.Append(curve); } curves.Add(loop); FilledRegion.Create(doc, filledRegionType, doc.ActiveView.Id, curves); } catch (Exception e) { _logger.Fatal(e); } }
public void CropAroundRoom(Room room, View view) //This provides the required shape now how to combine with the offset and tie into wall thickness { if (view != null) { IList <IList <BoundarySegment> > segments = room.GetBoundarySegments(new SpatialElementBoundaryOptions()); if (null != segments) //the room may not be bound { foreach (IList <BoundarySegment> segmentList in segments) { CurveLoop loop = new CurveLoop(); foreach (BoundarySegment boundarySegment in segmentList) { List <XYZ> points = boundarySegment.GetCurve().Tessellate().ToList(); for (int ip = 0; ip < points.Count - 1; ip++) { Line l = Line.CreateBound(points[ip], points[ip + 1]); loop.Append(l); } } ViewCropRegionShapeManager vcrShapeMgr = view.GetCropRegionShapeManager(); bool cropValid = vcrShapeMgr.IsCropRegionShapeValid(loop); if (cropValid) { vcrShapeMgr.SetCropShape(loop); break; // if more than one set of boundary segments for room, crop around the first one } } } } }
private DirectShape RunBuilding(Document doc, Way building, Dictionary <long?, OsmGeo> allNodes) { var points = new List <XYZ>(); foreach (var nodeId in building.Nodes) { var geometry = allNodes[nodeId]; if (geometry is Node node) { var coords = coordService.GetRevitCoords((double)node.Latitude, (double)node.Longitude); points.Add(coords); } } var curveLoop = new CurveLoop(); for (int i = 0; i < points.Count - 1; i++) { Line line = Line.CreateBound(points[i], points[i + 1]); curveLoop.Append(line); } var heightTag = building.Tags.FirstOrDefault(tag => tag.Key == "height"); var heightFeet = UnitUtils.ConvertToInternalUnits(3, DisplayUnitType.DUT_METERS); if (double.TryParse(heightTag.Value, out double heightMeters)) { heightFeet = UnitUtils.ConvertToInternalUnits(heightMeters, DisplayUnitType.DUT_METERS); } return(shapeService.Build(doc, new List <CurveLoop> { curveLoop }, heightFeet, new ElementId(BuiltInCategory.OST_GenericModel))); }
/***************************************************/ private static void AddLoop(this BRepBuilder brep, BRepBuilderGeometryId face, XYZ normal, ICurve curve, bool external) { CurveLoop cl = new CurveLoop(); foreach (ICurve sp in curve.ISubParts()) { foreach (Curve cc in sp.IToRevitCurves()) { cl.Append(cc); } } if (external != cl.IsCounterclockwise(normal)) { cl.Flip(); } BRepBuilderGeometryId loop = brep.AddLoop(face); foreach (Curve cc in cl) { BRepBuilderGeometryId edge = brep.AddEdge(BRepBuilderEdgeGeometry.Create(cc)); brep.AddCoEdge(loop, edge, false); } brep.FinishLoop(loop); }
/// <summary> /// Construct a Revit FilledRegion element by Curves /// </summary> /// <param name="view">View to place filled region on</param> /// <param name="boundary">Boundary curves</param> /// <param name="regionType">Region Type</param> /// <returns></returns> public static FilledRegion ByCurves(Revit.Elements.Views.View view, IEnumerable <Autodesk.DesignScript.Geometry.Curve> boundary, FilledRegionType regionType) { Autodesk.Revit.DB.FilledRegionType type = regionType.InternalRevitElement; CurveLoop loop = new CurveLoop(); foreach (Autodesk.DesignScript.Geometry.Curve curve in boundary) { loop.Append(curve.ToRevitType()); } if (loop.IsOpen()) { throw new Exception(Properties.Resources.CurveLoopNotClosed); } Autodesk.Revit.DB.View revitView = (Autodesk.Revit.DB.View)view.InternalElement; if (!view.IsAnnotationView()) { throw new Exception(Properties.Resources.ViewDoesNotSupportAnnotations); } return(new FilledRegion(revitView, type.Id, new List <CurveLoop>() { loop })); }
/// <summary> /// 调整viewPlan的尺寸并贴合选中房间 /// change a viewPlan to fix the selected room /// </summary> /// <param name="view"></param> /// <param name="tran"></param> /// <param name="viewOffseet"></param> public void ChangeViewFitRoom(ViewPlan view, Transaction tran, double viewOffseet) { if (view == null) { TaskDialog.Show("viewIsNull", "Can't find the type of View."); return; } //获得并设定房间的边界设定,并获取其边界集 DocSet.uidoc.ActiveView = view; SpatialElementBoundaryOptions opt = new SpatialElementBoundaryOptions(); opt.SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Center;//房间边界设定,能变更获取的边界位置 IList <IList <BoundarySegment> > segments = DocSet.selRoom.GetBoundarySegments(opt); if (segments == null) { TaskDialog.Show("segementsIsNull", "can't get the BoundarySegment of room"); return; } ViewCropRegionShapeManager vcrShanpMgr = view.GetCropRegionShapeManager(); CurveLoop loop = new CurveLoop(); foreach (IList <BoundarySegment> segmentList in segments) { foreach (BoundarySegment segment in segmentList) { Curve curve = segment.GetCurve(); loop.Append(curve); } bool cropValid = vcrShanpMgr.IsCropRegionShapeValid(loop); if (cropValid) { //默认矩形 //TaskDialog.Show("cropValid", "the crop is shape Valid"); tran.Start("change the view crop region"); vcrShanpMgr.SetCropShape(loop); tran.Commit(); tran.Start("Remove Crop Region Shape"); vcrShanpMgr.RemoveCropRegionShape(); tran.Commit(); //TaskDialog.Show("ChangeView", "ChangeViewdone"); break; } } tran.Start("loop offset"); //TaskDialog.Show("!!!", "changeloop!"); loop = CurveLoop.CreateViaOffset(vcrShanpMgr.GetCropShape().First(), -1 * viewOffseet / 300, new XYZ(0, 0, 1)); vcrShanpMgr.SetCropShape(loop); tran.Commit(); DocSet.uidoc.ActiveView = view; }
private Solid FindCeilingSolid(Element ceiling) { Solid ceilingSolid = null; try { var opt = m_app.Application.Create.NewGeometryOptions(); opt.ComputeReferences = true; opt.IncludeNonVisibleObjects = true; var geomElem = ceiling.get_Geometry(opt); foreach (var obj in geomElem) { var solid = obj as Solid; if (null != solid) { if (solid.Volume > 0) { ceilingSolid = solid; break; } else { var curveLoopList = new List <CurveLoop>(); XYZ normal = null; foreach (Face face in solid.Faces) { if (face.EdgeLoops.Size > 0) { normal = face.ComputeNormal(new UV(0, 0)); foreach (EdgeArray edgeArray in face.EdgeLoops) { var curveLoop = new CurveLoop(); foreach (Edge edge in edgeArray) { curveLoop.Append(edge.AsCurve()); } curveLoopList.Add(curveLoop); } } } var extrusion = GeometryCreationUtilities.CreateExtrusionGeometry(curveLoopList, normal, 1); if (extrusion.Volume > 0) { ceilingSolid = extrusion; break; } } } } } catch (Exception ex) { MessageBox.Show("Could not find the solid of the ceiling.\n" + ex.Message, "FindCeilingSolid", MessageBoxButtons.OK, MessageBoxIcon.Warning); } return(ceilingSolid); }
private IList <CurveLoop> CreateProfileCurveLoopsForDirectrix(Curve directrix, out double startParam) { startParam = 0.0; if (directrix == null) { return(null); } if (directrix.IsBound) { startParam = directrix.GetEndParameter(0); } Transform originTrf = directrix.ComputeDerivatives(startParam, false); if (originTrf == null) { return(null); } // The X-dir of the transform of the start of the directrix will form the normal of the disk. // We are not using the origin in Plane.CreateByNormalAndOrigin because that has // limits of [-30K,30K]. Plane diskPlaneAxes = Plane.CreateByNormalAndOrigin(originTrf.BasisX, XYZ.Zero); IList <CurveLoop> profileCurveLoops = new List <CurveLoop>(); CurveLoop diskOuterCurveLoop = new CurveLoop(); diskOuterCurveLoop.Append(Arc.Create(originTrf.Origin, Radius, 0, Math.PI, diskPlaneAxes.XVec, diskPlaneAxes.YVec)); diskOuterCurveLoop.Append(Arc.Create(originTrf.Origin, Radius, Math.PI, 2.0 * Math.PI, diskPlaneAxes.XVec, diskPlaneAxes.YVec)); profileCurveLoops.Add(diskOuterCurveLoop); if (InnerRadius.HasValue) { CurveLoop diskInnerCurveLoop = new CurveLoop(); diskInnerCurveLoop.Append(Arc.Create(originTrf.Origin, InnerRadius.Value, 0, Math.PI, diskPlaneAxes.XVec, diskPlaneAxes.YVec)); diskInnerCurveLoop.Append(Arc.Create(originTrf.Origin, InnerRadius.Value, Math.PI, 2.0 * Math.PI, diskPlaneAxes.XVec, diskPlaneAxes.YVec)); profileCurveLoops.Add(diskInnerCurveLoop); } return(profileCurveLoops); }
public static Plane GetPlaneFromCurve(Curve c, bool planarOnly) { //find the plane of the curve and generate a sketch plane double period = c.IsBound ? 0.0 : (c.IsCyclic ? c.Period : 1.0); var p0 = c.IsBound ? c.Evaluate(0.0, true) : c.Evaluate(0.0, false); var p1 = c.IsBound ? c.Evaluate(0.5, true) : c.Evaluate(0.25 * period, false); var p2 = c.IsBound ? c.Evaluate(1.0, true) : c.Evaluate(0.5 * period, false); if (IsLineLike(c)) { XYZ norm = null; //keep old plane computations if (System.Math.Abs(p0.Z - p2.Z) < Tolerance) { norm = XYZ.BasisZ; } else { var v1 = p1 - p0; var v2 = p2 - p0; var p3 = new XYZ(p2.X, p2.Y, p0.Z); var v3 = p3 - p0; norm = v1.CrossProduct(v3); if (norm.IsZeroLength()) { norm = v2.CrossProduct(XYZ.BasisY); } norm = norm.Normalize(); } return new Plane(norm, p0); } var cLoop = new CurveLoop(); cLoop.Append(c.Clone()); if (cLoop.HasPlane()) { return cLoop.GetPlane(); } if (planarOnly) return null; // Get best fit plane using tesselation var points = c.Tessellate().Select(x => x.ToPoint(false)); var bestFitPlane = Autodesk.DesignScript.Geometry.Plane.ByBestFitThroughPoints(points); return bestFitPlane.ToPlane(false); }
/// <summary> /// Create a copy of a curve loop with a given transformation applied. /// </summary> /// <param name="origLoop">The original curve loop.</param> /// <param name="trf">The transform.</param> /// <returns>The transformed loop.</returns> public static CurveLoop CreateTransformed(CurveLoop origLoop, Transform trf) { if (origLoop == null) return null; CurveLoop newLoop = new CurveLoop(); foreach (Curve curve in origLoop) { newLoop.Append(curve.CreateTransformed(trf)); } return newLoop; }
/// <summary> /// A PolyCurve is not a curve, this is a special extension method to convert to a Revit CurveLoop /// </summary> /// <param name="pcrv"></param> /// <returns></returns> public static Autodesk.Revit.DB.CurveLoop ToRevitType(this Autodesk.DesignScript.Geometry.PolyCurve pcrv) { if (!pcrv.IsClosed) { throw new Exception("The input PolyCurve must be closed"); } var cl = new CurveLoop(); var crvs = pcrv.Curves(); foreach (Autodesk.DesignScript.Geometry.Curve curve in crvs) { Autodesk.Revit.DB.Curve converted = curve.ToNurbsCurve().ToRevitType(); cl.Append(converted); } return cl; }
public static Autodesk.Revit.DB.CurveLoop ToRevitType(this Autodesk.DesignScript.Geometry.PolyCurve pcrv, bool performHostUnitConversion = true) { if (!pcrv.IsClosed) { throw new Exception("The input PolyCurve must be closed"); } pcrv = performHostUnitConversion ? pcrv.InHostUnits() : pcrv; var cl = new CurveLoop(); var crvs = pcrv.Curves(); foreach (Autodesk.DesignScript.Geometry.Curve curve in crvs) { Autodesk.Revit.DB.Curve converted = curve.ToNurbsCurve().ToRevitType(false); cl.Append(converted); } return cl; }
// This routine may return null geometry for one of three reasons: // 1. Invalid input. // 2. No IfcMaterialLayerUsage. // 3. The IfcMaterialLayerUsage isn't handled. // If the reason is #1 or #3, we want to warn the user. If it is #2, we don't. Pass back shouldWarn to let the caller know. private IList<GeometryObject> CreateGeometryFromMaterialLayerUsage(IFCImportShapeEditScope shapeEditScope, Transform extrusionPosition, IList<CurveLoop> loops, XYZ extrusionDirection, double currDepth, out ElementId materialId, out bool shouldWarn) { IList<GeometryObject> extrusionSolids = null; materialId = ElementId.InvalidElementId; try { shouldWarn = true; // Invalid input. // Check for valid input. if (shapeEditScope == null || extrusionPosition == null || loops == null || loops.Count() == 0 || extrusionDirection == null || !Application.IsValidThickness(currDepth)) return null; IFCProduct creator = shapeEditScope.Creator; if (creator == null) return null; shouldWarn = false; // Missing, empty, or optimized out IfcMaterialLayerSetUsage - valid reason to stop. IIFCMaterialSelect materialSelect = creator.MaterialSelect; if (materialSelect == null) return null; IFCMaterialLayerSetUsage materialLayerSetUsage = materialSelect as IFCMaterialLayerSetUsage; if (materialLayerSetUsage == null) return null; IFCMaterialLayerSet materialLayerSet = materialLayerSetUsage.MaterialLayerSet; if (materialLayerSet == null) return null; IList<IFCMaterialLayer> materialLayers = materialLayerSet.MaterialLayers; if (materialLayers == null || materialLayers.Count == 0) return null; // Optimization: if there is only one layer, use the standard method, with possibly an overloaded material. ElementId baseMaterialId = GetMaterialElementId(shapeEditScope); if (materialLayers.Count == 1) { IFCMaterial oneMaterial = materialLayers[0].Material; if (oneMaterial == null) return null; materialId = oneMaterial.GetMaterialElementId(); if (materialId != ElementId.InvalidElementId) { // We will not override the material of the element if the layer material has no color. if (Importer.TheCache.MaterialsWithNoColor.Contains(materialId)) materialId = ElementId.InvalidElementId; } return null; } // Anything below here is something we should report to the user, with the exception of the total thickness // not matching the extrusion thickness. This would require more analysis to determine that it is actually // an error condition. shouldWarn = true; IList<IFCMaterialLayer> realMaterialLayers = new List<IFCMaterialLayer>(); double totalThickness = 0.0; foreach (IFCMaterialLayer materialLayer in materialLayers) { double depth = materialLayer.LayerThickness; if (MathUtil.IsAlmostZero(depth)) continue; if (depth < 0.0) return null; realMaterialLayers.Add(materialLayer); totalThickness += depth; } // Axis3 means that the material layers are stacked in the Z direction. This is common for floor slabs. bool isAxis3 = (materialLayerSetUsage.Direction == IFCLayerSetDirection.Axis3); // For elements extruded in the Z direction, if the extrusion layers don't have the same thickness as the extrusion, // this could be one of two reasons: // 1. There is a discrepancy between the extrusion depth and the material layer set usage calculated depth. // 2. There are multiple extrusions in the body definition. // In either case, we will use the extrusion geometry over the calculated material layer set usage geometry. // In the future, we may decide to allow for case #1 by passing in a flag to allow for this. if (isAxis3 && !MathUtil.IsAlmostEqual(totalThickness, currDepth)) { shouldWarn = false; return null; } int numLayers = realMaterialLayers.Count(); if (numLayers == 0) return null; // We'll use this initial value for the Axis2 case, so read it here. double baseOffsetForLayer = materialLayerSetUsage.Offset; // Needed for Axis2 case only. The axisCurve is the curve defined in the product representation representing // a base curve (an axis) for the footprint of the element. Curve axisCurve = null; // The oriented cuve list represents the 4 curves of supported Axis2 footprint in the following order: // 1. curve along length of object closest to the first material layer with the orientation of the axis curve // 2. connecting end curve // 3. curve along length of object closest to the last material layer with the orientation opposite of the axis curve // 4. connecting end curve. IList<Curve> orientedCurveList = null; if (!isAxis3) { // Axis2 means that the material layers are stacked inthe Y direction. This is by definition for IfcWallStandardCase, // which has a local coordinate system whose Y direction is orthogonal to the length of the wall. if (materialLayerSetUsage.Direction == IFCLayerSetDirection.Axis2) { axisCurve = GetAxisCurve(creator, extrusionPosition); if (axisCurve == null) return null; orientedCurveList = GetOrientedCurveList(loops, axisCurve, extrusionPosition.BasisZ, baseOffsetForLayer, totalThickness); if (orientedCurveList == null) return null; } else return null; // Not handled. } extrusionSolids = new List<GeometryObject>(); bool positiveOrientation = (materialLayerSetUsage.DirectionSense == IFCDirectionSense.Positive); // Always extrude in the positive direction for Axis2. XYZ materialExtrusionDirection = (positiveOrientation || !isAxis3) ? extrusionDirection : -extrusionDirection; // Axis2 repeated values. // The IFC concept of offset direction is reversed from Revit's. XYZ normalDirectionForAxis2 = positiveOrientation ? -extrusionPosition.BasisZ : extrusionPosition.BasisZ; bool axisIsCyclic = (axisCurve == null) ? false : axisCurve.IsCyclic; double axisCurvePeriod = axisIsCyclic ? axisCurve.Period : 0.0; Transform curveLoopTransform = Transform.Identity; IList<CurveLoop> currLoops = null; double depthSoFar = 0.0; for (int ii = 0; ii < numLayers; ii++) { IFCMaterialLayer materialLayer = materialLayers[ii]; // Ignore 0 thickness layers. No need to warn. double depth = materialLayer.LayerThickness; if (MathUtil.IsAlmostZero(depth)) continue; // If the thickness is non-zero but invalid, fail. if (!Application.IsValidThickness(depth)) return null; double extrusionDistance = 0.0; if (isAxis3) { // Offset the curve loops if necessary, using the base extrusionDirection, regardless of the direction sense // of the MaterialLayerSetUsage. double offsetForLayer = positiveOrientation ? baseOffsetForLayer + depthSoFar : baseOffsetForLayer - depthSoFar; if (!MathUtil.IsAlmostZero(offsetForLayer)) { curveLoopTransform.Origin = offsetForLayer * extrusionDirection; currLoops = new List<CurveLoop>(); foreach (CurveLoop loop in loops) { CurveLoop newLoop = CurveLoop.CreateViaTransform(loop, curveLoopTransform); if (newLoop == null) return null; currLoops.Add(newLoop); } } else currLoops = loops; extrusionDistance = depth; } else { // startClipCurve, firstEndCapCurve, endClipCurve, secondEndCapCurve. Curve[] outline = new Curve[4]; double[][] endParameters = new double[4][]; double startClip = depthSoFar; double endClip = depthSoFar + depth; outline[0] = orientedCurveList[0].CreateOffset(startClip, normalDirectionForAxis2); outline[1] = orientedCurveList[1].Clone(); outline[2] = orientedCurveList[2].CreateOffset(totalThickness - endClip, normalDirectionForAxis2); outline[3] = orientedCurveList[3].Clone(); for (int jj = 0; jj < 4; jj++) { outline[jj].MakeUnbound(); endParameters[jj] = new double[2]; endParameters[jj][0] = 0.0; endParameters[jj][1] = 0.0; } // Trim/Extend the curves so that they make a closed loop. for (int jj = 0; jj < 4; jj++) { IntersectionResultArray resultArray = null; outline[jj].Intersect(outline[(jj + 1) % 4], out resultArray); if (resultArray == null || resultArray.Size == 0) return null; int numResults = resultArray.Size; if ((numResults > 1 && !axisIsCyclic) || (numResults > 2)) return null; UV intersectionPoint = resultArray.get_Item(0).UVPoint; endParameters[jj][1] = intersectionPoint.U; endParameters[(jj + 1) % 4][0] = intersectionPoint.V; if (numResults == 2) { // If the current result is closer to the end of the curve, keep it. UV newIntersectionPoint = resultArray.get_Item(1).UVPoint; int endParamIndex = (jj % 2); double newParamToCheck = newIntersectionPoint[endParamIndex]; double oldParamToCheck = (endParamIndex == 0) ? endParameters[jj][1] : endParameters[(jj + 1) % 4][0]; double currentEndPoint = (endParamIndex == 0) ? orientedCurveList[jj].GetEndParameter(1) : orientedCurveList[(jj + 1) % 4].GetEndParameter(0); // Put in range of [-Period/2, Period/2]. double newDist = (currentEndPoint - newParamToCheck) % axisCurvePeriod; if (newDist < -axisCurvePeriod / 2.0) newDist += axisCurvePeriod; if (newDist > axisCurvePeriod / 2.0) newDist -= axisCurvePeriod; double oldDist = (currentEndPoint - oldParamToCheck) % axisCurvePeriod; if (oldDist < -axisCurvePeriod / 2.0) oldDist += axisCurvePeriod; if (oldDist > axisCurvePeriod / 2.0) oldDist -= axisCurvePeriod; if (Math.Abs(newDist) < Math.Abs(oldDist)) { endParameters[jj][1] = newIntersectionPoint.U; endParameters[(jj + 1) % 4][0] = newIntersectionPoint.V; } } } CurveLoop newCurveLoop = new CurveLoop(); for (int jj = 0; jj < 4; jj++) { if (endParameters[jj][1] < endParameters[jj][0]) { if (!outline[jj].IsCyclic) return null; endParameters[jj][1] += Math.Floor(endParameters[jj][0] / axisCurvePeriod + 1.0) * axisCurvePeriod; } outline[jj].MakeBound(endParameters[jj][0], endParameters[jj][1]); newCurveLoop.Append(outline[jj]); } currLoops = new List<CurveLoop>(); currLoops.Add(newCurveLoop); extrusionDistance = currDepth; } // Determine the material id. IFCMaterial material = materialLayer.Material; ElementId layerMaterialId = (material == null) ? ElementId.InvalidElementId : material.GetMaterialElementId(); // The second option here is really for Referencing. Without a UI (yet) to determine whether to show the base // extusion or the layers for objects with material layer sets, we've chosen to display the base material if the layer material // has no color information. This means that the layer is assigned the "wrong" material, but looks better on screen. // We will reexamine this decision (1) for the Open case, (2) if there is UI to toggle between layers and base extrusion, or // (3) based on user feedback. if (layerMaterialId == ElementId.InvalidElementId || Importer.TheCache.MaterialsWithNoColor.Contains(layerMaterialId)) layerMaterialId = baseMaterialId; SolidOptions solidOptions = new SolidOptions(layerMaterialId, shapeEditScope.GraphicsStyleId); // Create the extrusion for the material layer. GeometryObject extrusionSolid = GeometryCreationUtilities.CreateExtrusionGeometry( currLoops, materialExtrusionDirection, extrusionDistance, solidOptions); if (extrusionSolid == null) return null; extrusionSolids.Add(extrusionSolid); depthSoFar += depth; } } catch { // Ignore the specific exception, but let the user know there was a problem processing the IfcMaterialLayerSetUsage. shouldWarn = true; return null; } return extrusionSolids; }
private static IList<CurveLoop> GetBoundaryLoopsFromBaseCurve(Wall wallElement, IList<IList<IFCConnectedWallData>> connectedWalls, Curve baseCurve, Curve trimmedCurve, double unscaledWidth, double scaledDepth) { // If we don't have connected wall information, we can't clip them away. Abort. if (connectedWalls == null) return null; Curve axisCurve = MaybeStretchBaseCurve(baseCurve, trimmedCurve); if (axisCurve == null) return null; // Create the extruded wall minus the wall joins. Solid baseSolid = CreateWallEndClippedWallGeometry(wallElement, connectedWalls, axisCurve, unscaledWidth, scaledDepth); if (baseSolid == null) return null; // Get the one face pointing in the -Z direction. If there are multiple, abort. IList<CurveLoop> boundaryLoops = new List<CurveLoop>(); foreach (Face potentialBaseFace in baseSolid.Faces) { if (potentialBaseFace is PlanarFace) { PlanarFace planarFace = potentialBaseFace as PlanarFace; if (planarFace.Normal.IsAlmostEqualTo(-XYZ.BasisZ)) { if (boundaryLoops.Count > 0) return null; try { foreach (EdgeArray edgeLoop in planarFace.EdgeLoops) { bool hasCurve = false; CurveLoop curveLoop = new CurveLoop(); foreach (Edge edge in edgeLoop) { Curve edgeCurve = edge.AsCurveFollowingFace(planarFace); if (edgeCurve == null) return null; curveLoop.Append(edgeCurve); hasCurve = true; } if (!hasCurve) return null; boundaryLoops.Add(curveLoop); } } catch { return null; } } } } return boundaryLoops; }
/// <summary> /// Create Hatch /// </summary> /// <param name="hatch"></param> /// <returns></returns> public static Element Create(this Grevit.Types.Hatch hatch) { // Get all Filled region types FilteredElementCollector collector = new FilteredElementCollector(GrevitBuildModel.document).OfClass(typeof(Autodesk.Revit.DB.FilledRegionType)); // Get the View to place the hatch on Element viewElement = GrevitBuildModel.document.GetElementByName(typeof(Autodesk.Revit.DB.View), hatch.view); // Get the hatch pattern name and set it to solid if the hatch pattern name is invalid string patternname = (hatch.pattern == null || hatch.pattern == string.Empty) ? patternname = "Solid fill" : hatch.pattern; // Get the fill pattern element and filled region type FillPatternElement fillPatternElement = FillPatternElement.GetFillPatternElementByName(GrevitBuildModel.document, FillPatternTarget.Drafting, patternname); FilledRegionType filledRegionType = collector.FirstElement() as FilledRegionType; // Setup a new curveloop for the outline CurveLoop curveLoop = new CurveLoop(); List<CurveLoop> listOfCurves = new List<CurveLoop>(); // Get a closed loop from the grevit points for (int i = 0; i < hatch.outline.Count; i++) { int j = i + 1; Grevit.Types.Point p1 = hatch.outline[i]; if (j == hatch.outline.Count) j = 0; Grevit.Types.Point p2 = hatch.outline[j]; Curve cn = Autodesk.Revit.DB.Line.CreateBound(p1.ToXYZ(), p2.ToXYZ()); curveLoop.Append(cn); } listOfCurves.Add(curveLoop); // Create a filled region from the loop return FilledRegion.Create(GrevitBuildModel.document, filledRegionType.Id, viewElement.Id, listOfCurves); }
/// <summary> /// Creates an open or closed CurveLoop from a list of vertices. /// </summary> /// <param name="pointXYZs">The list of vertices.</param> /// <param name="points">The optional list of IFCAnyHandles that generated the vertices, used solely for error reporting.</param> /// <param name="id">The id of the IFCAnyHandle associated with the CurveLoop.</param> /// <param name="closeCurve">True if the loop needs a segment between the last point and the first point.</param> /// <returns>The new curve loop.</returns> /// <remarks>If closeCurve is true, there will be pointsXyz.Count line segments. Otherwise, there will be pointsXyz.Count-1.</remarks> public static CurveLoop CreatePolyCurveLoop(IList<XYZ> pointXYZs, IList<IFCAnyHandle> points, int id, bool closeCurve) { int numPoints = pointXYZs.Count; if (numPoints < 2) { // TODO: log warning return null; } IList<int> badIds = new List<int>(); // The input polycurve loop may or may not repeat the start/end point. // wasAlreadyClosed checks if the point was repeated. bool wasAlreadyClosed = pointXYZs[0].IsAlmostEqualTo(pointXYZs[numPoints - 1]); bool wasClosed = closeCurve ? true : wasAlreadyClosed; // We expect at least 3 points if the curve is closed, 2 otherwise. int numMinPoints = wasAlreadyClosed ? 4 : (closeCurve ? 3 : 2); if (numPoints < numMinPoints) { // TODO: log warning return null; } // Check distance between points; remove too-close points, and warn if result is non-collinear. // Always include first point. IList<XYZ> finalPoints = new List<XYZ>(); finalPoints.Add(pointXYZs[0]); int numNewPoints = 1; int numPointsToCheck = closeCurve ? numPoints + 1 : numPoints; for (int ii = 1; ii < numPointsToCheck; ii++) { int nextIndex = (ii % numPoints); int nextNextIndex = (nextIndex == numPoints-1 && wasAlreadyClosed) ? 1 : ((ii + 1) % numPoints); // Only check if the last segment overlaps the first segment if we have a closed curve. bool doSegmentOverlapCheck = (ii < numPointsToCheck - 1) || wasClosed; if (LineSegmentIsTooShort(finalPoints[numNewPoints - 1], pointXYZs[nextIndex]) || (doSegmentOverlapCheck && LineSegmentsOverlap(finalPoints[numNewPoints - 1], pointXYZs[nextIndex], pointXYZs[nextNextIndex]))) { if (points != null) badIds.Add(points[nextIndex].StepId); else badIds.Add(nextIndex + 1); } else { finalPoints.Add(pointXYZs[nextIndex]); numNewPoints++; } } // Check final segment; if too short, delete 2nd to last point instead of the last. if (wasClosed) { if (numNewPoints < 4) return null; bool isClosed = finalPoints[numNewPoints - 1].IsAlmostEqualTo(finalPoints[0]); // Do we have a closed loop now? if (wasClosed && !isClosed) // If we had a closed loop, and now we don't, fix it up. { // Presumably, the second-to-last point had to be very close to the last point, or we wouldn't have removed the last point. // So instead of creating a too-short segment, we replace the last point of the new point list with the last point of the original point list. finalPoints[numNewPoints - 1] = pointXYZs[numPoints - 1]; // Now we have to check that we didn't inadvertently make a "too-short" segment. for (int ii = numNewPoints - 1; ii > 0; ii--) { if (IFCGeometryUtil.LineSegmentIsTooShort(finalPoints[ii], finalPoints[ii - 1])) { // TODO: log this removal. finalPoints.RemoveAt(ii - 1); // Remove the intermediate point, not the last point. numNewPoints--; } else break; // We are in the clear, unless we removed too many points - we've already checked the rest of the loop. } } if (numNewPoints < 4) return null; } // This can be a very common warning, so we will restrict to verbose logging. if (Importer.TheOptions.VerboseLogging) { if (badIds.Count > 0) { int count = badIds.Count; string msg = null; if (count == 1) { msg = "Polyline had 1 point that was too close to one of its neighbors, removing point: #" + badIds[0] + "."; } else { msg = "Polyline had " + count + " points that were too close to one of their neighbors, removing points:"; foreach (int badId in badIds) msg += " #" + badId; msg += "."; } Importer.TheLog.LogWarning(id, msg, false); } } if (numNewPoints < numMinPoints) { if (Importer.TheOptions.VerboseLogging) { string msg = "PolyCurve had " + numNewPoints + " point(s) after removing points that were too close, expected at least " + numMinPoints + ", ignoring."; Importer.TheLog.LogWarning(id, msg, false); } return null; } CurveLoop curveLoop = new CurveLoop(); for (int ii = 0; ii < numNewPoints - 1; ii++) curveLoop.Append(Line.CreateBound(finalPoints[ii], finalPoints[ii + 1])); return curveLoop; }
/// <summary> /// Returns a CurveLoop that has potentially been trimmed. /// </summary> /// <param name="origCurveLoop">The original curve loop.</param> /// <param name="startVal">The starting trim parameter.</param> /// <param name="origEndVal">The optional end trim parameter. If not supplied, assume no end trim.</param> /// <returns>The original curve loop, if no trimming has been done, otherwise a trimmed copy.</returns> public static CurveLoop TrimCurveLoop(CurveLoop origCurveLoop, double startVal, double? origEndVal) { // Trivial case: no trimming. if (!origEndVal.HasValue && MathUtil.IsAlmostZero(startVal)) return origCurveLoop; IList<double> curveLengths = new List<double>(); IList<Curve> loopCurves = new List<Curve>(); double totalParamLength = 0.0; foreach (Curve curve in origCurveLoop) { double currLength = ScaleCurveLengthForSweptSolid(curve, curve.GetEndParameter(1) - curve.GetEndParameter(0)); loopCurves.Add(curve); curveLengths.Add(currLength); totalParamLength += currLength; } double endVal = origEndVal.HasValue ? origEndVal.Value : totalParamLength; // This check allows for some leniency in the setting of startVal and endVal; we assume that if the parameter range // is equal, that an offset value is OK. if (MathUtil.IsAlmostEqual(endVal - startVal, totalParamLength)) return origCurveLoop; int numCurves = loopCurves.Count; double currentPosition = 0.0; int currCurve = 0; IList<Curve> newLoopCurves = new List<Curve>(); if (startVal > MathUtil.Eps()) { for (; currCurve < numCurves; currCurve++) { if (currentPosition + curveLengths[currCurve] < startVal + MathUtil.Eps()) { currentPosition += curveLengths[currCurve]; continue; } Curve newCurve = loopCurves[currCurve].Clone(); if (!MathUtil.IsAlmostEqual(currentPosition, startVal)) newCurve.MakeBound(UnscaleSweptSolidCurveParam(loopCurves[currCurve], startVal - currentPosition), newCurve.GetEndParameter(1)); newLoopCurves.Add(newCurve); break; } } if (endVal < totalParamLength - MathUtil.Eps()) { for (; currCurve < numCurves; currCurve++) { if (currentPosition + curveLengths[currCurve] < endVal - MathUtil.Eps()) { currentPosition += curveLengths[currCurve]; newLoopCurves.Add(loopCurves[currCurve]); continue; } Curve newCurve = loopCurves[currCurve].Clone(); if (!MathUtil.IsAlmostEqual(currentPosition + curveLengths[currCurve], endVal)) newCurve.MakeBound(newCurve.GetEndParameter(0), UnscaleSweptSolidCurveParam(loopCurves[currCurve], endVal - currentPosition)); newLoopCurves.Add(newCurve); break; } } CurveLoop trimmedCurveLoop = new CurveLoop(); foreach (Curve curve in loopCurves) trimmedCurveLoop.Append(curve); return trimmedCurveLoop; }
/// <summary> /// Get the curve or CurveLoop representation of IFCCurve, as a CurveLoop. This will have a value, as long as Curve or CurveLoop do. /// </summary> public CurveLoop GetCurveLoop() { if (CurveLoop != null) return CurveLoop; if (Curve == null) return null; CurveLoop curveAsCurveLoop = new CurveLoop(); curveAsCurveLoop.Append(Curve); return curveAsCurveLoop; }
private CurveLoop CreateFilletedRectangleCurveLoop(XYZ[] corners, double filletRadius) { int sz = corners.Count(); if (sz != 4) return null; XYZ[] radii = new XYZ[4] { new XYZ( corners[0].X + filletRadius, corners[0].Y + filletRadius, 0.0 ), new XYZ( corners[1].X - filletRadius, corners[1].Y + filletRadius, 0.0 ), new XYZ( corners[2].X - filletRadius, corners[2].Y - filletRadius, 0.0 ), new XYZ( corners[3].X + filletRadius, corners[3].Y - filletRadius, 0.0 ), }; XYZ[] fillets = new XYZ[8] { new XYZ( corners[0].X, corners[0].Y + filletRadius, 0.0 ), new XYZ( corners[0].X + filletRadius, corners[0].Y, 0.0 ), new XYZ( corners[1].X - filletRadius, corners[1].Y, 0.0 ), new XYZ( corners[1].X, corners[1].Y + filletRadius, 0.0 ), new XYZ( corners[2].X, corners[2].Y - filletRadius, 0.0 ), new XYZ( corners[2].X - filletRadius, corners[2].Y, 0.0 ), new XYZ( corners[3].X + filletRadius, corners[3].Y, 0.0 ), new XYZ( corners[3].X, corners[3].Y - filletRadius, 0.0 ) }; CurveLoop curveLoop = new CurveLoop(); for (int ii = 0; ii < 4; ii++) { curveLoop.Append(Line.CreateBound(fillets[ii * 2 + 1], fillets[(ii * 2 + 2) % 8])); double startAngle = Math.PI * ((ii + 3) % 4) / 2; curveLoop.Append(CreateXYArc(radii[(ii + 1) % 4], filletRadius, startAngle, startAngle + Math.PI / 2)); } return curveLoop; }
private void ProcessIFCCircleProfileDef(IFCAnyHandle profileDef) { bool found = false; double radius = IFCImportHandleUtil.GetRequiredScaledLengthAttribute(profileDef, "Radius", out found); if (!found) return; if (radius < MathUtil.Eps()) { IFCImportFile.TheLog.LogError(Id, "IfcCircleProfileDef has invalid radius: " + radius + ", ignoring.", false); return; } // Some internal routines want CurveLoops with bounded components. Split to avoid problems. OuterCurve = new CurveLoop(); OuterCurve.Append(CreateXYArc(XYZ.Zero, radius, 0, Math.PI)); OuterCurve.Append(CreateXYArc(XYZ.Zero, radius, Math.PI, 2 * Math.PI)); if (IFCAnyHandleUtil.IsSubTypeOf(profileDef, IFCEntityType.IfcCircleHollowProfileDef)) { double wallThickness = IFCImportHandleUtil.GetOptionalScaledLengthAttribute(profileDef, "WallThickness", 0.0); if (wallThickness > MathUtil.Eps() && wallThickness < radius) { double innerRadius = radius - wallThickness; CurveLoop innerCurve = new CurveLoop(); innerCurve.Append(CreateXYArc(XYZ.Zero, innerRadius, 0, Math.PI)); innerCurve.Append(CreateXYArc(XYZ.Zero, innerRadius, Math.PI, 2 * Math.PI)); InnerCurves.Add(innerCurve); } } }
private void ProcessIFCEllipseProfileDef(IFCAnyHandle profileDef) { bool found = false; double radiusX = IFCImportHandleUtil.GetRequiredScaledLengthAttribute(profileDef, "SemiAxis1", out found); if (!found) return; double radiusY = IFCImportHandleUtil.GetRequiredScaledLengthAttribute(profileDef, "SemiAxis2", out found); if (!found) return; // Some internal routines want CurveLoops with bounded components. Split to avoid problems. OuterCurve = new CurveLoop(); OuterCurve.Append(CreateXYEllipse(XYZ.Zero, radiusX, radiusY, 0, Math.PI)); OuterCurve.Append(CreateXYEllipse(XYZ.Zero, radiusX, radiusY, Math.PI, 2 * Math.PI)); }
private IList<GeometryObject> SplitSweptDiskIntoValidPieces(CurveLoop trimmedDirectrixInWCS, IList<CurveLoop> profileCurveLoops, SolidOptions solidOptions) { // If we have 0 or 1 curves, there is nothing we can do here. int numCurves = trimmedDirectrixInWCS.Count(); if (numCurves < 2) return null; // We will attempt to represent the original description in as few pieces as possible. IList<Curve> directrixCurves = new List<Curve>(); foreach (Curve directrixCurve in trimmedDirectrixInWCS) { if (directrixCurve == null) { numCurves--; if (numCurves < 2) return null; continue; } directrixCurves.Add(directrixCurve); } IList<GeometryObject> sweptDiskPieces = new List<GeometryObject>(); // We will march along the directrix one curve at a time, trying to build a bigger piece of the sweep. At the point that we throw an exception, // we will take the last biggest piece and start over. CurveLoop currentCurveLoop = new CurveLoop(); Solid bestSolidSoFar = null; double pathAttachmentParam = directrixCurves[0].GetEndParameter(0); for (int ii = 0; ii < numCurves; ii++) { currentCurveLoop.Append(directrixCurves[ii]); try { Solid currentSolid = GeometryCreationUtilities.CreateSweptGeometry(currentCurveLoop, 0, pathAttachmentParam, profileCurveLoops, solidOptions); bestSolidSoFar = currentSolid; } catch { if (bestSolidSoFar != null) { sweptDiskPieces.Add(bestSolidSoFar); bestSolidSoFar = null; } } // This should only happen as a result of the catch loop above. We want to protect against the case where one or more pieces of the sweep // are completely invalid. while (bestSolidSoFar == null && (ii < numCurves)) { try { currentCurveLoop = new CurveLoop(); currentCurveLoop.Append(directrixCurves[ii]); profileCurveLoops = CreateProfileCurveLoopsForDirectrix(directrixCurves[ii], out pathAttachmentParam); Solid currentSolid = GeometryCreationUtilities.CreateSweptGeometry(currentCurveLoop, 0, pathAttachmentParam, profileCurveLoops, solidOptions); bestSolidSoFar = currentSolid; break; } catch { ii++; } } } return sweptDiskPieces; }
/// <summary> /// Return geometry for a particular representation item. /// </summary> /// <param name="shapeEditScope">The geometry creation scope.</param> /// <param name="lcs">Local coordinate system for the geometry, without scale.</param> /// <param name="scaledLcs">Local coordinate system for the geometry, including scale, potentially non-uniform.</param> /// <param name="guid">The guid of an element for which represntation is being created.</param> /// <returns>Zero or more created geometries.</returns> protected override IList<GeometryObject> CreateGeometryInternal( IFCImportShapeEditScope shapeEditScope, Transform lcs, Transform scaledLcs, string guid) { Transform sweptDiskPosition = (lcs == null) ? Transform.Identity : lcs; CurveLoop baseProfileCurve = Directrix.GetCurveLoop(); if (baseProfileCurve == null) return null; CurveLoop trimmedDirectrix = IFCGeometryUtil.TrimCurveLoop(baseProfileCurve, StartParameter, EndParameter); if (trimmedDirectrix == null) return null; CurveLoop trimmedDirectrixInLCS = IFCGeometryUtil.CreateTransformed(trimmedDirectrix, sweptDiskPosition); // Create the disk. Transform originTrf = null; double startParam = 0.0; // If the directrix isn't bound, this arbitrary parameter will do. foreach (Curve curve in trimmedDirectrixInLCS) { if (curve.IsBound) startParam = curve.GetEndParameter(0); originTrf = curve.ComputeDerivatives(startParam, false); break; } if (originTrf == null) return null; // The X-dir of the transform of the start of the directrix will form the normal of the disk. Plane diskPlane = new Plane(originTrf.BasisX, originTrf.Origin); IList<CurveLoop> profileCurveLoops = new List<CurveLoop>(); CurveLoop diskOuterCurveLoop = new CurveLoop(); diskOuterCurveLoop.Append(Arc.Create(diskPlane, Radius, 0, Math.PI)); diskOuterCurveLoop.Append(Arc.Create(diskPlane, Radius, Math.PI, 2.0 * Math.PI)); profileCurveLoops.Add(diskOuterCurveLoop); if (InnerRadius.HasValue) { CurveLoop diskInnerCurveLoop = new CurveLoop(); diskInnerCurveLoop.Append(Arc.Create(diskPlane, InnerRadius.Value, 0, Math.PI)); diskInnerCurveLoop.Append(Arc.Create(diskPlane, InnerRadius.Value, Math.PI, 2.0 * Math.PI)); profileCurveLoops.Add(diskInnerCurveLoop); } SolidOptions solidOptions = new SolidOptions(GetMaterialElementId(shapeEditScope), shapeEditScope.GraphicsStyleId); Solid sweptDiskSolid = GeometryCreationUtilities.CreateSweptGeometry(trimmedDirectrixInLCS, 0, startParam, profileCurveLoops, solidOptions); IList<GeometryObject> myObjs = new List<GeometryObject>(); if (sweptDiskSolid != null) myObjs.Add(sweptDiskSolid); return myObjs; }
private void AddCurveToLoopInternal(CurveLoop curveLoop, Curve curve, bool initialReverse, bool tryReversed) { try { if (tryReversed != initialReverse) curveLoop.Append(curve.CreateReversed()); else curveLoop.Append(curve); } catch (Exception ex) { if (ex.Message.Contains("not contiguous")) { if (!tryReversed) AddCurveToLoopInternal(curveLoop, curve, initialReverse, true); else throw ex; } } }
/// <summary> /// Return a solid corresponding to the volume represented by boundingBoxXYZ. /// </summary> /// <param name="lcs">The local coordinate system of the bounding box; if null, assume the Identity transform.</param> /// <param name="boundingBoxXYZ">The bounding box.</param> /// <param name="solidOptions">The options for creating the solid. Allow null to mean default.</param> /// <returns>A solid of the same size and orientation as boundingBoxXYZ, or null if boundingBoxXYZ is invalid or null.</returns> /// <remarks>We don't do any checking on the input transform, which could have non-uniform scaling and/or mirroring. /// This could potentially lead to unexpected results, which we can examine if and when such cases arise.</remarks> public static Solid CreateSolidFromBoundingBox(Transform lcs, BoundingBoxXYZ boundingBoxXYZ, SolidOptions solidOptions) { // Check that the bounding box is valid. if (boundingBoxXYZ == null || !boundingBoxXYZ.Enabled) return null; try { // Create a transform based on the incoming local coordinate system and the bounding box coordinate system. Transform bboxTransform = (lcs == null) ? boundingBoxXYZ.Transform : lcs.Multiply(boundingBoxXYZ.Transform); XYZ[] profilePts = new XYZ[4]; profilePts[0] = bboxTransform.OfPoint(boundingBoxXYZ.Min); profilePts[1] = bboxTransform.OfPoint(new XYZ(boundingBoxXYZ.Max.X, boundingBoxXYZ.Min.Y, boundingBoxXYZ.Min.Z)); profilePts[2] = bboxTransform.OfPoint(new XYZ(boundingBoxXYZ.Max.X, boundingBoxXYZ.Max.Y, boundingBoxXYZ.Min.Z)); profilePts[3] = bboxTransform.OfPoint(new XYZ(boundingBoxXYZ.Min.X, boundingBoxXYZ.Max.Y, boundingBoxXYZ.Min.Z)); XYZ upperRightXYZ = bboxTransform.OfPoint(boundingBoxXYZ.Max); // If we assumed that the transforms had no scaling, // then we could simply take boundingBoxXYZ.Max.Z - boundingBoxXYZ.Min.Z. // This code removes that assumption. XYZ origExtrusionVector = new XYZ(boundingBoxXYZ.Min.X, boundingBoxXYZ.Min.Y, boundingBoxXYZ.Max.Z) - boundingBoxXYZ.Min; XYZ extrusionVector = bboxTransform.OfVector(origExtrusionVector); double extrusionDistance = extrusionVector.GetLength(); XYZ extrusionDirection = extrusionVector.Normalize(); CurveLoop baseLoop = new CurveLoop(); for (int ii = 0; ii < 4; ii++) { baseLoop.Append(Line.CreateBound(profilePts[ii], profilePts[(ii + 1) % 4])); } IList<CurveLoop> baseLoops = new List<CurveLoop>(); baseLoops.Add(baseLoop); if (solidOptions == null) return GeometryCreationUtilities.CreateExtrusionGeometry(baseLoops, extrusionDirection, extrusionDistance); else return GeometryCreationUtilities.CreateExtrusionGeometry(baseLoops, extrusionDirection, extrusionDistance, solidOptions); } catch { return null; } }
private static IList<CurveLoop> CoarsenCurveLoops(IList<CurveLoop> origCurveLoops) { // Coarsen loop unless we are at the Highest level of detail. if (ExporterCacheManager.ExportOptionsCache.LevelOfDetail >= 4) return origCurveLoops; IList<CurveLoop> modifiedLoops = new List<CurveLoop>(); foreach (CurveLoop curveLoop in origCurveLoops) { // We don't really know if the original CurveLoop is valid, so attempting to create a copy may result in exceptions. // Protect against this for each individual loop. try { if (curveLoop.Count() <= 24) { modifiedLoops.Add(curveLoop); continue; } bool modified = false; XYZ lastFirstPt = null; Line lastLine = null; IList<Curve> newCurves = new List<Curve>(); foreach (Curve curve in curveLoop) { // Set lastLine to be the first line in the loop, if it exists. // In addition, Revit may have legacy curve segments that are too short. Don't process them. if (!(curve is Line)) { // Break the polyline, if it existed. if (lastLine != null) newCurves.Add(lastLine); lastLine = null; lastFirstPt = null; newCurves.Add(curve); continue; } if (lastLine == null) { lastLine = curve as Line; lastFirstPt = lastLine.GetEndPoint(0); continue; } // If we are here, we have two lines in a row. See if they are almost collinear. XYZ currLastPt = curve.GetEndPoint(1); Line combinedLine = null; // If the combined curve is too short, don't merge. if (currLastPt.DistanceTo(lastFirstPt) > ExporterCacheManager.Document.Application.ShortCurveTolerance) { combinedLine = Line.CreateBound(lastFirstPt, currLastPt); XYZ currMidPt = curve.GetEndPoint(0); IntersectionResult result = combinedLine.Project(currMidPt); // If the absolute distance is greater than 1", or 1% of either line length, use both. double dist = result.Distance; if ((dist > 1.0 / 12.0) || (dist / (lastLine.Length) > 0.01) || (dist / (curve.Length) > 0.01)) combinedLine = null; } if (combinedLine == null) { newCurves.Add(lastLine); lastLine = curve as Line; lastFirstPt = lastLine.GetEndPoint(0); continue; } // The combined line is now the last line. lastLine = combinedLine; modified = true; } if (modified) { if (lastLine != null) newCurves.Add(lastLine); CurveLoop modifiedCurveLoop = new CurveLoop(); foreach (Curve modifiedCurve in newCurves) modifiedCurveLoop.Append(modifiedCurve); modifiedLoops.Add(modifiedCurveLoop); } else { modifiedLoops.Add(curveLoop); } } catch { // If we run into any trouble, use the original loop. // TODO: this may end up failing in the ValidateCurves check that follows, so we may just skip entirely. modifiedLoops.Add(curveLoop); } } return modifiedLoops; }
private CurveLoop CreatePolyCurveLoop(XYZ[] corners) { int sz = corners.Count(); if (sz == 0) return null; CurveLoop curveLoop = new CurveLoop(); for (int ii = 0; ii < sz; ii++) curveLoop.Append(Line.CreateBound(corners[ii], corners[(ii + 1) % sz])); return curveLoop; }
// In certain cases, Revit can't handle unbounded circles and ellipses. Create a CurveLoop with the curve split into two segments. private CurveLoop CreateCurveLoopFromUnboundedCyclicCurve(Curve innerCurve) { if (innerCurve == null) return null; if (!innerCurve.IsCyclic) return null; // We don't know how to handle anything other than circles or ellipses with a period of 2PI. double period = innerCurve.Period; if (!MathUtil.IsAlmostEqual(period, Math.PI * 2.0)) return null; double startParam = innerCurve.IsBound ? innerCurve.GetEndParameter(0) : 0.0; double endParam = innerCurve.IsBound ? innerCurve.GetEndParameter(1) : period; // Not a closed curve. if (!MathUtil.IsAlmostEqual(endParam - startParam, period)) return null; Curve firstCurve = innerCurve.Clone(); if (firstCurve == null) return null; Curve secondCurve = innerCurve.Clone(); if (secondCurve == null) return null; firstCurve.MakeBound(0, period / 2.0); secondCurve.MakeBound(period / 2.0, period); CurveLoop innerCurveLoop = new CurveLoop(); innerCurveLoop.Append(firstCurve); innerCurveLoop.Append(secondCurve); return innerCurveLoop; }
private static CurveLoop GetFaceBoundary(Face face, EdgeArray faceBoundary, XYZ baseLoopOffset, bool polygonalOnly, out FaceBoundaryType faceBoundaryType) { faceBoundaryType = FaceBoundaryType.Polygonal; CurveLoop currLoop = new CurveLoop(); foreach (Edge faceBoundaryEdge in faceBoundary) { Curve edgeCurve = faceBoundaryEdge.AsCurveFollowingFace(face); Curve offsetCurve = (baseLoopOffset != null) ? MoveCurve(edgeCurve, baseLoopOffset) : edgeCurve; if (!(offsetCurve is Line)) { if (polygonalOnly) { IList<XYZ> tessPts = offsetCurve.Tessellate(); int numTessPts = tessPts.Count; for (int ii = 0; ii < numTessPts - 1; ii++) { Line line = Line.get_Bound(tessPts[ii], tessPts[ii + 1]); currLoop.Append(line); } } else { currLoop.Append(offsetCurve); } if (offsetCurve is Arc) faceBoundaryType = FaceBoundaryType.LinesAndArcs; else faceBoundaryType = FaceBoundaryType.Complex; } else currLoop.Append(offsetCurve); } return currLoop; }
private void ProcessIFCArbitraryOpenProfileDef(IFCAnyHandle profileDef) { IFCAnyHandle curveHnd = IFCAnyHandleUtil.GetInstanceAttribute(profileDef, "Curve"); if (IFCAnyHandleUtil.IsNullOrHasNoValue(curveHnd)) { IFCImportFile.TheLog.LogNullError(IFCEntityType.IfcArbitraryOpenProfileDef); return; } IFCCurve profileIFCCurve = IFCCurve.ProcessIFCCurve(curveHnd); CurveLoop profileCurveLoop = profileIFCCurve.CurveLoop; if (profileCurveLoop == null) { Curve profileCurve = profileIFCCurve.Curve; if (profileCurve != null) { profileCurveLoop = new CurveLoop(); profileCurveLoop.Append(profileCurve); } } if ((profileCurveLoop != null) && IFCAnyHandleUtil.IsSubTypeOf(profileDef, IFCEntityType.IfcCenterLineProfileDef)) { double? thickness = IFCAnyHandleUtil.GetDoubleAttribute(profileDef, "Thickness"); if (!thickness.HasValue) { //LOG: ERROR: IfcCenterLineProfileDef has no thickness defined. return; } Plane plane = null; try { plane = profileCurveLoop.GetPlane(); } catch { //LOG: ERROR: Curve for IfcCenterLineProfileDef is non-planar. return; } double thicknessVal = IFCUnitUtil.ScaleLength(thickness.Value); profileCurveLoop = null; try { profileCurveLoop = CurveLoop.CreateViaThicken(profileCurveLoop, thicknessVal, plane.Normal); } catch { } } if (profileCurveLoop != null) OuterCurve = profileCurveLoop; else { //LOG: ERROR: Invalid outer curve in IfcArbitraryOpenProfileDef. return; } }
/// <summary> /// Creates an open or closed CurveLoop from a list of vertices. /// </summary> /// <param name="pointXYZs">The list of vertices.</param> /// <param name="points">The optional list of IFCAnyHandles that generated the vertices, used solely for error reporting.</param> /// <param name="id">The id of the IFCAnyHandle associated with the CurveLoop.</param> /// <param name="isClosedLoop">True if the vertices represent a closed loop, false if not.</param> /// <returns>The new curve loop.</returns> /// <remarks>If isClosedLoop is true, there will be pointsXyz.Count line segments. Otherwise, there will be pointsXyz.Count-1.</remarks> public static CurveLoop CreatePolyCurveLoop(IList<XYZ> pointXYZs, IList<IFCAnyHandle> points, int id, bool isClosedLoop) { int numPoints = pointXYZs.Count; if (numPoints < 2) return null; IList<int> badIds = new List<int>(); int numMinPoints = isClosedLoop ? 3 : 2; // Check distance between points; remove too-close points, and warn if result is non-collinear. // Always include first point. IList<XYZ> finalPoints = new List<XYZ>(); finalPoints.Add(pointXYZs[0]); int numNewPoints = 1; for (int ii = 1; ii < numPoints; ii++) { if (IFCGeometryUtil.LineSegmentIsTooShort(finalPoints[numNewPoints - 1], pointXYZs[ii])) { if (points != null) badIds.Add(points[ii].StepId); else badIds.Add(ii+1); } else { finalPoints.Add(pointXYZs[ii]); numNewPoints++; } } // Check final segment; if too short, delete 2nd to last point. if (isClosedLoop) { if (IFCGeometryUtil.LineSegmentIsTooShort(finalPoints[numNewPoints - 1], pointXYZs[0])) { finalPoints.RemoveAt(numNewPoints - 1); numNewPoints--; } } // This can be a very common warning, so we will restrict to verbose logging. if (Importer.TheOptions.VerboseLogging) { if (badIds.Count > 0) { int count = badIds.Count; string msg = null; if (count == 1) { msg = "Polyline had 1 point that was too close to one of its neighbors, removing point: #" + badIds[0] + "."; } else { msg = "Polyline had " + count + " points that were too close to one of their neighbors, removing points:"; foreach (int badId in badIds) msg += " #" + badId; msg += "."; } IFCImportFile.TheLog.LogWarning(id, msg, false); } } if (numNewPoints < numMinPoints) { if (Importer.TheOptions.VerboseLogging) { string msg = "PolyCurve had " + numNewPoints + " point(s) after removing points that were too close, expected at least " + numMinPoints + ", ignoring."; IFCImportFile.TheLog.LogWarning(id, msg, false); } return null; } CurveLoop curveLoop = new CurveLoop(); for (int ii = 0; ii < numNewPoints - 1; ii++) curveLoop.Append(Line.CreateBound(finalPoints[ii], finalPoints[ii + 1])); if (isClosedLoop) curveLoop.Append(Line.CreateBound(finalPoints[numNewPoints - 1], finalPoints[0])); return curveLoop; }
protected override void Process(IFCAnyHandle ifcCurve) { base.Process(ifcCurve); bool found = false; bool sameSense = IFCImportHandleUtil.GetRequiredBooleanAttribute(ifcCurve, "SenseAgreement", out found); if (!found) sameSense = true; IFCAnyHandle basisCurve = IFCImportHandleUtil.GetRequiredInstanceAttribute(ifcCurve, "BasisCurve", true); IFCCurve ifcBasisCurve = IFCCurve.ProcessIFCCurve(basisCurve); if (ifcBasisCurve == null || (ifcBasisCurve.Curve == null && ifcBasisCurve.CurveLoop == null)) { // LOG: ERROR: Error processing BasisCurve # for IfcTrimmedCurve #. return; } if (ifcBasisCurve.Curve == null) { // LOG: ERROR: Expected a single curve, not a curve loop for BasisCurve # for IfcTrimmedCurve #. return; } IFCData trim1 = ifcCurve.GetAttribute("Trim1"); if (trim1.PrimitiveType != IFCDataPrimitiveType.Aggregate) { // LOG: ERROR: Invalid data type for Trim1 attribute for IfcTrimmedCurve #. return; } IFCData trim2 = ifcCurve.GetAttribute("Trim2"); if (trim2.PrimitiveType != IFCDataPrimitiveType.Aggregate) { // LOG: ERROR: Invalid data type for Trim1 attribute for IfcTrimmedCurve #. return; } IFCTrimmingPreference trimPreference = IFCEnums.GetSafeEnumerationAttribute<IFCTrimmingPreference>(ifcCurve, "MasterRepresentation", IFCTrimmingPreference.Parameter); double param1 = 0.0, param2 = 0.0; try { GetTrimParameters(trim1, trim2, ifcBasisCurve, trimPreference, out param1, out param2); } catch (Exception ex) { Importer.TheLog.LogError(ifcCurve.StepId, ex.Message, false); return; } Curve baseCurve = ifcBasisCurve.Curve; if (baseCurve.IsCyclic) { if (!sameSense) MathUtil.Swap(ref param1, ref param2); if (param2 < param1) param2 = MathUtil.PutInRange(param2, param1 + Math.PI, 2 * Math.PI); if (param2 - param1 > 2.0 * Math.PI - MathUtil.Eps()) { Importer.TheLog.LogWarning(ifcCurve.StepId, "IfcTrimmedCurve length is greater than 2*PI, leaving unbound.", false); Curve = baseCurve; return; } Curve = baseCurve.Clone(); try { Curve.MakeBound(param1, param2); } catch (Exception ex) { if (ex.Message.Contains("too small")) { Curve = null; Importer.TheLog.LogError(Id, "curve length is invalid, ignoring.", false); return; } else throw ex; } } else { if (MathUtil.IsAlmostEqual(param1, param2)) { Importer.TheLog.LogError(Id, "Param1 = Param2 for IfcTrimmedCurve #, ignoring.", false); return; } if (param1 > param2 - MathUtil.Eps()) { Importer.TheLog.LogWarning(Id, "Param1 > Param2 for IfcTrimmedCurve #, reversing.", false); MathUtil.Swap(ref param1, ref param2); return; } Curve copyCurve = baseCurve.Clone(); double length = param2 - param1; if (length <= IFCImportFile.TheFile.Document.Application.ShortCurveTolerance) { string lengthAsString = IFCUnitUtil.FormatLengthAsString(length); Importer.TheLog.LogError(Id, "curve length of " + lengthAsString + " is invalid, ignoring.", false); return; } copyCurve.MakeBound(param1, param2); if (sameSense) { Curve = copyCurve; } else { Curve = copyCurve.CreateReversed(); } } CurveLoop = new CurveLoop(); CurveLoop.Append(Curve); }
private void ProcessIFCCShapeProfileDef(IFCAnyHandle profileDef) { bool found = false; double depth = IFCImportHandleUtil.GetRequiredScaledLengthAttribute(profileDef, "Depth", out found); if (!found) return; double width = IFCImportHandleUtil.GetRequiredScaledLengthAttribute(profileDef, "Width", out found); if (!found) return; double wallThickness = IFCImportHandleUtil.GetRequiredScaledLengthAttribute(profileDef, "WallThickness", out found); if (!found) return; double girth = IFCImportHandleUtil.GetRequiredScaledLengthAttribute(profileDef, "Girth", out found); if (!found) return; // Optional parameters double centerOptX = IFCImportHandleUtil.GetOptionalScaledLengthAttribute(profileDef, "CentreOfGravityInX", 0.0); double innerRadius = IFCImportHandleUtil.GetOptionalScaledLengthAttribute(profileDef, "InternalFilletRadius", 0.0); bool hasFillet = !MathUtil.IsAlmostZero(innerRadius); double outerRadius = hasFillet ? innerRadius + wallThickness : 0.0; XYZ[] cShapePoints = new XYZ[12] { new XYZ(width/2.0 + centerOptX, -depth/2.0+girth, 0.0), new XYZ(width/2.0 + centerOptX, -depth/2.0, 0.0), new XYZ(-width/2.0 + centerOptX, -depth/2.0, 0.0), new XYZ(-width/2.0 + centerOptX, depth/2.0, 0.0), new XYZ(width/2.0 + centerOptX, depth/2.0, 0.0), new XYZ(width/2.0 + centerOptX, -(-depth/2.0+girth), 0.0), new XYZ(width/2.0 - wallThickness, -(-depth/2.0+girth), 0.0), new XYZ(width/2.0 - wallThickness, depth/2.0 - wallThickness, 0.0), new XYZ(-width/2.0 + wallThickness, depth/2.0 - wallThickness, 0.0), new XYZ(-width/2.0 + wallThickness, -depth/2.0 + wallThickness, 0.0), new XYZ(width/2.0 - wallThickness, -depth/2.0 + wallThickness, 0.0), new XYZ(width/2.0 + centerOptX - wallThickness, -depth/2.0+girth, 0.0) }; OuterCurve = new CurveLoop(); if (hasFillet) { XYZ[] cFilletPoints = new XYZ[16] { new XYZ(cShapePoints[1][0], cShapePoints[1][1] + outerRadius, 0.0), new XYZ(cShapePoints[1][0] - outerRadius, cShapePoints[1][1], 0.0), new XYZ(cShapePoints[2][0] + outerRadius, cShapePoints[2][1], 0.0), new XYZ(cShapePoints[2][0], cShapePoints[2][1] + outerRadius, 0.0), new XYZ(cShapePoints[3][0], cShapePoints[3][1] - outerRadius, 0.0), new XYZ(cShapePoints[3][0] + outerRadius, cShapePoints[3][1], 0.0), new XYZ(cShapePoints[4][0] - outerRadius, cShapePoints[4][1], 0.0), new XYZ(cShapePoints[4][0], cShapePoints[4][1] - outerRadius, 0.0), new XYZ(cShapePoints[7][0], cShapePoints[7][1] - innerRadius, 0.0), new XYZ(cShapePoints[7][0] - innerRadius, cShapePoints[7][1], 0.0), new XYZ(cShapePoints[8][0] + innerRadius, cShapePoints[8][1], 0.0), new XYZ(cShapePoints[8][0], cShapePoints[8][1] - innerRadius, 0.0), new XYZ(cShapePoints[9][0], cShapePoints[9][1] + innerRadius, 0.0), new XYZ(cShapePoints[9][0] + innerRadius, cShapePoints[9][1], 0.0), new XYZ(cShapePoints[10][0] - innerRadius, cShapePoints[10][1], 0.0), new XYZ(cShapePoints[10][0], cShapePoints[10][1] + innerRadius, 0.0) }; // shared for inner and outer. XYZ[] cFilletCenters = new XYZ[4] { new XYZ(cShapePoints[1][0] - outerRadius, cShapePoints[1][1] + outerRadius, 0.0), new XYZ(cShapePoints[2][0] + outerRadius, cShapePoints[2][1] + outerRadius, 0.0), new XYZ(cShapePoints[3][0] + outerRadius, cShapePoints[3][1] - outerRadius, 0.0), new XYZ(cShapePoints[4][0] - outerRadius, cShapePoints[4][1] - outerRadius, 0.0) }; // flip outers not inners. double[][] cRange = new double[4][] { new double[2] { 3*Math.PI/2.0, 2.0*Math.PI }, new double[2] { Math.PI, 3*Math.PI/2.0 }, new double[2] { Math.PI/2.0, Math.PI }, new double[2] { 0.0, Math.PI/2.0 } }; OuterCurve.Append(Line.CreateBound(cShapePoints[0], cFilletPoints[0])); for (int ii = 0; ii < 3; ii++) { OuterCurve.Append(CreateReversedXYArc(cFilletCenters[ii], outerRadius, cRange[ii][0], cRange[ii][1])); OuterCurve.Append(Line.CreateBound(cFilletPoints[2 * ii + 1], cFilletPoints[2 * ii + 2])); OuterCurve.Append(CreateReversedXYArc(cFilletCenters[3], outerRadius, cRange[3][0], cRange[3][1])); OuterCurve.Append(Line.CreateBound(cFilletPoints[7], cShapePoints[5])); OuterCurve.Append(Line.CreateBound(cShapePoints[5], cShapePoints[6])); OuterCurve.Append(Line.CreateBound(cShapePoints[6], cFilletPoints[8])); for (int jj = 0; jj < 3; ii++) { OuterCurve.Append(CreateXYArc(cFilletCenters[3 - jj], innerRadius, cRange[3 - jj][0], cRange[3 - jj][1])); OuterCurve.Append(Line.CreateBound(cFilletPoints[2 * jj + 9], cFilletPoints[2 * jj + 10])); } OuterCurve.Append(CreateXYArc(cFilletCenters[0], innerRadius, cRange[0][0], cRange[0][1])); OuterCurve.Append(Line.CreateBound(cFilletPoints[15], cShapePoints[11])); OuterCurve.Append(Line.CreateBound(cShapePoints[11], cShapePoints[0])); } } else { OuterCurve = CreatePolyCurveLoop(cShapePoints); } }
private void ProcessIFCZShapeProfileDef(IFCAnyHandle profileDef) { bool found = false; double flangeWidth = IFCImportHandleUtil.GetRequiredScaledLengthAttribute(profileDef, "FlangeWidth", out found); if (!found) return; double depth = IFCImportHandleUtil.GetRequiredScaledLengthAttribute(profileDef, "Depth", out found); if (!found) return; double webThickness = IFCImportHandleUtil.GetRequiredScaledLengthAttribute(profileDef, "WebThickness", out found); if (!found) return; double flangeThickness = IFCImportHandleUtil.GetRequiredScaledLengthAttribute(profileDef, "FlangeThickness", out found); if (!found) return; double filletRadius = IFCImportHandleUtil.GetOptionalScaledLengthAttribute(profileDef, "FilletRadius", 0.0); bool hasFillet = !MathUtil.IsAlmostZero(filletRadius); double edgeRadius = IFCImportHandleUtil.GetOptionalScaledLengthAttribute(profileDef, "EdgeRadius", 0.0); bool hasEdgeRadius = !MathUtil.IsAlmostZero(edgeRadius); XYZ[] zShapePoints = new XYZ[8] { new XYZ(-webThickness/2.0, -depth/2.0, 0.0), new XYZ(flangeWidth - webThickness/2.0, -depth/2.0, 0.0), new XYZ(flangeWidth - webThickness/2.0, flangeThickness - depth/2.0, 0.0), new XYZ(webThickness/2.0, flangeThickness - depth/2.0, 0.0), new XYZ(webThickness/2.0, depth/2.0, 0.0), new XYZ(webThickness/2.0 - flangeWidth, depth/2.0, 0.0), new XYZ(webThickness/2.0 - flangeWidth, depth/2.0 - flangeThickness, 0.0), new XYZ(-webThickness/2.0, depth/2.0 - flangeThickness, 0.0) }; // need to flip fillet arcs. XYZ[] zFilletPoints = new XYZ[4] { new XYZ(zShapePoints[3][0] + filletRadius, zShapePoints[3][1], 0.0), new XYZ(zShapePoints[3][0], zShapePoints[3][1] + filletRadius, 0.0), new XYZ(zShapePoints[7][0] - filletRadius, zShapePoints[7][1], 0.0), new XYZ(zShapePoints[7][0], zShapePoints[7][1] - filletRadius, 0.0) }; XYZ[] zFilletCenters = new XYZ[2] { new XYZ(zShapePoints[3][0] + filletRadius, zShapePoints[3][1] + filletRadius, 0.0), new XYZ(zShapePoints[7][0] - filletRadius, zShapePoints[7][1] - filletRadius, 0.0), }; double[][] filletRange = new double[2][] { new double[2] { Math.PI, 3*Math.PI/2.0 }, new double[2] { 0.0, Math.PI/2.0 } }; // do not flip edge arcs. XYZ[] zEdgePoints = new XYZ[4] { new XYZ(zShapePoints[2][0], zShapePoints[2][1] - edgeRadius, 0.0), new XYZ(zShapePoints[2][0] - edgeRadius, zShapePoints[2][1], 0.0), new XYZ(zShapePoints[6][0], zShapePoints[6][1] + edgeRadius, 0.0), new XYZ(zShapePoints[6][0] + edgeRadius, zShapePoints[6][1], 0.0) }; XYZ[] zEdgeCenters = new XYZ[2] { new XYZ(zShapePoints[2][0] - edgeRadius, zShapePoints[2][1] - edgeRadius, 0.0), new XYZ(zShapePoints[6][0] + edgeRadius, zShapePoints[6][1] + edgeRadius, 0.0) }; double[][] edgeRange = new double[2][] { new double[2] { 0.0, Math.PI/2.0 }, new double[2] { Math.PI, 3*Math.PI/2.0 } }; OuterCurve = new CurveLoop(); OuterCurve.Append(Line.CreateBound(zShapePoints[0], zShapePoints[1])); XYZ zNextStart = null; if (hasEdgeRadius) { OuterCurve.Append(Line.CreateBound(zShapePoints[1], zEdgePoints[0])); OuterCurve.Append(CreateXYArc(zEdgeCenters[0], edgeRadius, edgeRange[0][0], edgeRange[0][1])); zNextStart = zEdgePoints[1]; } else { OuterCurve.Append(Line.CreateBound(zShapePoints[1], zShapePoints[2])); zNextStart = zShapePoints[2]; } if (hasFillet) { OuterCurve.Append(Line.CreateBound(zNextStart, zFilletPoints[0])); OuterCurve.Append(CreateReversedXYArc(zFilletCenters[0], filletRadius, filletRange[0][0], filletRange[0][1])); zNextStart = zFilletPoints[1]; } else { OuterCurve.Append(Line.CreateBound(zNextStart, zShapePoints[3])); zNextStart = zShapePoints[3]; } OuterCurve.Append(Line.CreateBound(zNextStart, zShapePoints[4])); OuterCurve.Append(Line.CreateBound(zShapePoints[4], zShapePoints[5])); if (hasEdgeRadius) { OuterCurve.Append(Line.CreateBound(zShapePoints[5], zEdgePoints[2])); OuterCurve.Append(CreateXYArc(zEdgeCenters[1], edgeRadius, edgeRange[1][0], edgeRange[1][1])); zNextStart = zEdgePoints[3]; } else { OuterCurve.Append(Line.CreateBound(zShapePoints[5], zShapePoints[6])); zNextStart = zShapePoints[6]; } if (hasFillet) { OuterCurve.Append(Line.CreateBound(zNextStart, zFilletPoints[2])); OuterCurve.Append(CreateReversedXYArc(zFilletCenters[1], filletRadius, filletRange[1][0], filletRange[1][1])); zNextStart = zFilletPoints[3]; } else { OuterCurve.Append(Line.CreateBound(zNextStart, zShapePoints[7])); zNextStart = zShapePoints[7]; } OuterCurve.Append(Line.CreateBound(zNextStart, zShapePoints[0])); }
private IList<CurveLoop> CreateProfileCurveLoopsForDirectrix(Curve directrix, out double startParam) { startParam = 0.0; if (directrix == null) return null; if (directrix.IsBound) startParam = directrix.GetEndParameter(0); Transform originTrf = directrix.ComputeDerivatives(startParam, false); if (originTrf == null) return null; // The X-dir of the transform of the start of the directrix will form the normal of the disk. Plane diskPlane = new Plane(originTrf.BasisX, originTrf.Origin); IList<CurveLoop> profileCurveLoops = new List<CurveLoop>(); CurveLoop diskOuterCurveLoop = new CurveLoop(); diskOuterCurveLoop.Append(Arc.Create(diskPlane, Radius, 0, Math.PI)); diskOuterCurveLoop.Append(Arc.Create(diskPlane, Radius, Math.PI, 2.0 * Math.PI)); profileCurveLoops.Add(diskOuterCurveLoop); if (InnerRadius.HasValue) { CurveLoop diskInnerCurveLoop = new CurveLoop(); diskInnerCurveLoop.Append(Arc.Create(diskPlane, InnerRadius.Value, 0, Math.PI)); diskInnerCurveLoop.Append(Arc.Create(diskPlane, InnerRadius.Value, Math.PI, 2.0 * Math.PI)); profileCurveLoops.Add(diskInnerCurveLoop); } return profileCurveLoops; }
private void ProcessIFCLShapeProfileDef(IFCAnyHandle profileDef) { bool found = false; double depth = IFCImportHandleUtil.GetRequiredScaledLengthAttribute(profileDef, "Depth", out found); if (!found) return; double thickness = IFCImportHandleUtil.GetRequiredScaledLengthAttribute(profileDef, "Thickness", out found); if (!found) return; double width = IFCImportHandleUtil.GetOptionalScaledLengthAttribute(profileDef, "Width", depth); double filletRadius = IFCImportHandleUtil.GetOptionalScaledLengthAttribute(profileDef, "FilletRadius", 0.0); bool filletedCorner = !MathUtil.IsAlmostZero(filletRadius); double edgeRadius = IFCImportHandleUtil.GetOptionalScaledLengthAttribute(profileDef, "EdgeRadius", 0.0); bool filletedEdge = !MathUtil.IsAlmostZero(edgeRadius); if (filletedEdge && (thickness < edgeRadius - MathUtil.Eps())) { // LOG: WARN: IFC: In IfcLShapeProfileDef (#id), edgeRadius (value) >= thickness (value), ignoring." filletedEdge = false; } bool fullFilletedEdge = (filletedEdge && MathUtil.IsAlmostEqual(thickness, edgeRadius)); double centerOptX = IFCImportHandleUtil.GetOptionalScaledLengthAttribute(profileDef, "CentreOfGravityInX", 0.0); double centerOptY = IFCImportHandleUtil.GetOptionalScaledLengthAttribute(profileDef, "CentreOfGravityInY", centerOptX); // TODO: use leg slope double legSlope = IFCImportHandleUtil.GetOptionalScaledAngleAttribute(profileDef, "LegSlope", 0.0); XYZ lOrig = new XYZ(-width/2.0+centerOptX, -depth/2.0+centerOptY, 0.0); XYZ lLR = new XYZ(lOrig[0] + width, lOrig[1], 0.0); XYZ lLRPlusThickness = new XYZ(lLR[0], lLR[1] + thickness, 0.0); XYZ lCorner = new XYZ(lOrig[0] + thickness, lOrig[1] + thickness, 0.0); XYZ lULPlusThickness = new XYZ(lOrig[0] + thickness, lOrig[1] + depth, 0.0); XYZ lUL = new XYZ(lULPlusThickness[0] - thickness, lULPlusThickness[1], 0.0); // fillet modifications. double[] edgeRanges = new double[2]; XYZ lLREdgeCtr = null, lULEdgeCtr = null; XYZ lLRStartFillet = null, lLREndFillet = null; XYZ lULStartFillet = null, lULEndFillet = null; if (filletedEdge) { lLREdgeCtr = new XYZ(lLRPlusThickness[0] - edgeRadius, lLRPlusThickness[1] - edgeRadius, 0.0); lULEdgeCtr = new XYZ(lULPlusThickness[0] - edgeRadius, lULPlusThickness[1] - edgeRadius, 0.0); lLRStartFillet = new XYZ(lLRPlusThickness[0], lLRPlusThickness[1] - edgeRadius, 0.0); lLREndFillet = new XYZ(lLRPlusThickness[0] - edgeRadius, lLRPlusThickness[1], 0.0); lULStartFillet = new XYZ(lULPlusThickness[0], lULPlusThickness[1] - edgeRadius, 0.0); lULEndFillet = new XYZ(lULPlusThickness[0] - edgeRadius, lULPlusThickness[1], 0.0); edgeRanges[0] = 0.0; edgeRanges[1] = Math.PI / 2.0; } XYZ lLRCorner = null, lULCorner = null, lFilletCtr = null; double[] filletRange = new double[2]; if (filletedCorner) { lLRCorner = new XYZ(lCorner[0] + filletRadius, lCorner[1], lCorner[2]); lULCorner = new XYZ( lCorner[0], lCorner[1] + filletRadius, lCorner[2]); lFilletCtr = new XYZ(lCorner[0] + filletRadius, lCorner[1] + filletRadius, lCorner[2]); filletRange[0] = Math.PI; filletRange[1] = 3.0 * Math.PI / 2; } OuterCurve = new CurveLoop(); OuterCurve.Append(Line.CreateBound(lOrig, lLR)); XYZ startCornerPoint = null, endCornerPoint = null; if (filletedEdge) { startCornerPoint = lLREndFillet; endCornerPoint = lULStartFillet; } else { startCornerPoint = lLRPlusThickness; endCornerPoint = lULPlusThickness; } if (filletedEdge) { if (!fullFilletedEdge) { OuterCurve.Append(Line.CreateBound(lLR, lLRStartFillet)); } OuterCurve.Append(CreateXYArc(lLREdgeCtr, edgeRadius, edgeRanges[0], edgeRanges[1])); } else { OuterCurve.Append(Line.CreateBound(lLR, startCornerPoint)); } if (filletedCorner) { OuterCurve.Append(Line.CreateBound(startCornerPoint, lLRCorner)); OuterCurve.Append(CreateReversedXYArc(lFilletCtr, filletRadius, filletRange[0], filletRange[1])); OuterCurve.Append(Line.CreateBound(lULCorner, endCornerPoint)); } else { OuterCurve.Append(Line.CreateBound(startCornerPoint, lCorner)); OuterCurve.Append(Line.CreateBound(lCorner, endCornerPoint)); } if (filletedEdge) { OuterCurve.Append(CreateXYArc(lULEdgeCtr, edgeRadius, edgeRanges[0], edgeRanges[1])); if (!fullFilletedEdge) { OuterCurve.Append(Line.CreateBound(lULEndFillet, lUL)); } } else { OuterCurve.Append(Line.CreateBound(endCornerPoint, lUL)); } OuterCurve.Append(Line.CreateBound(lUL, lOrig)); }
/// <summary> /// Creates or populates Revit elements based on the information contained in this class. /// </summary> /// <param name="doc">The document.</param> protected override void Create(Document doc) { Transform lcs = (ObjectLocation != null) ? ObjectLocation.TotalTransform : Transform.Identity; // 2015+: create cone(s) for the direction of flow. CurveLoop rightTrangle = new CurveLoop(); const double radius = 0.5/12.0; const double height = 1.5/12.0; SolidOptions solidOptions = new SolidOptions(ElementId.InvalidElementId, GraphicsStyleId); Frame coordinateFrame = new Frame(lcs.Origin, lcs.BasisX, lcs.BasisY, lcs.BasisZ); // The origin is at the base of the cone for everything but source - then it is at the top of the cone. XYZ pt1 = FlowDirection == IFCFlowDirection.Source ? lcs.Origin - height * lcs.BasisZ : lcs.Origin; XYZ pt2 = pt1 + radius * lcs.BasisX; XYZ pt3 = pt1 + height * lcs.BasisZ; rightTrangle.Append(Line.CreateBound(pt1, pt2)); rightTrangle.Append(Line.CreateBound(pt2, pt3)); rightTrangle.Append(Line.CreateBound(pt3, pt1)); IList<CurveLoop> curveLoops = new List<CurveLoop>(); curveLoops.Add(rightTrangle); Solid portArrow = GeometryCreationUtilities.CreateRevolvedGeometry(coordinateFrame, curveLoops, 0.0, Math.PI * 2.0, solidOptions); Solid oppositePortArrow = null; if (FlowDirection == IFCFlowDirection.SourceAndSink) { Frame oppositeCoordinateFrame = new Frame(lcs.Origin, -lcs.BasisX, lcs.BasisY, -lcs.BasisZ); CurveLoop oppositeRightTrangle = new CurveLoop(); XYZ oppPt2 = pt1 - radius * lcs.BasisX; XYZ oppPt3 = pt1 - height * lcs.BasisZ; oppositeRightTrangle.Append(Line.CreateBound(pt1, oppPt2)); oppositeRightTrangle.Append(Line.CreateBound(oppPt2, oppPt3)); oppositeRightTrangle.Append(Line.CreateBound(oppPt3, pt1)); IList<CurveLoop> oppositeCurveLoops = new List<CurveLoop>(); oppositeCurveLoops.Add(oppositeRightTrangle); oppositePortArrow = GeometryCreationUtilities.CreateRevolvedGeometry(oppositeCoordinateFrame, oppositeCurveLoops, 0.0, Math.PI * 2.0, solidOptions); } if (portArrow != null) { IList<GeometryObject> geomObjs = new List<GeometryObject>(); geomObjs.Add(portArrow); if (oppositePortArrow != null) geomObjs.Add(oppositePortArrow); DirectShape directShape = IFCElementUtil.CreateElement(doc, CategoryId, GlobalId, geomObjs); if (directShape != null) { CreatedGeometry = geomObjs; CreatedElementId = directShape.Id; } else Importer.TheLog.LogCreationError(this, null, false); } }
private void ProcessIFCIShapeProfileDef(IFCAnyHandle profileDef) { bool found = false; double width = IFCImportHandleUtil.GetRequiredScaledLengthAttribute(profileDef, "OverallWidth", out found); if (!found) return; double depth = IFCImportHandleUtil.GetRequiredScaledLengthAttribute(profileDef, "OverallDepth", out found); if (!found) return; double webThickness = IFCImportHandleUtil.GetRequiredScaledLengthAttribute(profileDef, "WebThickness", out found); if (!found) return; double flangeThickness = IFCImportHandleUtil.GetRequiredScaledLengthAttribute(profileDef, "FlangeThickness", out found); if (!found) return; double filletRadius = IFCImportHandleUtil.GetOptionalScaledLengthAttribute(profileDef, "FilletRadius", 0.0); bool hasFillet = !MathUtil.IsAlmostZero(filletRadius); // take advantage of X/Y symmetries below. XYZ[] iShapePoints = new XYZ[12] { new XYZ(-width/2.0, -depth/2.0, 0.0), new XYZ(width/2.0, -depth/2.0, 0.0), new XYZ(width/2.0, -depth/2.0 + flangeThickness, 0.0), new XYZ(webThickness/2.0, -depth/2.0 + flangeThickness, 0.0), new XYZ(webThickness/2.0, -(-depth/2.0 + flangeThickness), 0.0), new XYZ(width/2.0, -(-depth/2.0 + flangeThickness), 0.0), new XYZ(width/2.0, depth/2.0, 0.0), new XYZ(-width/2.0, depth/2.0, 0.0), new XYZ(-width/2.0, -(-depth/2.0 + flangeThickness), 0.0), new XYZ(-webThickness/2.0, -(-depth/2.0 + flangeThickness), 0.0), new XYZ(-webThickness/2.0, -depth/2.0 + flangeThickness, 0.0), new XYZ(-width/2.0, -depth/2.0 + flangeThickness, 0.0) }; if (hasFillet) { OuterCurve = new CurveLoop(); XYZ[] iFilletPoints = new XYZ[8] { new XYZ(iShapePoints[3][0] + filletRadius, iShapePoints[3][1], 0.0), new XYZ(iShapePoints[3][0], iShapePoints[3][1] + filletRadius, 0.0), new XYZ(iShapePoints[4][0], iShapePoints[4][1] - filletRadius, 0.0), new XYZ(iShapePoints[4][0] + filletRadius, iShapePoints[4][1], 0.0), new XYZ(iShapePoints[9][0] - filletRadius, iShapePoints[9][1], 0.0), new XYZ(iShapePoints[9][0], iShapePoints[9][1] - filletRadius, 0.0), new XYZ(iShapePoints[10][0], iShapePoints[10][1] + filletRadius, 0.0), new XYZ(iShapePoints[10][0] - filletRadius, iShapePoints[10][1], 0.0) }; XYZ[] iFilletCtr = new XYZ[4] { new XYZ(iShapePoints[3][0] + filletRadius, iShapePoints[3][1] + filletRadius, 0.0), new XYZ(iShapePoints[4][0] + filletRadius, iShapePoints[4][1] - filletRadius, 0.0), new XYZ(iShapePoints[9][0] - filletRadius, iShapePoints[9][1] - filletRadius, 0.0), new XYZ(iShapePoints[10][0] - filletRadius, iShapePoints[10][1] + filletRadius, 0.0) }; // need to flip all fillets. double[][] filletRanges = new double[4][] { new double[2] { Math.PI, 3.0*Math.PI/2 }, new double[2] { Math.PI/2.0, Math.PI }, new double[2] { 0, Math.PI/2.0 }, new double[2] { 3.0*Math.PI/2, 2.0*Math.PI } }; OuterCurve.Append(Line.CreateBound(iShapePoints[0], iShapePoints[1])); OuterCurve.Append(Line.CreateBound(iShapePoints[1], iShapePoints[2])); OuterCurve.Append(Line.CreateBound(iShapePoints[2], iFilletPoints[0])); OuterCurve.Append(CreateReversedXYArc(iFilletCtr[0], filletRadius, filletRanges[0][0], filletRanges[0][1])); OuterCurve.Append(Line.CreateBound(iFilletPoints[1], iFilletPoints[2])); OuterCurve.Append(CreateReversedXYArc(iFilletCtr[1], filletRadius, filletRanges[1][0], filletRanges[1][1])); OuterCurve.Append(Line.CreateBound(iFilletPoints[3], iShapePoints[5])); OuterCurve.Append(Line.CreateBound(iShapePoints[5], iShapePoints[6])); OuterCurve.Append(Line.CreateBound(iShapePoints[6], iShapePoints[7])); OuterCurve.Append(Line.CreateBound(iShapePoints[7], iShapePoints[8])); OuterCurve.Append(Line.CreateBound(iShapePoints[8], iFilletPoints[4])); OuterCurve.Append(CreateReversedXYArc(iFilletCtr[2], filletRadius, filletRanges[2][0], filletRanges[2][1])); OuterCurve.Append(Line.CreateBound(iFilletPoints[5], iFilletPoints[6])); OuterCurve.Append(CreateReversedXYArc(iFilletCtr[3], filletRadius, filletRanges[3][0], filletRanges[3][1])); OuterCurve.Append(Line.CreateBound(iFilletPoints[7], iShapePoints[11])); OuterCurve.Append(Line.CreateBound(iShapePoints[11], iShapePoints[0])); } else { OuterCurve = CreatePolyCurveLoop(iShapePoints); } }