private XYZ GetValidXVectorFromLoop(CurveLoop curveLoop, XYZ zVec, XYZ origin) { foreach (Curve curve in curveLoop) { IList<XYZ> pointsToCheck = new List<XYZ>(); // If unbound, must be cyclic. if (!curve.IsBound) { pointsToCheck.Add(curve.Evaluate(0, false)); pointsToCheck.Add(curve.Evaluate(Math.PI / 2.0, false)); pointsToCheck.Add(curve.Evaluate(Math.PI, false)); } else { pointsToCheck.Add(curve.Evaluate(0, true)); pointsToCheck.Add(curve.Evaluate(1.0, true)); if (curve.IsCyclic) pointsToCheck.Add(curve.Evaluate(0.5, true)); } foreach (XYZ pointToCheck in pointsToCheck) { XYZ possibleVec = (pointToCheck - origin); XYZ yVec = zVec.CrossProduct(possibleVec).Normalize(); if (yVec.IsZeroLength()) continue; return yVec.CrossProduct(zVec); } } return null; }
/// <summary> /// Determines if curve loop is counterclockwise. /// </summary> /// <param name="curveLoop"> /// The curveLoop. /// </param> /// <param name="normal"> /// The normal. /// </param> /// <returns> /// Returns true only if the loop is counterclockwise, false otherwise. /// </returns> public static bool IsIFCLoopCCW(CurveLoop curveLoop, XYZ normal) { if (curveLoop == null) throw new Exception("CurveLoop is null."); // If loop is not suitable for ccw evaluation an exception is thrown return curveLoop.IsCounterclockwise(normal); }
protected override CurveLoop GenerateLoop() { CurveLoop curveLoop = new CurveLoop(); foreach (IFCOrientedEdge edge in EdgeList) { if (edge != null) curveLoop.Append(edge.GetGeometry()); } return curveLoop; }
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; }
private static bool CurveLoopIsARectangle(CurveLoop curveLoop, out IList<int> cornerIndices) { cornerIndices = new List<int>(4); // looking for four orthogonal lines in one curve loop. int sz = curveLoop.Count(); if (sz < 4) return false; IList<Line> lines = new List<Line>(); foreach (Curve curve in curveLoop) { if (!(curve is Line)) return false; lines.Add(curve as Line); } sz = lines.Count; int numAngles = 0; // Must have 4 right angles found, and all other lines collinear -- if not, not a rectangle. for (int ii = 0; ii < sz; ii++) { double dot = lines[ii].Direction.DotProduct(lines[(ii + 1) % sz].Direction); if (MathUtil.IsAlmostZero(dot)) { if (numAngles > 3) return false; cornerIndices.Add(ii); numAngles++; } else if (MathUtil.IsAlmostEqual(dot, 1.0)) { XYZ line0End1 = lines[ii].GetEndPoint(1); XYZ line1End0 = lines[(ii + 1) % sz].GetEndPoint(0); if (!line0End1.IsAlmostEqualTo(line1End0)) return false; } else return false; } return (numAngles == 4); }
/// <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; }
/// <summary> /// Create a curve representation of this IFCCompositeCurve from a curveloop /// </summary> /// <param name="curveLoop">The curveloop</param> /// <returns>A Revit curve that is made by appending every curve in the given curveloop, if possible</returns> private Curve ConvertCurveLoopIntoSingleCurve(CurveLoop curveLoop) { if (curveLoop == null) { return(null); } CurveLoopIterator curveIterator = curveLoop.GetCurveLoopIterator(); Curve firstCurve = curveIterator.Current; Curve returnCurve = null; // We only connect the curves if they are Line, Arc or Ellipse if (!((firstCurve is Line) || (firstCurve is Arc) || (firstCurve is Ellipse))) { return(null); } XYZ firstStartPoint = firstCurve.GetEndPoint(0); Curve currentCurve = null; if (firstCurve is Line) { Line firstLine = firstCurve as Line; while (curveIterator.MoveNext()) { currentCurve = curveIterator.Current; if (!(currentCurve is Line)) { return(null); } Line currentLine = currentCurve as Line; if (!(firstLine.Direction.IsAlmostEqualTo(currentLine.Direction))) { return(null); } } returnCurve = Line.CreateBound(firstStartPoint, currentCurve.GetEndPoint(1)); } else if (firstCurve is Arc) { Arc firstArc = firstCurve as Arc; XYZ firstCurveNormal = firstArc.Normal; while (curveIterator.MoveNext()) { currentCurve = curveIterator.Current; if (!(currentCurve is Arc)) { return(null); } XYZ currentStartPoint = currentCurve.GetEndPoint(0); XYZ currentEndPoint = currentCurve.GetEndPoint(1); Arc currentArc = currentCurve as Arc; XYZ currentCenter = currentArc.Center; double currentRadius = currentArc.Radius; XYZ currentNormal = currentArc.Normal; // We check if this circle is similar to the first circle by checking that they have the same center, same radius, // and lie on the same plane if (!(currentCenter.IsAlmostEqualTo(firstArc.Center) && MathUtil.IsAlmostEqual(currentRadius, firstArc.Radius))) { return(null); } if (!MathUtil.IsAlmostEqual(Math.Abs(currentNormal.DotProduct(firstCurveNormal)), 1)) { return(null); } } // If all of the curve segments are part of the same circle, then the returning curve will be a circle bounded // by the start point of the first curve and the end point of the last curve. XYZ lastPoint = currentCurve.GetEndPoint(1); if (lastPoint.IsAlmostEqualTo(firstStartPoint)) { firstCurve.MakeUnbound(); } else { double startParameter = firstArc.GetEndParameter(0); double endParameter = firstArc.Project(lastPoint).Parameter; if (endParameter < startParameter) { endParameter += Math.PI * 2; } firstCurve.MakeBound(startParameter, endParameter); } returnCurve = firstCurve; } else if (firstCurve is Ellipse) { Ellipse firstEllipse = firstCurve as Ellipse; double radiusX = firstEllipse.RadiusX; double radiusY = firstEllipse.RadiusY; XYZ xDirection = firstEllipse.XDirection; XYZ yDirection = firstEllipse.YDirection; XYZ firstCurveNormal = firstEllipse.Normal; while (curveIterator.MoveNext()) { currentCurve = curveIterator.Current; if (!(currentCurve is Ellipse)) { return(null); } XYZ currentStartPoint = currentCurve.GetEndPoint(0); XYZ currentEndPoint = currentCurve.GetEndPoint(1); Ellipse currentEllipse = currentCurve as Ellipse; XYZ currentCenter = currentEllipse.Center; double currentRadiusX = currentEllipse.RadiusX; double currentRadiusY = currentEllipse.RadiusY; XYZ currentXDirection = currentEllipse.XDirection; XYZ currentYDirection = currentEllipse.YDirection; XYZ currentNormal = currentEllipse.Normal; if (!MathUtil.IsAlmostEqual(Math.Abs(currentNormal.DotProduct(firstCurveNormal)), 1)) { return(null); } // We determine whether this ellipse is the same as the initial ellipse by checking if their centers and corresponding // radiuses as well as radius directions are the same or permutations of each other. if (!currentCenter.IsAlmostEqualTo(firstEllipse.Center)) { return(null); } // Checks if the corresponding radius and radius direction are the same if (MathUtil.IsAlmostEqual(radiusX, currentRadiusX)) { if (!(MathUtil.IsAlmostEqual(radiusY, currentRadiusY) && currentXDirection.IsAlmostEqualTo(xDirection) && currentYDirection.IsAlmostEqualTo(yDirection))) { return(null); } } // Checks if the corresponding radiuses and radius directions are permutations of each other else if (MathUtil.IsAlmostEqual(radiusX, currentRadiusY)) { if (!(MathUtil.IsAlmostEqual(radiusY, currentRadiusX) && currentXDirection.IsAlmostEqualTo(yDirection) && currentYDirection.IsAlmostEqualTo(xDirection))) { return(null); } } else { return(null); } } // If all of the curve segments are part of the same ellipse then the returning curve will be the ellipse whose start point is the start // point of the first curve and the end point is the end point of the last curve XYZ lastPoint = currentCurve.GetEndPoint(1); if (lastPoint.IsAlmostEqualTo(firstStartPoint)) { firstCurve.MakeUnbound(); } else { double startParameter = firstEllipse.GetEndParameter(0); double endParameter = firstEllipse.Project(lastPoint).Parameter; if (endParameter < startParameter) { endParameter += Math.PI * 2; } firstCurve.MakeBound(startParameter, endParameter); } returnCurve = firstCurve; } return(returnCurve); }
/// <summary> /// Get the curve from the Axis representation of the given IfcProduct, transformed to the current local coordinate system. /// </summary> /// <param name="creator">The IfcProduct that may or may not contain a valid axis curve.</param> /// <param name="lcs">The local coordinate system.</param> /// <returns>The axis curve, if found, and valid.</returns> /// <remarks>In this case, we only allow bounded lines and arcs to be valid axis curves, as per IFC2x3 convention. /// The Curve may be contained as either a single Curve in the IFCCurve representation item, or it could be an /// open CurveLoop with one item.</remarks> private Curve GetAxisCurve(IFCProduct creator, Transform lcs) { // We need an axis curve to clip the extrusion profiles; if we can't get one, fail IFCProductRepresentation productRepresentation = creator.ProductRepresentation; if (productRepresentation == null) { return(null); } IList <IFCRepresentation> representations = productRepresentation.Representations; if (representations == null) { return(null); } foreach (IFCRepresentation representation in representations) { // Go through the list of representations for this product, to find the Axis representation. if (representation == null || representation.Identifier != IFCRepresentationIdentifier.Axis) { continue; } IList <IFCRepresentationItem> items = representation.RepresentationItems; if (items == null) { continue; } // Go through the list of representation items in the Axis representation, to look for the IfcCurve. foreach (IFCRepresentationItem item in items) { if (item is IFCCurve) { // We will accept either a bounded Curve of type Line or Arc, // or an open CurveLoop with one curve that satisfies the same condition. IFCCurve ifcCurve = item as IFCCurve; Curve axisCurve = ifcCurve.Curve; if (axisCurve == null) { CurveLoop axisCurveLoop = ifcCurve.CurveLoop; if (axisCurveLoop != null && axisCurveLoop.IsOpen() && axisCurveLoop.Count() == 1) { axisCurve = axisCurveLoop.First(); if (!(axisCurve is Line || axisCurve is Arc)) { axisCurve = null; } } } if (axisCurve != null) { return(axisCurve.CreateTransformed(lcs)); } } } } return(null); }
/// <summary> /// 梁柱连接 /// </summary> /// <param name="beamList">梁的实例</param> /// <param name="colList">柱子的实例</param> /// <param name="doc">项目文档</param> private void JoinBeamAndColumns(ref List <FamilyInstance> beamList, List <FamilyInstance> colList, Document doc) { if (colList.Count != 0 && beamList.Count != 0) { List <XYZ> colPosList = colList.ConvertAll(m => (m.Location as LocationPoint).Point); Level lev = doc.GetElement(beamList[0].Host.Id) as Level; List <FamilyInstance> BeamNotJoinNowColListList = new List <FamilyInstance>(); //需要改变定位线的梁、 List <ElementId> beamElemChnageIds = new List <ElementId>(); List <Line> beamLocationCurveList = new List <Line>(); foreach (FamilyInstance col in colList) { XYZ colPos = (col.Location as LocationPoint).Point; XYZ direction = -XYZ.BasisZ; double b = col.Symbol.LookupParameter("b").AsDouble(); double h = col.Symbol.LookupParameter("h").AsDouble(); double length = b > h ? b : h; double curveLoopWidth = length / 2 + 200 / 304.8; CurveLoop cuLoop = new CurveLoop(); double x = colPos.X; double y = colPos.Y; double z = lev.Elevation; //左上 XYZ p1 = new XYZ(x - curveLoopWidth, y + curveLoopWidth, z); //左下 XYZ p2 = p1 + new XYZ(0, -2 * curveLoopWidth, 0); //右下 XYZ p3 = p2 + new XYZ(2 * curveLoopWidth, 0, 0); //右上 XYZ p4 = p3 + new XYZ(0, 2 * curveLoopWidth, 0); Curve c1 = Line.CreateBound(p1, p2); Curve c2 = Line.CreateBound(p2, p3); Curve c3 = Line.CreateBound(p3, p4); Curve c4 = Line.CreateBound(p4, p1); cuLoop.Append(c1); cuLoop.Append(c2); cuLoop.Append(c3); cuLoop.Append(c4); Solid intersectSolid = GeometryCreationUtilities.CreateExtrusionGeometry(new List <CurveLoop>() { cuLoop }, direction, 200 / 304.8); ElementIntersectsSolidFilter ElemInsectSolidFilter = new ElementIntersectsSolidFilter(intersectSolid); IList <Element> beamNotJoinColList = new FilteredElementCollector(doc).OfClass(typeof(FamilyInstance)) .OfCategory(BuiltInCategory.OST_StructuralFraming).WherePasses(ElemInsectSolidFilter).ToElements(). Where(m => !JoinGeometryUtils.AreElementsJoined(doc, m, col)).ToList(); //Transaction trans = new Transaction(doc, "创建内建模型"); //trans.Start(); //DirectShapeType drt = DirectShapeType.Create(doc, "实体", new ElementId(BuiltInCategory.OST_Parts)); //DirectShape ds = DirectShape.CreateElement(doc, new ElementId(BuiltInCategory.OST_Parts), Guid.NewGuid().ToString(), Guid.NewGuid().ToString()); //ds.SetShape(new List<GeometryObject>() { intersectSolid }); //ds.SetTypeId(drt.Id); //trans.Commit(); //TaskDialog.Show("biao", "uu"); foreach (Element e in beamNotJoinColList) { //判断是否发生了变化 bool pd = true; Line l = (e.Location as LocationCurve).Curve is Line ? (e.Location as LocationCurve).Curve as Line : null; if (l == null) { continue; } XYZ lp1 = l.GetEndPoint(0); XYZ lp2 = l.GetEndPoint(1); XYZ dirt = (lp1 - lp2) / lp1.DistanceTo(lp2); //当柱端点与梁端点相距不超过某个值是默认让其相交 XYZ pi = new XYZ(x, y, z); if (lp1.DistanceTo(pi) < curveLoopWidth) { if (dirt.IsAlmostEqualTo(new XYZ(0, 1, 0)) || dirt.IsAlmostEqualTo(new XYZ(0, -1, 0))) { lp1 = new XYZ(lp1.X, pi.Y, lev.Elevation); } else if (dirt.IsAlmostEqualTo(new XYZ(-1, 0, 0)) || dirt.IsAlmostEqualTo(new XYZ(1, 0, 0))) { lp1 = new XYZ(pi.X, lp1.Y, lev.Elevation); } else { continue; } } else if (lp2.DistanceTo(pi) < curveLoopWidth) { if (dirt.IsAlmostEqualTo(new XYZ(0, 1, 0)) || dirt.IsAlmostEqualTo(new XYZ(0, -1, 0))) { lp2 = new XYZ(lp2.X, pi.Y, lev.Elevation); } else if (dirt.IsAlmostEqualTo(new XYZ(-1, 0, 0)) || dirt.IsAlmostEqualTo(new XYZ(1, 0, 0))) { lp2 = new XYZ(pi.X, lp2.Y, lev.Elevation); } else { continue; } } else { pd = false; } if (pd == true) { if (beamElemChnageIds.Count() == 0 || beamElemChnageIds.Where(m => m == e.Id).Count() == 0) { beamElemChnageIds.Add(e.Id); beamLocationCurveList.Add(Line.CreateBound(lp1, lp2)); } else { int index = beamElemChnageIds.IndexOf(e.Id); Line indexLine = beamLocationCurveList.ElementAt(index); XYZ pone = indexLine.GetEndPoint(0); XYZ ptwo = indexLine.GetEndPoint(1); //变化的线 Line linelast1 = Line.CreateBound(pone, lp2); Line linelast2 = Line.CreateBound(lp1, ptwo); beamLocationCurveList[index] = linelast1.Length > linelast2.Length ? linelast1 : linelast2; } } } } //创建新的梁实例 using (Transaction transChange = new Transaction(doc)) { transChange.Start("join"); foreach (ElementId beamId in beamElemChnageIds) { int index = beamElemChnageIds.IndexOf(beamId); Element beam = doc.GetElement(beamId); (beam.Location as LocationCurve).Curve = beamLocationCurveList[index]; TaskDialog.Show("kaishi", "sdduas"); } transChange.Commit(); } using (Transaction trans = new Transaction(doc, "调整顺序")) { trans.Start(); //梁柱剪切关系 foreach (FamilyInstance col in colList) { foreach (FamilyInstance beam in beamList) { if (JoinGeometryUtils.AreElementsJoined(doc, beam, col) == true) { if (JoinGeometryUtils.IsCuttingElementInJoin(doc, beam, col)) { JoinGeometryUtils.SwitchJoinOrder(doc, col, beam); } } } } trans.Commit(); } } }
/// <summary> /// Reverses curve loop. /// </summary> /// <param name="curveloop"> /// The curveloop. /// </param> /// <returns> /// The reversed curve loop. /// </returns> public static CurveLoop ReverseOrientation(CurveLoop curveloop) { CurveLoop copyOfCurveLoop = CurveLoop.CreateViaCopy(curveloop); copyOfCurveLoop.Flip(); return copyOfCurveLoop; }
private static IList<UV> TransformAndProjectCurveLoopToPlane(ExporterIFC exporterIFC, CurveLoop loop, Plane projScaledPlane) { IList<UV> uvs = new List<UV>(); XYZ projDir = projScaledPlane.Normal; foreach (Curve curve in loop) { XYZ point = curve.get_EndPoint(0); XYZ scaledPoint = ExporterIFCUtils.TransformAndScalePoint(exporterIFC, point); UV scaledUV = ProjectPointToPlane(projScaledPlane, projDir, scaledPoint); uvs.Add(scaledUV); } return uvs; }
public Result Execute( ExternalCommandData commandData, ref string message, ElementSet elements) { UIApplication uiapp = commandData.Application; UIDocument uidoc = uiapp.ActiveUIDocument; Document doc = uidoc.Document; Reference r = uidoc.Selection.PickObject(ObjectType.Element, "Select Element"); Options geometryOptions = new Options(); geometryOptions.ComputeReferences = false; GeometryElement geomElem = doc.GetElement(r).get_Geometry(geometryOptions); List <NurbSpline> cadSplines = new List <NurbSpline>(); IList <XYZ> controlPoints = new List <XYZ>(); List <double> weights = new List <double>(); List <double> knots = new List <double>(); if (null != geomElem) { foreach (var o in geomElem) { GeometryInstance gi = o as GeometryInstance; GeometryElement instanceGeometryElement = gi.GetInstanceGeometry(); foreach (GeometryObject instanceObj in instanceGeometryElement) { if (instanceObj.GetType().ToString().Contains("NurbSpline")) { //TaskDialog.Show("r", instanceObj.GetType().ToString()); NurbSpline nurb = instanceObj as NurbSpline; cadSplines.Add(nurb); controlPoints = nurb.CtrlPoints; //weights = nurb.Weights; weights = nurb.Weights.Cast <double>().ToList(); //knots = nurb.Knots; knots = nurb.Knots.Cast <double>().ToList(); } break; } } } double scale = 0.3048; #region Test //List<XYZ> controlPoints = new List<XYZ>(); //controlPoints.Add(new XYZ(0 / scale, 0 / scale, 0 / scale)); //controlPoints.Add(new XYZ(5 / scale, 5 / scale, 2 / scale)); //controlPoints.Add(new XYZ(10 / scale, 10 / scale, 5 / scale)); //controlPoints.Add(new XYZ(15 / scale, 10 / scale, 5 / scale)); //controlPoints.Add(new XYZ(20 / scale, 5 / scale, 4 / scale)); //controlPoints.Add(new XYZ(25 / scale, 5 / scale, 3 / scale)); //List<double> weights = new List<double>(); //weights.Add(1.0); //weights.Add(1.0); //weights.Add(1.0); //weights.Add(1.0); //weights.Add(1.0); //weights.Add(1.0); //List<double> knots = new List<double>(); //knots.Add(0); //1revit //knots.Add(0); //2 //knots.Add(0); //3 //knots.Add(0); //4 //knots.Add(10.76); //5 //knots.Add(21.51); //6 //knots.Add(32.27); //7 //knots.Add(32.27); //knots.Add(32.27); //9 //knots.Add(32.27);//revit #endregion HermiteSpline hermspline = HermiteSpline.Create(controlPoints, false); //Curve nurbSpline = NurbSpline.Create(hermspline); Curve nurbSpline = NurbSpline.CreateCurve(3, knots, controlPoints, weights); //XYZ startPoint = nurbSpline.GetEndPoint(0); Transform nurbsTr = nurbSpline.ComputeDerivatives(0, true); XYZ startPoint = nurbsTr.Origin; //PrintPoint("a", nurbsTr.Origin); #region Test Plane //Plane geomPlane = Autodesk.Revit.DB.Plane.CreateByOriginAndBasis(nurbsTr.Origin, nurbsTr.BasisY.Normalize(), nurbsTr.BasisZ.Normalize()); //Plane geomPlane = Autodesk.Revit.DB.Plane.CreateByOriginAndBasis(nurbSpline.GetEndPoint(0), nurbsTr.BasisY.Normalize(), nurbsTr.BasisZ.Normalize()); //Frame f = new Frame(nurbSpline.GetEndPoint(0), nurbsTr.BasisY.Normalize(), nurbsTr.BasisZ.Normalize(), nurbsTr.BasisX.Normalize()); //Plane geomPlane = Autodesk.Revit.DB.Plane.CreateByThreePoints(XYZ.Zero, XYZ.BasisX, XYZ.BasisZ); //Plane geomPlane = Plane.CreateByNormalAndOrigin(nurbsTr.BasisX.Normalize(), nurbSpline.GetEndPoint(1)); funziona //Plane geomPlane = Plane.CreateByThreePoints(startPoint, startPoint + nurbsTr.BasisX.Normalize(), startPoint + XYZ.BasisZ); #endregion //XYZ curveDir = controlPoints[1] - controlPoints[0]; XYZ curveDir = nurbsTr.BasisX; XYZ perpDir = curveDir.CrossProduct(startPoint + XYZ.BasisZ).Normalize(); Plane perpPlane = Plane.CreateByNormalAndOrigin(curveDir, startPoint); //Plane vertPlane = Plane.CreateByThreePoints(startPoint, perpPlane.XVec, XYZ.BasisZ); Plane vertPlane = perpPlane; //PrintPoint("per", perpDir); List <PtCoord> pointsCoordinates = new List <PtCoord>(); using (var form = new FormAddActiveView("Enter coordinates in clockwise order")) { form.ShowDialog(); //if the user hits cancel just drop out of macro if (form.DialogResult == System.Windows.Forms.DialogResult.Cancel) { return(Result.Cancelled); } string[] inputs = form.TextString.Split(';'); foreach (string coord in inputs) { string[] xy = coord.Split(','); pointsCoordinates.Add(new PtCoord(Double.Parse(xy[0]) / (scale * 1000), Double.Parse(xy[1]) / (scale * 1000))); } } // List<PtCoord> pointsCoordinates = new List<PtCoord>(){new PtCoord(5,0), new PtCoord(2,2), new PtCoord(-14,0), new PtCoord(2,-2)}; List <XYZ> pts = VertexPoints(nurbsTr.Origin, pointsCoordinates, vertPlane); XYZ pt1 = nurbsTr.Origin; XYZ pt2 = pt1 + vertPlane.XVec * 5; XYZ pt3 = pt2 + vertPlane.YVec * 2 + vertPlane.XVec * 2; XYZ pt4 = pt3 - vertPlane.XVec * 12; XYZ pt5 = pt4 - vertPlane.YVec * 2 + vertPlane.XVec * 2; Line l1 = Line.CreateBound(pt1, pt2); Line l2 = Line.CreateBound(pt2, pt3); Line l3 = Line.CreateBound(pt3, pt4); Line l4 = Line.CreateBound(pt4, pt5); Line l5 = Line.CreateBound(pt5, pt1); // // var profileLoop = CurveLoop.Create(new List<Curve>{l1, l2, l3, l4, l5}); var profileLoop = LoopPoints(pts); //double rotAngle = -2.543 * Math.PI / 180; double rotAngle = -15 * Math.PI / 180; var transform = Transform.CreateRotationAtPoint(nurbsTr.BasisX, rotAngle, nurbsTr.Origin); profileLoop.Transform(transform); var loops = new List <CurveLoop> { profileLoop }; var path = CurveLoop.Create(new List <Curve> { nurbSpline }); WireframeBuilder builder = new WireframeBuilder(); builder.AddCurve(nurbSpline); //Solid solid = GeometryCreationUtilities.CreateSweptGeometry(path,0,nurbSpline.GetEndParameter(0),loops); Solid solid = GeometryCreationUtilities.CreateFixedReferenceSweptGeometry(path, 0, nurbSpline.GetEndParameter(0), loops, XYZ.BasisZ); using (Transaction t = new Transaction(doc, "create spline")) { t.Start(); ElementId categoryId = new ElementId(BuiltInCategory.OST_Floors); DirectShape ds = DirectShape.CreateElement(doc, categoryId); ds.SetShape(builder); ds.Name = "RhinoSpline"; SketchPlane sp = SketchPlane.Create(doc, vertPlane); uidoc.ActiveView.SketchPlane = sp; //uidoc.ActiveView.ShowActiveWorkPlane(); ModelLine line1 = doc.Create.NewModelCurve(l1, sp) as ModelLine; ModelLine line2 = doc.Create.NewModelCurve(l2, sp) as ModelLine; ModelLine line3 = doc.Create.NewModelCurve(l3, sp) as ModelLine; ModelLine line4 = doc.Create.NewModelCurve(l4, sp) as ModelLine; ModelLine line5 = doc.Create.NewModelCurve(l5, sp) as ModelLine; List <GeometryObject> gs = new List <GeometryObject>(); gs.Add(solid); //DirectShape directShape = DirectShape.CreateElement(doc, categoryId); ds.AppendShape(gs); t.Commit(); } return(Result.Succeeded); }
/// <summary> /// Create geometry for an IfcHalfSpaceSolid. /// </summary> /// <param name="shapeEditScope">The shape edit 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>A list containing one geometry for the IfcHalfSpaceSolid.</returns> protected virtual IList <GeometryObject> CreateGeometryInternal( IFCImportShapeEditScope shapeEditScope, Transform lcs, Transform scaledLcs, string guid) { IFCPlane ifcPlane = BaseSurface as IFCPlane; Plane plane = ifcPlane.Plane; XYZ origin = plane.Origin; XYZ xVec = plane.XVec; XYZ yVec = plane.YVec; // Set some huge boundaries for now. const double largeCoordinateValue = 100000; XYZ[] corners = new XYZ[4] { lcs.OfPoint((xVec * -largeCoordinateValue) + (yVec * -largeCoordinateValue) + origin), lcs.OfPoint((xVec * largeCoordinateValue) + (yVec * -largeCoordinateValue) + origin), lcs.OfPoint((xVec * largeCoordinateValue) + (yVec * largeCoordinateValue) + origin), lcs.OfPoint((xVec * -largeCoordinateValue) + (yVec * largeCoordinateValue) + origin) }; IList <CurveLoop> loops = new List <CurveLoop>(); CurveLoop loop = new CurveLoop(); for (int ii = 0; ii < 4; ii++) { if (AgreementFlag) { loop.Append(Line.CreateBound(corners[(5 - ii) % 4], corners[(4 - ii) % 4])); } else { loop.Append(Line.CreateBound(corners[ii], corners[(ii + 1) % 4])); } } loops.Add(loop); XYZ normal = lcs.OfVector(AgreementFlag ? -plane.Normal : plane.Normal); SolidOptions solidOptions = new SolidOptions(GetMaterialElementId(shapeEditScope), shapeEditScope.GraphicsStyleId); Solid baseSolid = GeometryCreationUtilities.CreateExtrusionGeometry(loops, normal, largeCoordinateValue, solidOptions); if (BaseBoundingCurve != null) { CurveLoop polygonalBoundary = BaseBoundingCurve.CurveLoop; Transform totalTransform = lcs.Multiply(BaseBoundingCurveTransform); // Make sure this bounding polygon extends below base of half-space soild. Transform moveBaseTransform = Transform.Identity; moveBaseTransform.Origin = new XYZ(0, 0, -largeCoordinateValue); totalTransform = totalTransform.Multiply(moveBaseTransform); CurveLoop transformedPolygonalBoundary = IFCGeometryUtil.CreateTransformed(polygonalBoundary, totalTransform); IList <CurveLoop> boundingLoops = new List <CurveLoop>(); boundingLoops.Add(transformedPolygonalBoundary); Solid boundingSolid = GeometryCreationUtilities.CreateExtrusionGeometry(boundingLoops, totalTransform.BasisZ, 2.0 * largeCoordinateValue, solidOptions); baseSolid = IFCGeometryUtil.ExecuteSafeBooleanOperation(Id, BaseBoundingCurve.Id, baseSolid, boundingSolid, BooleanOperationsType.Intersect); } IList <GeometryObject> returnList = new List <GeometryObject>(); returnList.Add(baseSolid); return(returnList); }
/// <summary> /// Trims the CurveLoop contained in an IFCCurve by the start and optional end parameter values. /// </summary> /// <param name="id">The id of the IFC entity containing the directrix, for messaging purposes.</param> /// <param name="ifcCurve">The IFCCurve entity containing the CurveLoop to be trimmed.</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(int id, IFCCurve ifcCurve, double startVal, double?origEndVal) { CurveLoop origCurveLoop = ifcCurve.GetCurveLoop(); if (origCurveLoop == null) { return(null); } // 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; bool allLines = true; foreach (Curve curve in origCurveLoop) { if (!(curve is Line)) { allLines = false; } double curveLength = curve.GetEndParameter(1) - curve.GetEndParameter(0); double currLength = ScaleCurveLengthForSweptSolid(curve, curveLength); 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. double curveParamLength = endVal - startVal; if (MathUtil.IsAlmostEqual(curveParamLength, totalParamLength)) { return(origCurveLoop); } // Error in some Tekla files - lines are parameterized by length, instead of 1.0 (as is correct). // Warn and ignore the parameter length. This must come after the MathUtil.IsAlmostEqual(curveParamLength, totalParamLength) // check above, since we don't want to warn if curveParamLength == totalParamLength. if (!CheckIfTrimParametersAreValidForSomeInvalidities(id, ifcCurve, curveParamLength)) { return(origCurveLoop); } // Special cases: // if startval = 0 and endval = 1 and we have a polyline, then this likely means that the importing application // incorrectly set the extents to be the "whole" curve, when really this is just a portion of the curves // (the parametrization is described above). // As such, if the totalParamLength is not 1 but startVal = 0 and endVal = 1, we will warn but not trim. // This is not a hypothetical case: it occurs in several AllPlan 2017 files at least. if (allLines) { if ((!MathUtil.IsAlmostEqual(totalParamLength, 1.0)) && (MathUtil.IsAlmostZero(startVal) && MathUtil.IsAlmostEqual(endVal, 1.0))) { Importer.TheLog.LogWarning(id, "The Start Parameter for the trimming of this curve was set to 0, and the End Parameter was set to 1. " + "Most likely, this is an error in the sending application, and the trim extents are being ignored. " + "If this trim was intended, please contact Autodesk.", true); 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 newLoopCurves) { trimmedCurveLoop.Append(curve); } return(trimmedCurveLoop); }
private static bool GetCalloutCornerPoints(Document doc, ElementId calloutId, out XYZ firstPoint, out XYZ secondPoint) { bool result = false; firstPoint = new XYZ(0, 0, 0); secondPoint = new XYZ(0, 0, 0); try { double minX = double.MaxValue; double minY = double.MaxValue; double minZ = double.MaxValue; double maxX = double.MinValue; double maxY = double.MinValue; double maxZ = double.MinValue; ViewCropRegionShapeManager cropRegion = View.GetCropRegionShapeManagerForReferenceCallout(doc, calloutId); #if RELEASE2016 || RELEASE2017 IList <CurveLoop> curveLoops = cropRegion.GetCropShape(); foreach (CurveLoop cLoop in curveLoops) { foreach (Curve curve in cLoop) { XYZ point = curve.GetEndPoint(0); if (point.X < minX) { minX = point.X; } if (point.Y < minY) { minY = point.Y; } if (point.Z < minZ) { minZ = point.Z; } if (point.X > maxX) { maxX = point.X; } if (point.Y > maxY) { maxY = point.Y; } if (point.Z > maxZ) { maxZ = point.Z; } } } if (curveLoops.Count() > 0) { firstPoint = new XYZ(minX, minY, minZ); secondPoint = new XYZ(maxX, maxY, maxZ); result = true; } #else CurveLoop curveLoop = cropRegion.GetCropRegionShape(); foreach (Curve curve in curveLoop) { XYZ point = curve.GetEndPoint(0); if (point.X < minX) { minX = point.X; } if (point.Y < minY) { minY = point.Y; } if (point.Z < minZ) { minZ = point.Z; } if (point.X > maxX) { maxX = point.X; } if (point.Y > maxY) { maxY = point.Y; } if (point.Z > maxZ) { maxZ = point.Z; } } if (curveLoop.Count() > 0) { firstPoint = new XYZ(minX, minY, minZ); secondPoint = new XYZ(maxX, maxY, maxZ); result = true; } #endif } catch (Exception ex) { errorMessage.AppendLine("Failed to get corner points of callout.\n" + ex.Message); //MessageBox.Show("Failed to get corner points of callout\n" + ex.Message, "Get Corner Points of Callout", MessageBoxButton.OK, MessageBoxImage.Warning); } return(result); }
/// <summary> /// Create a copy of a curve loop with a given non-transformal transformation applied. /// </summary> /// <param name="origLoop">The original curve loop.</param> /// <param name="id">The id of the originating entity, for error reporting.</param> /// <param name="unscaledTrf">The unscaled (conformal) transform, used if we don't know how to process the curve loop.</param> /// <param name="scaledTrf">The scaled transform.</param> /// <returns>The transformed loop.</returns> /// <remarks>Revit API only allows for conformal transformations. Here, we support /// enough data types for non-conformal cases. In cases where we can't process /// a curve in the loop, we will use the conformal parameter and log an error.</remarks> public static CurveLoop CreateTransformed(CurveLoop origLoop, int id, Transform unscaledTrf, Transform scaledTrf) { if (origLoop == null) { return(null); } if (scaledTrf.IsConformal) { return(CreateTransformedFromConformalTransform(origLoop, scaledTrf)); } CurveLoop newLoop = new CurveLoop(); foreach (Curve curve in origLoop) { Curve newCurve = null; try { // Cover only Line, Arc, and Ellipse for now. These are the most common cases. Warn if it isn't one of these, or if the if (curve is Line) { Line line = curve as Line; XYZ newEndPoint0 = scaledTrf.OfPoint(line.GetEndPoint(0)); XYZ newEndPoint1 = scaledTrf.OfPoint(line.GetEndPoint(1)); newCurve = Line.CreateBound(newEndPoint0, newEndPoint1); } else if (curve is Arc || curve is Ellipse) { double startParam = curve.GetEndParameter(0); double endParam = curve.GetEndParameter(1); XYZ center = null; XYZ xAxis = null; XYZ yAxis = null; double radiusX = 0.0; double radiusY = 0.0; if (curve is Arc) { Arc arc = curve as Arc; center = arc.Center; xAxis = arc.XDirection; yAxis = arc.YDirection; radiusX = radiusY = arc.Radius; } else if (curve is Ellipse) { Ellipse ellipse = curve as Ellipse; center = ellipse.Center; xAxis = ellipse.XDirection; yAxis = ellipse.YDirection; radiusX = ellipse.RadiusX; radiusY = ellipse.RadiusY; } XYZ radiusXDir = new XYZ(radiusX, 0, 0); XYZ radiusYDir = new XYZ(0, radiusY, 0); XYZ scaledRadiusXDir = scaledTrf.OfVector(radiusXDir); XYZ scaledRadiusYDir = scaledTrf.OfVector(radiusYDir); double scaledRadiusX = scaledRadiusXDir.GetLength(); double scaledRadiusY = scaledRadiusYDir.GetLength(); XYZ scaledCenter = scaledTrf.OfPoint(center); XYZ scaledXAxis = scaledTrf.OfVector(xAxis).Normalize(); XYZ scaledYAxis = scaledTrf.OfVector(yAxis).Normalize(); newCurve = CreateArcOrEllipse(scaledCenter, scaledRadiusX, scaledRadiusY, scaledXAxis, scaledYAxis, startParam, endParam); } } catch (Exception) { newCurve = null; } if (newCurve == null) { Importer.TheLog.LogError(id, "Couldn't apply a non-uniform transform to this curve loop. The resulting geometry may be the wrong size.", false); return(CreateTransformedFromConformalTransform(origLoop, unscaledTrf)); } else { newLoop.Append(newCurve); } } return(newLoop); }
private static Polygon ToPolygon(this CurveLoop curveLoop, bool scaleToMeters = false) { return(new Polygon(curveLoop.Select(l => l.GetEndPoint(0).ToVector3(scaleToMeters)).ToList())); }
protected override void Process(IFCAnyHandle ifcCurve) { base.Process(ifcCurve); // We are going to attempt minor repairs for small but reasonable gaps between Line/Line and Line/Arc pairs. As such, we want to collect the // curves before we create the curve loop. IList <IFCAnyHandle> segments = IFCAnyHandleUtil.GetAggregateInstanceAttribute <List <IFCAnyHandle> >(ifcCurve, "Segments"); if (segments == null) { Importer.TheLog.LogError(Id, "Invalid IfcCompositeCurve with no segments.", true); } // need List<> so that we can AddRange later. List <Curve> curveSegments = new List <Curve>(); foreach (IFCAnyHandle segment in segments) { IList <Curve> currCurve = ProcessIFCCompositeCurveSegment(segment); if (currCurve != null && currCurve.Count != 0) { curveSegments.AddRange(currCurve); } } int numSegments = curveSegments.Count; if (numSegments == 0) { Importer.TheLog.LogError(Id, "Invalid IfcCompositeCurve with no segments.", true); } try { // We are going to try to reverse or tweak segments as necessary to make the CurveLoop. // For each curve, it is acceptable if it can be appended to the end of the existing loop, or prepended to its start, // possibly after reversing the curve, and possibly with some tweaking. // NOTE: we do not do any checks yet to repair the endpoints of the curveloop to make them closed. // NOTE: this is not expected to be perfect with dirty data, but is expected to not change already valid data. // curveLoopStartPoint and curveLoopEndPoint will change over time as we add new curves to the start or end of the CurveLoop. XYZ curveLoopStartPoint = curveSegments[0].GetEndPoint(0); XYZ curveLoopEndPoint = curveSegments[0].GetEndPoint(1); double vertexEps = IFCImportFile.TheFile.Document.Application.VertexTolerance; // This is intended to be "relatively large". The idea here is that the user would rather have the information presented // than thrown away because of a gap that is architecturally insignificant. double gapVertexEps = Math.Max(vertexEps, 0.01); // 1/100th of a foot, or 3.048 mm. double shortCurveTol = IFCImportFile.TheFile.Document.Application.ShortCurveTolerance; // canRepairFirst may change over time, as we may potentially add curves to the start of the CurveLoop. bool canRepairFirst = (curveSegments[0] is Line); for (int ii = 1; ii < numSegments; ii++) { XYZ nextStartPoint = curveSegments[ii].GetEndPoint(0); XYZ nextEndPoint = curveSegments[ii].GetEndPoint(1); // These will be set below. bool attachNextSegmentToEnd = false; bool reverseNextSegment = false; double minGap = 0.0; // Scoped to prevent distLoopEndPtToNextStartPt and others from being used later on. { // Find the minimum gap between the current curve segment and the existing curve loop. If it is too large, we will give up. double distLoopEndPtToNextStartPt = curveLoopEndPoint.DistanceTo(nextStartPoint); double distLoopEndPtToNextEndPt = curveLoopEndPoint.DistanceTo(nextEndPoint); double distLoopStartPtToNextEndPt = curveLoopStartPoint.DistanceTo(nextEndPoint); double distLoopStartPtToNextStartPt = curveLoopStartPoint.DistanceTo(nextStartPoint); // Determine the minimum gap between the two curves. If it is too large, we'll give up before trying anything. double minStartGap = Math.Min(distLoopStartPtToNextEndPt, distLoopStartPtToNextStartPt); double minEndGap = Math.Min(distLoopEndPtToNextStartPt, distLoopEndPtToNextEndPt); minGap = Math.Min(minStartGap, minEndGap); // If the minimum distance between the two curves is greater than gapVertexEps (which is the larger of our two tolerances), // we can't fix the issue. if (minGap > gapVertexEps) { string lengthAsString = UnitFormatUtils.Format(IFCImportFile.TheFile.Document.GetUnits(), UnitType.UT_Length, minGap, true, false); string maxGapAsString = UnitFormatUtils.Format(IFCImportFile.TheFile.Document.GetUnits(), UnitType.UT_Length, gapVertexEps, true, false); throw new InvalidOperationException("IfcCompositeCurve contains a gap of " + lengthAsString + " that is greater than the maximum gap size of " + maxGapAsString + " and cannot be repaired."); } // We have a possibility to add the segment. What we do depends on the gap distance. // If the current curve loop's closest end to the next segment is its end (vs. start) point, set attachNextSegmentToEnd to true. attachNextSegmentToEnd = (MathUtil.IsAlmostEqual(distLoopEndPtToNextStartPt, minGap)) || (MathUtil.IsAlmostEqual(distLoopEndPtToNextEndPt, minGap)); // We need to reverse the next segment if: // 1. We are attaching the next segment to the end of the curve loop, and the next segment's closest end to the current curve loop is its end (vs. start) point. // 2. We are attaching the next segment to the start of the curve loop, and the next segment's closest end to the current curve loop is its start (vs. end) point. reverseNextSegment = (MathUtil.IsAlmostEqual(distLoopEndPtToNextEndPt, minGap)) || (MathUtil.IsAlmostEqual(distLoopStartPtToNextStartPt, minGap)); } if (reverseNextSegment) { curveSegments[ii] = curveSegments[ii].CreateReversed(); MathUtil.Swap <XYZ>(ref nextStartPoint, ref nextEndPoint); } // If minGap is less than vertexEps, we won't need to do any repairing - just fix the orientation if necessary. if (minGap < vertexEps) { if (attachNextSegmentToEnd) { // Update the curve loop end point to be the end point of the next segment after potentially being reversed. curveLoopEndPoint = nextEndPoint; } else { canRepairFirst = curveSegments[ii] is Line; curveLoopStartPoint = nextStartPoint; // Update the curve loop start point to be the start point of the next segment, now at the beginning of the loop, // after potentially being reversed. Curve tmpCurve = curveSegments[ii]; curveSegments.RemoveAt(ii); curveSegments.Insert(0, tmpCurve); } continue; } // The gap is too big for CurveLoop, but smaller than our maximum tolerance - we will try to fix the gap by extending // one of the line segments around the gap. If the gap is between two Arcs, we will try to introduce a short // segment between them, as long as the gap is larger than the short curve tolerance. bool canRepairNext = curveSegments[ii] is Line; bool createdRepairLine = false; if (attachNextSegmentToEnd) { // Update the curve loop end point to be the end point of the next segment after potentially being reversed. XYZ originalCurveLoopEndPoint = curveLoopEndPoint; curveLoopEndPoint = nextEndPoint; if (canRepairNext) { curveSegments[ii] = RepairLineAndReport(Id, originalCurveLoopEndPoint, curveLoopEndPoint, minGap); } else if (curveSegments[ii - 1] is Line) // = canRepairCurrent, only used here. { curveSegments[ii - 1] = RepairLineAndReport(Id, curveSegments[ii - 1].GetEndPoint(0), curveSegments[ii].GetEndPoint(0), minGap); } else { // Can't add a line to fix a gap that is smaller than the short curve tolerance. // In the future, we may fix this gap by intersecting the two curves and extending one of them. if (minGap < shortCurveTol + MathUtil.Eps()) { Importer.TheLog.LogError(Id, "IfcCompositeCurve contains a gap between two non-linear segments that is too short to be repaired by a connecting segment.", true); } try { Line repairLine = Line.CreateBound(originalCurveLoopEndPoint, curveSegments[ii].GetEndPoint(0)); curveSegments.Insert(ii, repairLine); ii++; // Skip the repair line as we've already "added" it and the non-linear segment to our growing loop. numSegments++; createdRepairLine = true; } catch { Importer.TheLog.LogError(Id, "IfcCompositeCurve contains a gap between two non-linear segments that can't be fixed.", true); } } } else { XYZ originalCurveLoopStartPoint = curveLoopStartPoint; curveLoopStartPoint = nextStartPoint; if (canRepairNext) { curveSegments[ii] = RepairLineAndReport(Id, curveLoopStartPoint, originalCurveLoopStartPoint, minGap); } else if (canRepairFirst) { curveSegments[0] = RepairLineAndReport(Id, curveSegments[ii].GetEndPoint(1), curveSegments[0].GetEndPoint(1), minGap); } else { // Can't add a line to fix a gap that is smaller than the short curve tolerance. // In the future, we may fix this gap by intersecting the two curves and extending one of them. if (minGap < shortCurveTol + MathUtil.Eps()) { Importer.TheLog.LogError(Id, "IfcCompositeCurve contains a gap between two non-linear segments that is too short to be repaired by a connecting segment.", true); } Line repairLine = Line.CreateBound(curveSegments[ii].GetEndPoint(1), originalCurveLoopStartPoint); curveSegments.Insert(0, repairLine); ii++; // Skip the repair line as we've already "added" it and the non-linear curve to our growing loop. numSegments++; } // Either canRepairFirst was already true, or canRepairNext was true and we added it to the front of the loop, // or we added a short repair line to the front of the loop. In any of these cases, the front curve segement of the // loop is now a line segment. if (!canRepairFirst && !canRepairNext && !createdRepairLine) { Importer.TheLog.LogError(Id, "IfcCompositeCurve contains a gap between two non-linear segments that can't be fixed.", true); } canRepairFirst = true; // Move the curve to the front of the loop. Curve tmpCurve = curveSegments[ii]; curveSegments.RemoveAt(ii); curveSegments.Insert(0, tmpCurve); } } if (CurveLoop == null) { CurveLoop = new CurveLoop(); } foreach (Curve curveSegment in curveSegments) { CurveLoop.Append(curveSegment); } } catch (Exception ex) { Importer.TheLog.LogError(Id, ex.Message, true); } // Try to create the curve representation of this IfcCompositeCurve Curve = ConvertCurveLoopIntoSingleCurve(CurveLoop); }
/// <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); }
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> /// Finds parent handle from opening CurveLoop and parent CurveLoops. /// </summary> /// <param name="elementHandles">The parent handles.</param> /// <param name="curveLoops">The parent CurveLoops.</param> /// <param name="openingLoop">The opening CurveLoop.</param> /// <returns>The parent handle.</returns> private static IFCAnyHandle FindParentHandle(IList<IFCAnyHandle> elementHandles, IList<CurveLoop> curveLoops, CurveLoop openingLoop) { // first one is roof handle, others are slabs if (elementHandles.Count != curveLoops.Count + 1) return null; for (int ii = 0; ii < curveLoops.Count; ii++) { if (GeometryUtil.CurveLoopsInside(openingLoop, curveLoops[ii]) || GeometryUtil.CurveLoopsIntersect(openingLoop, curveLoops[ii])) { return elementHandles[ii + 1]; } } return elementHandles[0]; }
/// <summary> /// Exports a roof or floor as a container of multiple roof slabs. Returns the handle, if successful. /// </summary> /// <param name="exporterIFC">The exporter.</param> /// <param name="element">The roof or floor element.</param> /// <param name="geometry">The geometry of the element.</param> /// <param name="productWrapper">The product wrapper.</param> /// <returns>The roof handle.</returns> /// <remarks>For floors, if there is only one component, return null, as we do not want to create a container.</remarks> public static IFCAnyHandle ExportRoofOrFloorAsContainer(ExporterIFC exporterIFC, Element element, GeometryElement geometry, ProductWrapper productWrapper) { IFCFile file = exporterIFC.GetFile(); // We support ExtrusionRoofs, FootPrintRoofs, and Floors only. bool elementIsRoof = (element is ExtrusionRoof) || (element is FootPrintRoof); bool elementIsFloor = (element is Floor); if (!elementIsRoof && !elementIsFloor) { return(null); } string subSlabType = null; IFCExportInfoPair roofExportType = ExporterUtil.GetProductExportType(exporterIFC, element, out _); if (roofExportType.IsUnKnown) { IFCEntityType elementClassTypeEnum = elementIsFloor ? IFCEntityType.IfcSlab: IFCEntityType.IfcRoof; roofExportType = new IFCExportInfoPair(elementClassTypeEnum, ""); } else { if (elementIsFloor) { subSlabType = "FLOOR"; } else if (elementIsRoof) { subSlabType = "ROOF"; } } // Check the intended IFC entity or type name is in the exclude list specified in the UI if (ExporterCacheManager.ExportOptionsCache.IsElementInExcludeList(roofExportType.ExportType)) { return(null); } Document doc = element.Document; using (SubTransaction tempPartTransaction = new SubTransaction(doc)) { using (IFCTransaction transaction = new IFCTransaction(file)) { MaterialLayerSetInfo layersetInfo = new MaterialLayerSetInfo(exporterIFC, element, productWrapper); bool hasLayers = false; if (layersetInfo.MaterialIds.Count > 1) { hasLayers = true; } bool exportByComponents = ExporterCacheManager.ExportOptionsCache.ExportAs4ReferenceView && hasLayers; // Check for containment override IFCAnyHandle overrideContainerHnd = null; ElementId overrideContainerId = ParameterUtil.OverrideContainmentParameter(exporterIFC, element, out overrideContainerHnd); // We want to delay creating entity handles until as late as possible, so that if we abort the IFC transaction, // we don't have to delete elements. This is both for performance reasons and to potentially extend the number // of projects that can be exported by reducing (a small amount) of waste. IList <HostObjectSubcomponentInfo> hostObjectSubcomponents = null; try { hostObjectSubcomponents = ExporterIFCUtils.ComputeSubcomponents(element as HostObject); } catch { return(null); } if (hostObjectSubcomponents == null) { return(null); } int numSubcomponents = hostObjectSubcomponents.Count; if (numSubcomponents == 0 || (elementIsFloor && numSubcomponents == 1)) { return(null); } using (PlacementSetter setter = PlacementSetter.Create(exporterIFC, element, null, null, overrideContainerId, overrideContainerHnd)) { IFCAnyHandle localPlacement = setter.LocalPlacement; IFCAnyHandle hostObjectHandle = null; try { using (IFCExtrusionCreationData extrusionCreationData = new IFCExtrusionCreationData()) { IFCAnyHandle ownerHistory = ExporterCacheManager.OwnerHistoryHandle; extrusionCreationData.SetLocalPlacement(localPlacement); extrusionCreationData.ReuseLocalPlacement = true; using (TransformSetter trfSetter = TransformSetter.Create()) { IList <GeometryObject> geometryList = new List <GeometryObject>(); geometryList.Add(geometry); trfSetter.InitializeFromBoundingBox(exporterIFC, geometryList, extrusionCreationData); IFCAnyHandle prodRepHnd = null; string elementGUID = GUIDUtil.CreateGUID(element); hostObjectHandle = IFCInstanceExporter.CreateGenericIFCEntity( roofExportType, exporterIFC, element, elementGUID, ownerHistory, localPlacement, prodRepHnd); if (IFCAnyHandleUtil.IsNullOrHasNoValue(hostObjectHandle)) { return(null); } IList <IFCAnyHandle> elementHandles = new List <IFCAnyHandle>(); elementHandles.Add(hostObjectHandle); // If element is floor, then the profile curve loop of hostObjectSubComponent is computed from the top face of the floor // else if element is roof, then the profile curve loop is taken from the bottom face of the roof instead XYZ extrusionDir = elementIsFloor ? new XYZ(0, 0, -1) : new XYZ(0, 0, 1); ElementId catId = CategoryUtil.GetSafeCategoryId(element); IList <IFCAnyHandle> slabHandles = new List <IFCAnyHandle>(); IList <CurveLoop> hostObjectOpeningLoops = new List <CurveLoop>(); double maximumScaledDepth = 0.0; using (IFCExtrusionCreationData slabExtrusionCreationData = new IFCExtrusionCreationData()) { slabExtrusionCreationData.SetLocalPlacement(extrusionCreationData.GetLocalPlacement()); slabExtrusionCreationData.ReuseLocalPlacement = false; slabExtrusionCreationData.ForceOffset = true; int loopNum = 0; int subElementStart = elementIsRoof ? (int)IFCRoofSubElements.RoofSlabStart : (int)IFCSlabSubElements.SubSlabStart; foreach (HostObjectSubcomponentInfo hostObjectSubcomponent in hostObjectSubcomponents) { trfSetter.InitializeFromBoundingBox(exporterIFC, geometryList, slabExtrusionCreationData); Plane plane = hostObjectSubcomponent.GetPlane(); Transform lcs = GeometryUtil.CreateTransformFromPlane(plane); IList <CurveLoop> curveLoops = new List <CurveLoop>(); CurveLoop slabCurveLoop = hostObjectSubcomponent.GetCurveLoop(); curveLoops.Add(slabCurveLoop); double slope = Math.Abs(plane.Normal.Z); double scaledDepth = UnitUtil.ScaleLength(hostObjectSubcomponent.Depth); double scaledExtrusionDepth = scaledDepth * slope; IList <IFCAnyHandle> shapeReps = new List <IFCAnyHandle>(); IFCAnyHandle prodDefShape = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, shapeReps); IFCAnyHandle contextOfItems = exporterIFC.Get3DContextHandle("Body"); string representationType = ShapeRepresentationType.SweptSolid.ToString(); // Create representation items based on the layers // Because in this case, the Roof components are not derived from Parts, but by "splitting" geometry part that can be extruded, // the creation of the Items for IFC4RV will be different by using "manual" split based on the layer thickness HashSet <IFCAnyHandle> bodyItems = new HashSet <IFCAnyHandle>(); if (!exportByComponents) { IFCAnyHandle itemShapeRep = ExtrusionExporter.CreateExtrudedSolidFromCurveLoop(exporterIFC, null, curveLoops, lcs, extrusionDir, scaledExtrusionDepth, false); if (IFCAnyHandleUtil.IsNullOrHasNoValue(itemShapeRep)) { productWrapper.ClearInternalHandleWrapperData(element); return(null); } ElementId matId = HostObjectExporter.GetFirstLayerMaterialId(element as HostObject); BodyExporter.CreateSurfaceStyleForRepItem(exporterIFC, element.Document, false, itemShapeRep, matId); bodyItems.Add(itemShapeRep); } else { List <MaterialLayerSetInfo.MaterialInfo> MaterialIds = layersetInfo.MaterialIds; ElementId typeElemId = element.GetTypeId(); // From CollectMaterialLayerSet() Roofs with no components are only allowed one material. It arbitrarily chooses the thickest material. // To be consistant with Roof(as Slab), we will reverse the order. IFCAnyHandle materialLayerSet = ExporterCacheManager.MaterialSetCache.FindLayerSet(typeElemId); bool materialHandleIsNotValid = IFCAnyHandleUtil.IsNullOrHasNoValue(materialLayerSet); if (IFCAnyHandleUtil.IsNullOrHasNoValue(materialLayerSet) || materialHandleIsNotValid) { MaterialIds.Reverse(); } double scaleProj = extrusionDir.DotProduct(plane.Normal); foreach (MaterialLayerSetInfo.MaterialInfo matLayerInfo in MaterialIds) { double itemExtrDepth = matLayerInfo.m_matWidth; double scaledItemExtrDepth = UnitUtil.ScaleLength(itemExtrDepth) * slope; IFCAnyHandle itemShapeRep = ExtrusionExporter.CreateExtrudedSolidFromCurveLoop(exporterIFC, null, curveLoops, lcs, extrusionDir, scaledItemExtrDepth, false); if (IFCAnyHandleUtil.IsNullOrHasNoValue(itemShapeRep)) { productWrapper.ClearInternalHandleWrapperData(element); return(null); } BodyExporter.CreateSurfaceStyleForRepItem(exporterIFC, element.Document, false, itemShapeRep, matLayerInfo.m_baseMatId); bodyItems.Add(itemShapeRep); RepresentationUtil.CreateRepForShapeAspect(exporterIFC, element, prodDefShape, representationType, matLayerInfo.m_layerName, itemShapeRep); XYZ offset = new XYZ(0, 0, itemExtrDepth / scaleProj); // offset is calculated as extent in the direction of extrusion lcs.Origin += offset; } } IFCAnyHandle shapeRep = RepresentationUtil.CreateSweptSolidRep(exporterIFC, element, catId, contextOfItems, bodyItems, null); shapeReps.Add(shapeRep); IFCAnyHandleUtil.SetAttribute(prodDefShape, "Representations", shapeReps); // We could replace the code below to just use the newer, and better, // GenerateIFCGuidFrom. The code below maintains compatibility with older // versions while generating a stable GUID for all slabs (in the unlikely // case that we have more than 255 of them). string slabGUID = (loopNum < 256) ? GUIDUtil.CreateSubElementGUID(element, subElementStart + loopNum) : GUIDUtil.GenerateIFCGuidFrom(element, "Slab: " + loopNum.ToString()); IFCAnyHandle slabPlacement = ExporterUtil.CreateLocalPlacement(file, slabExtrusionCreationData.GetLocalPlacement(), null); IFCAnyHandle slabHnd = IFCInstanceExporter.CreateSlab(exporterIFC, element, slabGUID, ownerHistory, slabPlacement, prodDefShape, subSlabType); IFCExportInfoPair exportType = new IFCExportInfoPair(IFCEntityType.IfcSlab, subSlabType); //slab quantities slabExtrusionCreationData.ScaledLength = scaledExtrusionDepth; slabExtrusionCreationData.ScaledArea = UnitUtil.ScaleArea(UnitUtil.ScaleArea(hostObjectSubcomponent.AreaOfCurveLoop)); slabExtrusionCreationData.ScaledOuterPerimeter = UnitUtil.ScaleLength(curveLoops[0].GetExactLength()); slabExtrusionCreationData.Slope = UnitUtil.ScaleAngle(MathUtil.SafeAcos(Math.Abs(slope))); IFCExportInfoPair slabRoofExportType = new IFCExportInfoPair(IFCEntityType.IfcSlab, subSlabType); productWrapper.AddElement(null, slabHnd, setter, slabExtrusionCreationData, false, slabRoofExportType); // Create type IFCAnyHandle slabRoofTypeHnd = ExporterUtil.CreateGenericTypeFromElement(element, slabRoofExportType, exporterIFC.GetFile(), ownerHistory, subSlabType, productWrapper); ExporterCacheManager.TypeRelationsCache.Add(slabRoofTypeHnd, slabHnd); elementHandles.Add(slabHnd); slabHandles.Add(slabHnd); hostObjectOpeningLoops.Add(slabCurveLoop); maximumScaledDepth = Math.Max(maximumScaledDepth, scaledDepth); loopNum++; ExporterUtil.AddIntoComplexPropertyCache(slabHnd, layersetInfo); // Create material association here if (layersetInfo != null && !IFCAnyHandleUtil.IsNullOrHasNoValue(layersetInfo.MaterialLayerSetHandle)) { CategoryUtil.CreateMaterialAssociation(slabHnd, layersetInfo.MaterialLayerSetHandle); } } } productWrapper.AddElement(element, hostObjectHandle, setter, extrusionCreationData, true, roofExportType); ExporterUtil.RelateObjects(exporterIFC, null, hostObjectHandle, slabHandles); OpeningUtil.AddOpeningsToElement(exporterIFC, elementHandles, hostObjectOpeningLoops, element, null, maximumScaledDepth, null, setter, localPlacement, productWrapper); transaction.Commit(); return(hostObjectHandle); } } } catch { // SOmething wrong with the above process, unable to create the extrusion data. Reset any internal handles that may have been partially created since they are not committed productWrapper.ClearInternalHandleWrapperData(element); return(null); } finally { exporterIFC.ClearFaceWithElementHandleMap(); } } } } }
private static IFCRange GetExtrusionRangeOfCurveLoop(CurveLoop loop, XYZ extrusionDirection) { IFCRange range = new IFCRange(); bool init = false; foreach (Curve curve in loop) { if (!init) { if (curve.IsBound) { IList<XYZ> coords = curve.Tessellate(); foreach (XYZ coord in coords) { double val = coord.DotProduct(extrusionDirection); if (!init) { range.Start = val; range.End = val; init = true; } else { range.Start = Math.Min(range.Start, val); range.End = Math.Max(range.End, val); } } } else { double val = curve.get_EndPoint(0).DotProduct(extrusionDirection); range.Start = val; range.End = val; init = true; } } else { double val = curve.get_EndPoint(0).DotProduct(extrusionDirection); range.Start = Math.Min(range.Start, val); range.End = Math.Max(range.End, val); } } return range; }
/// <summary> /// This method takes the solidsList and clips all of its solids between the given range. /// </summary> /// <param name="elem"> /// The Element from which we obtain our BoundingBoxXYZ. /// </param> /// <param name="geomElem"> /// The top-level GeometryElement from which to gather X and Y coordinates for the intersecting solid. /// </param> /// <param name="range"> /// The IFCRange whose Z values we use to create an intersecting solid to clip the solids in this class's internal solidsList. /// If range boundaries are equal, method returns, performing no clippings. /// </param> public void ClipSolidsList(GeometryElement geomElem, IFCRange range) { if (geomElem == null) { throw new ArgumentNullException("geomElemToUse"); } if (MathUtil.IsAlmostEqual(range.Start, range.End) || solidsList.Count == 0) { return; } double bottomZ; double boundDifference; if (range.Start < range.End) { bottomZ = range.Start; boundDifference = range.End - range.Start; } else { bottomZ = range.End; boundDifference = range.Start - range.End; } // create a new solid using the X and Y of the bounding box on the top level GeometryElement and the Z of the IFCRange BoundingBoxXYZ elemBoundingBox = geomElem.GetBoundingBox(); XYZ pointA = new XYZ(elemBoundingBox.Min.X, elemBoundingBox.Min.Y, bottomZ); XYZ pointB = new XYZ(elemBoundingBox.Max.X, elemBoundingBox.Min.Y, bottomZ); XYZ pointC = new XYZ(elemBoundingBox.Max.X, elemBoundingBox.Max.Y, bottomZ); XYZ pointD = new XYZ(elemBoundingBox.Min.X, elemBoundingBox.Max.Y, bottomZ); List <Curve> perimeter = new List <Curve>(); perimeter.Add(Line.CreateBound(pointA, pointB)); perimeter.Add(Line.CreateBound(pointB, pointC)); perimeter.Add(Line.CreateBound(pointC, pointD)); perimeter.Add(Line.CreateBound(pointD, pointA)); List <CurveLoop> boxPerimeterList = new List <CurveLoop>(); boxPerimeterList.Add(CurveLoop.Create(perimeter)); Solid intersectionSolid = GeometryCreationUtilities.CreateExtrusionGeometry(boxPerimeterList, XYZ.BasisZ, boundDifference); // cycle through the elements in solidsList and intersect them against intersectionSolid to create a new list List <Solid> clippedSolidsList = new List <Solid>(); Solid currSolid; foreach (Solid solid in solidsList) { try { // ExecuteBooleanOperation can throw if it fails. In this case, just ignore the clipping. currSolid = BooleanOperationsUtils.ExecuteBooleanOperation(solid, intersectionSolid, BooleanOperationsType.Intersect); if (currSolid != null && currSolid.Volume != 0) { clippedSolidsList.Add(currSolid); } } catch { } } solidsList = clippedSolidsList; }
/// <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; }
private void ProcessIFCPolyline(IFCAnyHandle ifcCurve) { IList<IFCAnyHandle> points = IFCAnyHandleUtil.GetAggregateInstanceAttribute<List<IFCAnyHandle>>(ifcCurve, "Points"); int numPoints = points.Count; if (numPoints < 2) { string msg = "IfcPolyLine had " + numPoints + ", expected at least 2, ignoring"; IFCImportFile.TheLog.LogError(Id, msg, false); return; } IList<XYZ> pointXYZs = new List<XYZ>(); foreach (IFCAnyHandle point in points) { XYZ pointXYZ = IFCPoint.ProcessScaledLengthIFCCartesianPoint(point); pointXYZs.Add(pointXYZ); } CurveLoop = IFCGeometryUtil.CreatePolyCurveLoop(pointXYZs, points, Id, false); }
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> /// Create a curve representation of this IFCCompositeCurve from a curveloop /// </summary> /// <param name="curveLoop">The curveloop</param> /// <returns>A Revit curve that is made by appending every curve in the given curveloop, if possible</returns> private Curve ConvertCurveLoopIntoSingleCurve(CurveLoop curveLoop) { if (curveLoop == null) { return null; } CurveLoopIterator curveIterator = curveLoop.GetCurveLoopIterator(); Curve firstCurve = curveIterator.Current; Curve returnCurve = null; // We only connect the curves if they are Line, Arc or Ellipse if (!((firstCurve is Line) || (firstCurve is Arc) || (firstCurve is Ellipse))) { return null; } XYZ firstStartPoint = firstCurve.GetEndPoint(0); Curve currentCurve = null; if (firstCurve is Line) { Line firstLine = firstCurve as Line; while(curveIterator.MoveNext()) { currentCurve = curveIterator.Current; if (!(currentCurve is Line)) { return null; } Line currentLine = currentCurve as Line; if (!(firstLine.Direction.IsAlmostEqualTo(currentLine.Direction))) { return null; } } returnCurve = Line.CreateBound(firstStartPoint, currentCurve.GetEndPoint(1)); } else if (firstCurve is Arc) { Arc firstArc = firstCurve as Arc; XYZ firstCurveNormal = firstArc.Normal; while(curveIterator.MoveNext()) { currentCurve = curveIterator.Current; if (!(currentCurve is Arc)) { return null; } XYZ currentStartPoint = currentCurve.GetEndPoint(0); XYZ currentEndPoint = currentCurve.GetEndPoint(1); Arc currentArc = currentCurve as Arc; XYZ currentCenter = currentArc.Center; double currentRadius = currentArc.Radius; XYZ currentNormal = currentArc.Normal; // We check if this circle is similar to the first circle by checking that they have the same center, same radius, // and lie on the same plane if (!(currentCenter.IsAlmostEqualTo(firstArc.Center) && MathUtil.IsAlmostEqual(currentRadius, firstArc.Radius))) { return null; } if (!MathUtil.IsAlmostEqual(Math.Abs(currentNormal.DotProduct(firstCurveNormal)), 1)) { return null; } } // If all of the curve segments are part of the same circle, then the returning curve will be a circle bounded // by the start point of the first curve and the end point of the last curve. XYZ lastPoint = currentCurve.GetEndPoint(1); if (lastPoint.IsAlmostEqualTo(firstStartPoint)) { firstCurve.MakeUnbound(); } else { double startParameter = firstArc.GetEndParameter(0); double endParameter = firstArc.Project(lastPoint).Parameter; if (endParameter < startParameter) endParameter += Math.PI * 2; firstCurve.MakeBound(startParameter, endParameter); } returnCurve = firstCurve; } else if (firstCurve is Ellipse) { Ellipse firstEllipse = firstCurve as Ellipse; double radiusX = firstEllipse.RadiusX; double radiusY = firstEllipse.RadiusY; XYZ xDirection = firstEllipse.XDirection; XYZ yDirection = firstEllipse.YDirection; XYZ firstCurveNormal = firstEllipse.Normal; while(curveIterator.MoveNext()) { currentCurve = curveIterator.Current; if (!(currentCurve is Ellipse)) return null; XYZ currentStartPoint = currentCurve.GetEndPoint(0); XYZ currentEndPoint = currentCurve.GetEndPoint(1); Ellipse currentEllipse = currentCurve as Ellipse; XYZ currentCenter = currentEllipse.Center; double currentRadiusX = currentEllipse.RadiusX; double currentRadiusY = currentEllipse.RadiusY; XYZ currentXDirection = currentEllipse.XDirection; XYZ currentYDirection = currentEllipse.YDirection; XYZ currentNormal = currentEllipse.Normal; if (!MathUtil.IsAlmostEqual(Math.Abs(currentNormal.DotProduct(firstCurveNormal)), 1)) { return null; } // We determine whether this ellipse is the same as the initial ellipse by checking if their centers and corresponding // radiuses as well as radius directions are the same or permutations of each other. if (!currentCenter.IsAlmostEqualTo(firstEllipse.Center)) { return null; } // Checks if the corresponding radius and radius direction are the same if (MathUtil.IsAlmostEqual(radiusX, currentRadiusX)) { if (!(MathUtil.IsAlmostEqual(radiusY, currentRadiusY) && currentXDirection.IsAlmostEqualTo(xDirection) && currentYDirection.IsAlmostEqualTo(yDirection))) { return null; } } // Checks if the corresponding radiuses and radius directions are permutations of each other else if (MathUtil.IsAlmostEqual(radiusX, currentRadiusY)) { if (!(MathUtil.IsAlmostEqual(radiusY, currentRadiusX) && currentXDirection.IsAlmostEqualTo(yDirection) && currentYDirection.IsAlmostEqualTo(xDirection))) { return null; } } else { return null; } } // If all of the curve segments are part of the same ellipse then the returning curve will be the ellipse whose start point is the start // point of the first curve and the end point is the end point of the last curve XYZ lastPoint = currentCurve.GetEndPoint(1); if (lastPoint.IsAlmostEqualTo(firstStartPoint)) { firstCurve.MakeUnbound(); } else { double startParameter = firstEllipse.GetEndParameter(0); double endParameter = firstEllipse.Project(lastPoint).Parameter; if (endParameter < startParameter) { endParameter += Math.PI * 2; } firstCurve.MakeBound(startParameter, endParameter); } returnCurve = firstCurve; } return returnCurve; }
private List <List <Floor> > createLiningConcreteAsFloor2(Document doc, ElementId myFoundtionId, string nameFamily, double offsetValue, bool isCutting) { Element myFoundation = doc.GetElement(myFoundtionId) as Element; //Get level from elemet Level myLevel = doc.GetElement(myFoundation.LevelId) as Level; //Get geometry from element GeometryElement geometryElement = myFoundation.get_Geometry(new Options()); //Get list Of face (with normal vector = xyz(0,0,-1); List <Face> myListBottomFace = new List <Face>(); using (Transaction myTrans = new Transaction(doc, "fil face of foundation")) { myTrans.Start(); UV myPoint = new UV(0, 0); foreach (GeometryObject geometryObject in geometryElement) { if (geometryObject is Solid) { Solid solid = geometryObject as Solid; XYZ myNormVec = new XYZ(); foreach (Face myFace in solid.Faces) { myNormVec = myFace.ComputeNormal(myPoint); // If normal vector of face has Z value == -1 add to list if (Math.Round(myNormVec.Z, 1) == -1.0) { myListBottomFace.Add(myFace); } } } } myTrans.Commit(); } // Now We has a list of face (with normal vector = (0,0,-1) //Save floor to a list List <Floor> myListLining = new List <Floor>(); // List Floor cutting List <Floor> myListLiningCutting = new List <Floor>(); using (Transaction trans = new Transaction(doc, "abc")) { trans.Start(); foreach (Face myPickedFace in myListBottomFace) { //Get Nomarl vector XYZ myNorVecFace = myPickedFace.ComputeNormal(new UV(0, 0)); List <CurveLoop> myListCurvefromFace = myPickedFace.GetEdgesAsCurveLoops() as List <CurveLoop>; CurveArray myBoundaFloor = new CurveArray(); foreach (CurveLoop myCurLoop in myListCurvefromFace) { if (myFoundation.Category.Name != "Structural Framing") { // Offset For Slab CurveLoop curOffset = CurveLoop.CreateViaOffset(myCurLoop, offsetValue, myNorVecFace); //TaskDialog.Show("abc", "xyz: " +curOffset.GetPlane().Normal.ToString()); foreach (Curve myCur in curOffset) { myBoundaFloor.Append(myCur); } } else { List <double> myOffsetDist = getOffsetDis(myCurLoop, offsetValue); CurveLoop curOffset = CurveLoop.CreateViaOffset(myCurLoop, myOffsetDist, myNorVecFace); //TaskDialog.Show("abc", "xyz: " +curOffset.GetPlane().Normal.ToString()); foreach (Curve myCur in curOffset) { myBoundaFloor.Append(myCur); } } } FloorType floorType = new FilteredElementCollector(doc) .OfClass(typeof(FloorType)) .OfCategory(BuiltInCategory.OST_Floors) .First <Element>(f => f.Name.Equals(nameFamily)) as FloorType; //Floor myLining = doc.Create.NewFoundationSlab(myBoundaFloor, floorType, myLevel, true, new XYZ(0,0,1)); //Floor myLining = doc.Create.NewFloor(myBoundaFloor, floorType, myLevel, true, new XYZ(0,0,1)); Floor myLining = doc.Create.NewFloor(myBoundaFloor, floorType, myLevel, true, new XYZ(0, 0, 1)); // Cutting if foundation is beam if (isCutting) { myListLiningCutting.Add(myLining); } myListLining.Add(myLining); } trans.Commit(); } // Switch Joint List <List <Floor> > myListListFloor = new List <List <Floor> >() { myListLining, myListLiningCutting }; return(myListListFloor); }
// 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 || !extrusionPosition.IsConformal || !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); }
protected override void Process(IFCAnyHandle ifcCurve) { base.Process(ifcCurve); IFCAnyHandle points = IFCAnyHandleUtil.GetInstanceAttribute(ifcCurve, "Points"); if (IFCAnyHandleUtil.IsNullOrHasNoValue(points)) { Importer.TheLog.LogMissingRequiredAttributeError(ifcCurve, "Points", true); return; } IList <IFCData> segments = null; try { // The Segments attribute is new to IFC4 Add1, and we don't know that we may have a // vanilla IFC4 file. If we can't find the attribute, we will assume the points represent // the vertices of a polyline. segments = IFCAnyHandleUtil.GetAggregateAttribute <List <IFCData> >(ifcCurve, "Segments"); } catch (Exception ex) { if (IFCImportFile.HasUndefinedAttribute(ex)) { IFCImportFile.TheFile.DowngradeIFC4SchemaTo(IFCSchemaVersion.IFC4); } else { throw ex; } } IFCCartesianPointList pointList = IFCCartesianPointList.ProcessIFCCartesianPointList(points); IList <XYZ> pointListXYZs = pointList.CoordList; int numPoints = pointListXYZs.Count; CurveLoop curveLoop = null; IList <XYZ> pointXYZs = null; if (segments == null) { // Simple case: no segment information, just treat the curve as a polyline. pointXYZs = pointListXYZs; curveLoop = IFCGeometryUtil.CreatePolyCurveLoop(pointXYZs, null, Id, false); } else { curveLoop = new CurveLoop(); // Assure that we don't add the same point twice for a polyline segment. This could // happen by error, or, e.g., there are two IfcLineIndex segments in a row (although // this could also be considered an error condition.) int lastIndex = -1; // The list of all of the points, in the order that they are added. This can be // used as a backup representation. pointXYZs = new List <XYZ>(); IList <XYZ> currentLineSegmentPoints = new List <XYZ>(); foreach (IFCData segment in segments) { string indexType = ValidateSegment(segment); if (indexType == null) { Importer.TheLog.LogError(Id, "Unknown segment type in IfcIndexedPolyCurve.", false); continue; } IFCAggregate segmentInfo = segment.AsAggregate(); if (indexType.Equals("IfcLineIndex", StringComparison.OrdinalIgnoreCase)) { foreach (IFCData segmentInfoIndex in segmentInfo) { int?currentIndex = GetValidIndex(segmentInfoIndex, numPoints); if (currentIndex == null) { continue; } // We want to aggregate line segments, but if we have no points // yet, we need to always add the start point. int validCurrentIndex = currentIndex.Value; if (lastIndex != validCurrentIndex || currentLineSegmentPoints.Count == 0) { XYZ currPt = pointListXYZs[validCurrentIndex]; pointXYZs.Add(currPt); currentLineSegmentPoints.Add(currPt); lastIndex = validCurrentIndex; } } } else if (indexType.Equals("IfcArcIndex", StringComparison.OrdinalIgnoreCase)) { // Create any line segments that haven't been already created. CreateLineSegments(curveLoop, currentLineSegmentPoints); if (segmentInfo.Count != 3) { Importer.TheLog.LogError(Id, "Invalid IfcArcIndex in IfcIndexedPolyCurve.", false); continue; } int?startIndex = GetValidIndex(segmentInfo[0], numPoints); int?pointIndex = GetValidIndex(segmentInfo[1], numPoints); int?endIndex = GetValidIndex(segmentInfo[2], numPoints); if (startIndex == null || pointIndex == null || endIndex == null) { continue; } Arc arcSegment = null; XYZ startPoint = pointListXYZs[startIndex.Value]; XYZ pointOnArc = pointListXYZs[pointIndex.Value]; XYZ endPoint = pointListXYZs[endIndex.Value]; try { arcSegment = Arc.Create(startPoint, endPoint, pointOnArc); if (arcSegment != null) { curveLoop.Append(arcSegment); } } catch { // We won't do anything here; it may be that the arc is very small, and can // be repaired as a gap in the curve loop. If it can't, this will fail later. // We will monitor usage to see if anything more needs to be done here. } if (lastIndex != startIndex.Value) { pointXYZs.Add(startPoint); } pointXYZs.Add(pointOnArc); pointXYZs.Add(endPoint); lastIndex = endIndex.Value; } else { Importer.TheLog.LogError(Id, "Unsupported segment type in IfcIndexedPolyCurve.", false); continue; } } // Create any line segments that haven't been already created. CreateLineSegments(curveLoop, currentLineSegmentPoints); } SetCurveLoop(curveLoop, pointXYZs); }
/// <summary> /// Adds a new opening to extrusion creation data from curve loop and extrusion data. /// </summary> /// <param name="creationData">The extrusion creation data.</param> /// <param name="from">The extrusion data.</param> /// <param name="curveLoop">The curve loop.</param> private static void AddOpeningData(IFCExtrusionCreationData creationData, IFCExtrusionData from, CurveLoop curveLoop) { List<CurveLoop> curveLoops = new List<CurveLoop>(); curveLoops.Add(curveLoop); AddOpeningData(creationData, from, curveLoops); }
/// <summary> /// Adds a new retaining pond. /// </summary> /// <param name="uiDoc">The document.</param> /// <param name="pondRadius">The radius of the pond.</param> private void AddNewRetainingPond(UIDocument uiDoc, double pondRadius) { Document doc = uiDoc.Document; // Find toposurfaces FilteredElementCollector tsCollector = new FilteredElementCollector(doc); tsCollector.OfClass(typeof(TopographySurface)); IEnumerable <TopographySurface> tsEnumerable = tsCollector.Cast <TopographySurface>().Where <TopographySurface>(ts => !ts.IsSiteSubRegion); int count = tsEnumerable.Count <TopographySurface>(); // If there is only on surface, use it. If there is more than one, let the user select the target. TopographySurface targetSurface = null; if (count > 1) // tmp { targetSurface = SiteUIUtils.PickTopographySurface(uiDoc); } else { targetSurface = tsEnumerable.First <TopographySurface>(); } // Pick point and project to plane at toposurface average elevation XYZ point = SiteUIUtils.PickPointNearToposurface(uiDoc, targetSurface, "Pick point for center of pond."); double elevation = point.Z; // Add subregion first, so that any previously existing points can be removed to avoid distorting the new region // Find material "Water" FilteredElementCollector collector = new FilteredElementCollector(doc); collector.OfClass(typeof(Material)); Material mat = collector.Cast <Material>().FirstOrDefault <Material>(m => m.Name == "Water"); // Create subregion curves List <Curve> curves = new List <Curve>(); curves.Add(Arc.Create(point, pondRadius, 0, Math.PI, XYZ.BasisX, XYZ.BasisY)); curves.Add(Arc.Create(point, pondRadius, Math.PI, 2 * Math.PI, XYZ.BasisX, XYZ.BasisY)); CurveLoop curveLoop = CurveLoop.Create(curves); List <CurveLoop> curveLoops = new List <CurveLoop>(); curveLoops.Add(curveLoop); // All changes are added to one transaction group - will create one undo item using (TransactionGroup addGroup = new TransactionGroup(doc, "Add pond group")) { addGroup.Start(); IList <XYZ> existingPoints = null; // Transacton for adding subregion. using (Transaction t2 = new Transaction(doc, "Add subregion")) { t2.Start(); SiteSubRegion region = SiteSubRegion.Create(doc, curveLoops, targetSurface.Id); if (mat != null) { region.TopographySurface.MaterialId = mat.Id; } t2.Commit(); // The boundary points for the subregion cannot be deleted, since they are generated // to represent the subregion boundary rather than representing real points in the host. // Get non-boundary points only to be deleted. existingPoints = SiteEditingUtils.GetNonBoundaryPoints(region.TopographySurface); // Average elevation of all points in the subregion to use as base elevation for the pond topography elevation = SiteEditingUtils.GetAverageElevation(region.TopographySurface.GetPoints()); } // Add the topography points to the target surface via edit scope. using (TopographyEditScope editScope = new TopographyEditScope(doc, "Edit TS")) { editScope.Start(targetSurface.Id); // Transaction for points changes using (Transaction t = new Transaction(doc, "Add points")) { t.Start(); // Delete existing points first to avoid conflict if (existingPoints.Count > 0) { targetSurface.DeletePoints(existingPoints); } // Generate list of points to add IList <XYZ> points = SiteEditingUtils.GeneratePondPointsSurrounding(new XYZ(point.X, point.Y, elevation - 3), pondRadius); targetSurface.AddPoints(points); t.Commit(); } editScope.Commit(new TopographyEditFailuresPreprocessor()); } addGroup.Assimilate(); } }
private GeometryObject CreateGeometryFromMaterialProfile(IFCImportShapeEditScope shapeEditScope, IList <CurveLoop> loops, XYZ extrusionDirection, double currDepth, SolidOptions solidOptions, out bool shouldWarn) { GeometryObject extrusionSolid = null; try { shouldWarn = true; // invalid input IIFCMaterialSelect materialSelect = shapeEditScope.Creator.MaterialSelect; if (materialSelect == null) { return(null); } IFCMaterialProfileSetUsage matProfSetUsage = materialSelect as IFCMaterialProfileSetUsage; if (matProfSetUsage == null) { return(null); } IFCMaterialProfileSet matProfSet = matProfSetUsage.ForProfileSet; if (matProfSet == null) { return(null); } IList <IFCMaterialProfile> matProfList = matProfSet.MaterialProfileSet; if (matProfList.Count == 0) { return(null); } Transform transformByOffset = Transform.Identity; IList <CurveLoop> newloops = new List <CurveLoop>(); ElementId materialId = null; foreach (IFCMaterialProfile matProf in matProfList) { if (this.SweptArea.Id == matProf.Profile.Id) { // This is the same id (same profile), use the material name for creation of this geometry IFCMaterial theMaterial = matProf.Material; if (theMaterial != null) { materialId = theMaterial.GetMaterialElementId(); solidOptions.MaterialId = materialId; // Override the original option if the profile has a specific material id } // Here we will handle special case if the Material Profile has Offset if (matProf is IFCMaterialProfileWithOffsets) { IFCMaterialProfileWithOffsets matProfOffset = matProf as IFCMaterialProfileWithOffsets; double startOffset = matProfOffset.OffsetValues[0]; double endOffset = 0; if (matProfOffset.OffsetValues.Count > 1) { endOffset = matProfOffset.OffsetValues[1]; } // To handle offset, we need to move the start point (extrusion position) to the startOffset value along the axis (extrusion direction) // For the end offset, we will have to re-calculate the extrusion currDepth = currDepth - startOffset + endOffset; transformByOffset.Origin += startOffset * extrusionDirection; foreach (CurveLoop loop in loops) { CurveLoop newLoop = CurveLoop.CreateViaTransform(loop, transformByOffset); newloops.Add(newLoop); } } break; } } if (newloops.Count == 0) { extrusionSolid = GeometryCreationUtilities.CreateExtrusionGeometry(loops, extrusionDirection, currDepth, solidOptions); } else { extrusionSolid = GeometryCreationUtilities.CreateExtrusionGeometry(newloops, extrusionDirection, currDepth, solidOptions); } } catch { // Ignore the specific exception, but let the user know there was a problem processing the IfcMaterialLayerSetUsage. shouldWarn = true; return(null); } return(extrusionSolid); }
/// <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; }
void CommitInstance ( Document doc, IGH_DataAccess DA, int Iteration, IEnumerable <Rhino.Geometry.Point3d> points, IEnumerable <Rhino.Geometry.Curve> regions ) { var element = PreviousElement(doc, Iteration); if (!element?.Pinned ?? false) { ReplaceElement(doc, DA, Iteration, element); } else { try { var scaleFactor = 1.0 / Revit.ModelUnits; if (scaleFactor != 1.0) { points = points.Select(p => p * scaleFactor); foreach (var region in regions) { region.Scale(scaleFactor); } } TopographySurface topography = null; //if (element is TopographySurface topography) //{ // using (var editScope = new TopographyEditScope(doc, "TopographyByPoints")) // { // editScope.Start(element.Id); // topography.DeletePoints(topography.GetPoints()); // topography.AddPoints(points.ToHost().ToList()); // foreach (var subRegionId in topography.GetHostedSubRegionIds()) // doc.Delete(subRegionId); // editScope.Commit(new Revit.FailuresPreprocessor()); // } //} //else { topography = CopyParametersFrom(TopographySurface.Create(doc, points.ToHost().ToList()), element); element = topography; } if (topography != null && regions.Any()) { var curveLoops = regions.Select(region => CurveLoop.Create(region.ToHost().ToList())).ToList(); SiteSubRegion.Create(doc, curveLoops, topography.Id); } ReplaceElement(doc, DA, Iteration, element); } catch (Exception e) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, e.Message); ReplaceElement(doc, DA, Iteration, null); } } }
protected override void Process(IFCAnyHandle ifcCurve) { base.Process(ifcCurve); // We are going to attempt minor repairs for small but reasonable gaps between Line/Line and Line/Arc pairs. As such, we want to collect the // curves before we create the curve loop. IList<IFCAnyHandle> segments = IFCAnyHandleUtil.GetAggregateInstanceAttribute<List<IFCAnyHandle>>(ifcCurve, "Segments"); if (segments == null) Importer.TheLog.LogError(Id, "Invalid IfcCompositeCurve with no segments.", true); // need List<> so that we can AddRange later. List<Curve> curveSegments = new List<Curve>(); foreach (IFCAnyHandle segment in segments) { IList<Curve> currCurve = ProcessIFCCompositeCurveSegment(segment); if (currCurve != null && currCurve.Count != 0) curveSegments.AddRange(currCurve); } int numSegments = curveSegments.Count; if (numSegments == 0) Importer.TheLog.LogError(Id, "Invalid IfcCompositeCurve with no segments.", true); try { // We are going to try to reverse or tweak segments as necessary to make the CurveLoop. // For each curve, it is acceptable if it can be appended to the end of the existing loop, or prepended to its start, // possibly after reversing the curve, and possibly with some tweaking. // NOTE: we do not do any checks yet to repair the endpoints of the curveloop to make them closed. // NOTE: this is not expected to be perfect with dirty data, but is expected to not change already valid data. // curveLoopStartPoint and curveLoopEndPoint will change over time as we add new curves to the start or end of the CurveLoop. XYZ curveLoopStartPoint = curveSegments[0].GetEndPoint(0); XYZ curveLoopEndPoint = curveSegments[0].GetEndPoint(1); double vertexEps = IFCImportFile.TheFile.Document.Application.VertexTolerance; // This is intended to be "relatively large". The idea here is that the user would rather have the information presented // than thrown away because of a gap that is architecturally insignificant. double gapVertexEps = Math.Max(vertexEps, 0.01); // 1/100th of a foot, or 3.048 mm. double shortCurveTol = IFCImportFile.TheFile.Document.Application.ShortCurveTolerance; // canRepairFirst may change over time, as we may potentially add curves to the start of the CurveLoop. bool canRepairFirst = (curveSegments[0] is Line); for (int ii = 1; ii < numSegments; ii++) { XYZ nextStartPoint = curveSegments[ii].GetEndPoint(0); XYZ nextEndPoint = curveSegments[ii].GetEndPoint(1); // These will be set below. bool attachNextSegmentToEnd = false; bool reverseNextSegment = false; double minGap = 0.0; // Scoped to prevent distLoopEndPtToNextStartPt and others from being used later on. { // Find the minimum gap between the current curve segment and the existing curve loop. If it is too large, we will give up. double distLoopEndPtToNextStartPt = curveLoopEndPoint.DistanceTo(nextStartPoint); double distLoopEndPtToNextEndPt = curveLoopEndPoint.DistanceTo(nextEndPoint); double distLoopStartPtToNextEndPt = curveLoopStartPoint.DistanceTo(nextEndPoint); double distLoopStartPtToNextStartPt = curveLoopStartPoint.DistanceTo(nextStartPoint); // Determine the minimum gap between the two curves. If it is too large, we'll give up before trying anything. double minStartGap = Math.Min(distLoopStartPtToNextEndPt, distLoopStartPtToNextStartPt); double minEndGap = Math.Min(distLoopEndPtToNextStartPt, distLoopEndPtToNextEndPt); minGap = Math.Min(minStartGap, minEndGap); // If the minimum distance between the two curves is greater than gapVertexEps (which is the larger of our two tolerances), // we can't fix the issue. if (minGap > gapVertexEps) { string lengthAsString = UnitFormatUtils.Format(IFCImportFile.TheFile.Document.GetUnits(), UnitType.UT_Length, minGap, true, false); string maxGapAsString = UnitFormatUtils.Format(IFCImportFile.TheFile.Document.GetUnits(), UnitType.UT_Length, gapVertexEps, true, false); throw new InvalidOperationException("IfcCompositeCurve contains a gap of " + lengthAsString + " that is greater than the maximum gap size of " + maxGapAsString + " and cannot be repaired."); } // We have a possibility to add the segment. What we do depends on the gap distance. // If the current curve loop's closest end to the next segment is its end (vs. start) point, set attachNextSegmentToEnd to true. attachNextSegmentToEnd = (MathUtil.IsAlmostEqual(distLoopEndPtToNextStartPt, minGap)) || (MathUtil.IsAlmostEqual(distLoopEndPtToNextEndPt, minGap)); // We need to reverse the next segment if: // 1. We are attaching the next segment to the end of the curve loop, and the next segment's closest end to the current curve loop is its end (vs. start) point. // 2. We are attaching the next segment to the start of the curve loop, and the next segment's closest end to the current curve loop is its start (vs. end) point. reverseNextSegment = (MathUtil.IsAlmostEqual(distLoopEndPtToNextEndPt, minGap)) || (MathUtil.IsAlmostEqual(distLoopStartPtToNextStartPt, minGap)); } if (reverseNextSegment) { curveSegments[ii] = curveSegments[ii].CreateReversed(); MathUtil.Swap<XYZ>(ref nextStartPoint, ref nextEndPoint); } // If minGap is less than vertexEps, we won't need to do any repairing - just fix the orientation if necessary. if (minGap < vertexEps) { if (attachNextSegmentToEnd) { // Update the curve loop end point to be the end point of the next segment after potentially being reversed. curveLoopEndPoint = nextEndPoint; } else { canRepairFirst = curveSegments[ii] is Line; curveLoopStartPoint = nextStartPoint; // Update the curve loop start point to be the start point of the next segment, now at the beginning of the loop, // after potentially being reversed. Curve tmpCurve = curveSegments[ii]; curveSegments.RemoveAt(ii); curveSegments.Insert(0, tmpCurve); } continue; } // The gap is too big for CurveLoop, but smaller than our maximum tolerance - we will try to fix the gap by extending // one of the line segments around the gap. If the gap is between two Arcs, we will try to introduce a short // segment between them, as long as the gap is larger than the short curve tolerance. bool canRepairNext = curveSegments[ii] is Line; bool createdRepairLine = false; if (attachNextSegmentToEnd) { // Update the curve loop end point to be the end point of the next segment after potentially being reversed. XYZ originalCurveLoopEndPoint = curveLoopEndPoint; curveLoopEndPoint = nextEndPoint; if (canRepairNext) curveSegments[ii] = RepairLineAndReport(Id, originalCurveLoopEndPoint, curveLoopEndPoint, minGap); else if (curveSegments[ii - 1] is Line) // = canRepairCurrent, only used here. curveSegments[ii - 1] = RepairLineAndReport(Id, curveSegments[ii - 1].GetEndPoint(0), curveSegments[ii].GetEndPoint(0), minGap); else { // Can't add a line to fix a gap that is smaller than the short curve tolerance. // In the future, we may fix this gap by intersecting the two curves and extending one of them. if (minGap < shortCurveTol + MathUtil.Eps()) Importer.TheLog.LogError(Id, "IfcCompositeCurve contains a gap between two non-linear segments that is too short to be repaired by a connecting segment.", true); try { Line repairLine = Line.CreateBound(originalCurveLoopEndPoint, curveSegments[ii].GetEndPoint(0)); curveSegments.Insert(ii, repairLine); ii++; // Skip the repair line as we've already "added" it and the non-linear segment to our growing loop. numSegments++; createdRepairLine = true; } catch { Importer.TheLog.LogError(Id, "IfcCompositeCurve contains a gap between two non-linear segments that can't be fixed.", true); } } } else { XYZ originalCurveLoopStartPoint = curveLoopStartPoint; curveLoopStartPoint = nextStartPoint; if (canRepairNext) { curveSegments[ii] = RepairLineAndReport(Id, curveLoopStartPoint, originalCurveLoopStartPoint, minGap); } else if (canRepairFirst) curveSegments[0] = RepairLineAndReport(Id, curveSegments[ii].GetEndPoint(1), curveSegments[0].GetEndPoint(1), minGap); else { // Can't add a line to fix a gap that is smaller than the short curve tolerance. // In the future, we may fix this gap by intersecting the two curves and extending one of them. if (minGap < shortCurveTol + MathUtil.Eps()) Importer.TheLog.LogError(Id, "IfcCompositeCurve contains a gap between two non-linear segments that is too short to be repaired by a connecting segment.", true); Line repairLine = Line.CreateBound(curveSegments[ii].GetEndPoint(1), originalCurveLoopStartPoint); curveSegments.Insert(0, repairLine); ii++; // Skip the repair line as we've already "added" it and the non-linear curve to our growing loop. numSegments++; } // Either canRepairFirst was already true, or canRepairNext was true and we added it to the front of the loop, // or we added a short repair line to the front of the loop. In any of these cases, the front curve segement of the // loop is now a line segment. if (!canRepairFirst && !canRepairNext && !createdRepairLine) Importer.TheLog.LogError(Id, "IfcCompositeCurve contains a gap between two non-linear segments that can't be fixed.", true); canRepairFirst = true; // Move the curve to the front of the loop. Curve tmpCurve = curveSegments[ii]; curveSegments.RemoveAt(ii); curveSegments.Insert(0, tmpCurve); } } if (CurveLoop == null) CurveLoop = new CurveLoop(); foreach (Curve curveSegment in curveSegments) { CurveLoop.Append(curveSegment); } } catch (Exception ex) { Importer.TheLog.LogError(Id, ex.Message, true); } // Try to create the curve representation of this IfcCompositeCurve Curve = ConvertCurveLoopIntoSingleCurve(CurveLoop); }
public static Solid CreateSolidByLoopExtrusion(this Face face, double distance = 0.1) { CurveLoop loop = face.GetEdgesAsCurveLoops().First(); return(CreateSolidByLoopExtrusion(face.ComputeNormal(UV.Zero), loop, distance)); }
/// <summary> /// Computes height and width of a curve loop with respect to the projection plane. /// </summary> /// <param name="curveLoop">The curve loop.</param> /// <param name="plane">The projection plane.</param> /// <param name="height">The height.</param> /// <param name="width">The width.</param> /// <returns>True if success, false if fail.</returns> public static bool ComputeHeightWidthOfCurveLoop(CurveLoop curveLoop, Plane plane, out double height, out double width) { height = 0.0; width = 0.0; Plane localPlane = plane; if (localPlane == null) { try { localPlane = curveLoop.GetPlane(); } catch { return false; } } if (curveLoop.IsRectangular(localPlane)) { height = curveLoop.GetRectangularHeight(localPlane); width = curveLoop.GetRectangularWidth(localPlane); return true; } else return false; }
public static Solid CreateSolidByLoopExtrusion(XYZ normal, CurveLoop loop, double distance = 0.1) { return(GeometryCreationUtilities.CreateExtrusionGeometry(new List <CurveLoop> { loop }, normal, distance)); }
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); }
/// <summary>ElementIntersectsSolidFilter: 找到与某Solid相交的Elements </summary> public void FindIntersectWallsByGeometry() { Transaction trans = new Transaction(Doc, "ExComm"); trans.Start(); // ---------------- 在API内存中创建一个拉伸Solid的定义(但是并不包含在Document中) ---------------- //pick a point to draw solid Selection sel = UIDoc.Selection; XYZ pt = sel.PickPoint("Please pick a point to get the close walls"); XYZ pttemp1 = sel.PickPoint(ObjectSnapTypes.None, "Pick leader end..."); XYZ pttemp2 = sel.PickPoint(ObjectSnapTypes.None, "Pick leader elbow..."); double dBoxLength = 3; // 创建进行拉伸的闭合曲线 XYZ pt1 = new XYZ(pt.X - dBoxLength / 2, pt.Y - dBoxLength / 2, pt.Z); XYZ pt2 = new XYZ(pt.X + dBoxLength / 2, pt.Y - dBoxLength / 2, pt.Z); XYZ pt3 = new XYZ(pt.X + dBoxLength / 2, pt.Y + dBoxLength / 2, pt.Z); XYZ pt4 = new XYZ(pt.X - dBoxLength / 2, pt.Y + dBoxLength / 2, pt.Z); // 闭合曲线的四条边 Line lineBottom = Line.CreateBound(pt1, pt2); Line lineRight = Line.CreateBound(pt2, pt3); Line lineTop = Line.CreateBound(pt3, pt4); Line lineLeft = Line.CreateBound(pt4, pt1); // 将四条边连接起来 CurveLoop profile = new CurveLoop(); profile.Append(lineBottom); profile.Append(lineRight); profile.Append(lineTop); profile.Append(lineLeft); // 创建闭合的连续曲线段 List <CurveLoop> loops = new List <CurveLoop>(); loops.Add(profile); // 创建出一个Solid:此Solid只是为了与其他API交互,并未保存在Document中,所以也不可见。 XYZ vector = new XYZ(0, 0, 1); Solid solid = GeometryCreationUtilities.CreateExtrusionGeometry(loops, vector, 10); // 在整个文档中搜索与此虚拟定义的Solid相交的Element FilteredElementCollector collector = new FilteredElementCollector(Doc); ElementIntersectsSolidFilter solidFilter = new ElementIntersectsSolidFilter(solid); collector.WherePasses(solidFilter); // 将最终的相交结果选中 List <ElementId> selEle = new List <ElementId>(); foreach (Element elem in collector) { selEle.Add(elem.Id); } sel.SetElementIds(selEle); // trans.Commit(); }
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> /// 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> /// 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; }
/// <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); }
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; }
public Result Execute( ExternalCommandData commandData, ref string message, ElementSet elements) { UIApplication app = commandData.Application; UIDocument uidoc = app.ActiveUIDocument; Document doc = uidoc.Document; // Retrieve selected floors, or all floors, if nothing is selected: List <Element> floors = new List <Element>(); if (!Util.GetSelectedElementsOrAll( floors, uidoc, typeof(Floor))) { Selection sel = uidoc.Selection; message = (0 < sel.GetElementIds().Count) ? "Please select some floor elements." : "No floor elements found."; return(Result.Failed); } // Determine top face of each selected floor: int nNullFaces = 0; List <Face> topFaces = new List <Face>(); Options opt = app.Application.Create.NewGeometryOptions(); foreach (Floor floor in floors) { GeometryElement geo = floor.get_Geometry(opt); //GeometryObjectArray objects = geo.Objects; // 2012 foreach (GeometryObject obj in geo) { Solid solid = obj as Solid; if (solid != null) { PlanarFace f = GetTopFace(solid); if (null == f) { Debug.WriteLine( Util.ElementDescription(floor) + " has no top face."); ++nNullFaces; } topFaces.Add(f); } } } using (Transaction t = new Transaction(doc)) { t.Start("Create Model Lines and Floor"); // Create new floors from the top faces found. // Before creating the new floor, we would obviously // apply whatever modifications are required to the // new floor profile: Autodesk.Revit.Creation.Application creApp = app.Application.Create; Autodesk.Revit.Creation.Document creDoc = doc.Create; int i = 0; int n = topFaces.Count - nNullFaces; Debug.Print( "{0} top face{1} found.", n, Util.PluralSuffix(n)); foreach (Face f in topFaces) { Floor floor = floors[i++] as Floor; if (null != f) { EdgeArrayArray eaa = f.EdgeLoops; // Code for Revit 2021 and earlier: //CurveArray profile; // 2021 #region Attempt to include inner loops #if ATTEMPT_TO_INCLUDE_INNER_LOOPS bool use_original_loops = true; if (use_original_loops) { profile = Convert(eaa); } else #endif // ATTEMPT_TO_INCLUDE_INNER_LOOPS #endregion // Attempt to include inner loops //{ // profile = new CurveArray(); // // Only use first edge array, // // the outer boundary loop, // // skip the further items // // representing holes: // EdgeArray ea = eaa.get_Item( 0 ); // foreach ( Edge e in ea ) // { // IList<XYZ> pts = e.Tessellate(); // int m = pts.Count; // XYZ p = pts[0]; // XYZ q = pts[m - 1]; // Line line = Line.CreateBound( p, q ); // profile.Append( line ); // } //} List <CurveLoop> loops = new List <CurveLoop>(); // 2022 { CurveLoop loop = new CurveLoop(); // Only use first edge array, // the outer boundary loop, // skip the further items // representing holes: EdgeArray ea = eaa.get_Item(0); foreach (Edge e in ea) { IList <XYZ> pts = e.Tessellate(); int m = pts.Count; XYZ p = pts[0]; XYZ q = pts[m - 1]; Line line = Line.CreateBound(p, q); loop.Append(line); } loops = new List <CurveLoop>(); loops.Add(loop); } //Level level = floor.Level; // 2013 //Level level = doc.GetElement( floor.LevelId ) // as Level; // 2014 // In this case we have a valid floor type given. // In general, not that NewFloor will only accept // floor types whose IsFoundationSlab predicate // is false. //floor = creDoc.NewFloor( profile, // 2021 // floor.FloorType, level, true ); floor = Floor.Create(doc, loops, floor.FloorType.Id, floor.LevelId); // 2022 XYZ v = new XYZ(5, 5, 0); //doc.Move( floor, v ); // 2011 ElementTransformUtils.MoveElement(doc, floor.Id, v); // 2012 } } t.Commit(); } return(Result.Succeeded); }
private static bool IsInRange(IFCRange range, CurveLoop loop, Plane plane, XYZ extrusionDirection, out bool clipCompletely) { clipCompletely = false; if (range != null) { // This check is only applicable for cuts that are perpendicular to the extrusion direction. // For cuts that aren't, we can't easily tell if this cut is extraneous or not. if (!MathUtil.IsAlmostEqual(Math.Abs(plane.Normal.DotProduct(extrusionDirection)), 1.0)) return true; double eps = MathUtil.Eps(); double parameterValue = plane.Origin.DotProduct(extrusionDirection); if (range.Start > parameterValue - eps) { clipCompletely = true; return false; } if (range.End < parameterValue + eps) return false; } return true; }
public void Execute(UIApplication uiapp) { try { UIDocument uidoc = uiapp.ActiveUIDocument; Document doc = uidoc.Document; // myListView_ALL_Fam_Master.Items.Add(doc.GetElement(uidoc.Selection.GetElementIds().First()).Name); if (uidoc.Selection.GetElementIds().Count != 1) { MessageBox.Show("Please select ONE Wall."); return; } Element myElementWall = doc.GetElement(uidoc.Selection.GetElementIds().First()); if (myElementWall.GetType() == typeof(FamilyInstance)) { FamilyInstance myFamilyInstance = myElementWall as FamilyInstance; myElementWall = myFamilyInstance.Host; if (myElementWall == null) { MessageBox.Show("Family instance must be hosted to a wall."); return; } } /// TECHNIQUE 08 OF 19 (EE08_MoveElementAroundHostingSurface.cs) ///↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ MOVING ELEMENTS AROUND A HOSTING SURFACE ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ /// The people walk around the perimeter of the wall, and it will work on any surface /// /// /// Interfaces and ENUM's: /// /// /// Demonstrates classes: /// Reference /// Face /// Transform /// PlanarFace /// CurveLoop /// /// /// Key methods: /// myElementWall.GetGeometryObjectFromReference(pickedRef) as Face /// pickedRef.ConvertToStableRepresentation(doc).Contains("INSTANCE")) /// (myElementWall as FamilyInstance).GetTotalTransform(); /// myFace.GetBoundingBox().Min /// myFace.Evaluate(myUV_Min) /// /// myXYZ_FamilyTransform.OfPoint(myXYZ_CornerOne) /// myXYZ_FamilyTransform.OfVector(myPlanarFace.XVector); /// myCurveLoop.GetExactLength(); /// /// /// L1.GetEndPoint(0)).Normalize().Multiply(myDouble_ThisFarAlong); /// ElementTransformUtils.MoveElement(doc, myFamilyInstance.Id, myXYZ_MoveThisMuch); /// /// * class is actually part of the .NET framework (not Revit API) /// /// /// /// https://github.com/joshnewzealand/Revit-API-Playpen-CSharp List <Element> myListOfStuffOnWall = new FilteredElementCollector(doc).OfClass(typeof(FamilyInstance)).OfCategory(BuiltInCategory.OST_GenericModel).Where(x => (((FamilyInstance)x).Host != null)).Where(x => ((FamilyInstance)x).Host.Id == myElementWall.Id).ToList(); List <Element> myListOfFurniture = new FilteredElementCollector(doc).OfClass(typeof(FamilyInstance)).OfCategory(BuiltInCategory.OST_Furniture).Where(x => (((FamilyInstance)x).Host != null)).Where(x => ((FamilyInstance)x).Host.Id == myElementWall.Id).ToList(); myListOfStuffOnWall.AddRange(myListOfFurniture); if (myListOfStuffOnWall.Count() > 0) { using (Transaction tx = new Transaction(doc)) { tx.Start("Rotate People"); foreach (FamilyInstance myFI in myListOfStuffOnWall) { FamilyInstance myFamilyInstance = myFI as FamilyInstance; Reference pickedRef = myFI.HostFace; ////doc.Delete(myListElementID); ////myListElementID.Clear(); Face myFace = myElementWall.GetGeometryObjectFromReference(pickedRef) as Face; if (myFace == null) { return; } Transform myXYZ_FamilyTransform = Transform.Identity; if (pickedRef.ConvertToStableRepresentation(doc).Contains("INSTANCE")) { myXYZ_FamilyTransform = (myElementWall as FamilyInstance).GetTotalTransform(); } Transform myTransform = Transform.Identity; if (myFace.GetType() != typeof(PlanarFace)) { return; } PlanarFace myPlanarFace = myFace as PlanarFace; UV myUV_Min = myFace.GetBoundingBox().Min; UV myUV_Max = myFace.GetBoundingBox().Max; XYZ myXYZ_CornerOne = myFace.Evaluate(myUV_Min); myTransform.Origin = myXYZ_FamilyTransform.OfPoint(myXYZ_CornerOne); myTransform.BasisX = myXYZ_FamilyTransform.OfVector(myPlanarFace.XVector); myTransform.BasisY = myXYZ_FamilyTransform.OfVector(myPlanarFace.YVector); myTransform.BasisZ = myXYZ_FamilyTransform.OfVector(myPlanarFace.FaceNormal); XYZ myXYZ_Centre = XYZ.Zero; XYZ myXYZ_Min = new XYZ(myUV_Min.U, myUV_Min.V, 0); XYZ myXYZ_Max = new XYZ(myUV_Max.U, myUV_Max.V, 0); XYZ myXYZ_UV_CornerOne = (((myXYZ_Max - myXYZ_Min) * 0.1)); //; + myXYZ_Min; XYZ myXYZ_UV_CornerTwo = (((myXYZ_Max - myXYZ_Min) * 0.9)); // + myXYZ_Min; XYZ myXYZ_UV_Corner01 = new XYZ(myXYZ_UV_CornerOne.X, myXYZ_UV_CornerOne.Y, 0); XYZ myXYZ_UV_Corner02 = new XYZ(myXYZ_UV_CornerTwo.X, myXYZ_UV_CornerOne.Y, 0); XYZ myXYZ_UV_Corner03 = new XYZ(myXYZ_UV_CornerTwo.X, myXYZ_UV_CornerTwo.Y, 0); XYZ myXYZ_UV_Corner04 = new XYZ(myXYZ_UV_CornerOne.X, myXYZ_UV_CornerTwo.Y, 0); Line L1 = Line.CreateBound(myTransform.OfPoint(myXYZ_UV_Corner01), myTransform.OfPoint(myXYZ_UV_Corner02)); Line L2 = Line.CreateBound(myTransform.OfPoint(myXYZ_UV_Corner02), myTransform.OfPoint(myXYZ_UV_Corner03)); Line L3 = Line.CreateBound(myTransform.OfPoint(myXYZ_UV_Corner03), myTransform.OfPoint(myXYZ_UV_Corner04)); Line L4 = Line.CreateBound(myTransform.OfPoint(myXYZ_UV_Corner04), myTransform.OfPoint(myXYZ_UV_Corner01)); CurveLoop myCurveLoop = new CurveLoop(); myCurveLoop.Append(L1); myCurveLoop.Append(L2); myCurveLoop.Append(L3); myCurveLoop.Append(L4); double myDouble_ExactLength = myCurveLoop.GetExactLength(); double myDouble_ExactLength_Twenty = myDouble_ExactLength / 40; XYZ myXYZ_Result = myTransform.OfPoint((myXYZ_Max - myXYZ_Min) / 2); int myIntCurrentSpinnerValue = myWindow1.myIntegerUpDown_OneToTwentyCount.Value.Value; int myInt_Positioning = (40 / myListOfStuffOnWall.Count()) * (myListOfStuffOnWall.IndexOf(myFI) + 1); myIntCurrentSpinnerValue = (40 - myInt_Positioning) + myIntCurrentSpinnerValue; if (myIntCurrentSpinnerValue > 40) { myIntCurrentSpinnerValue = myIntCurrentSpinnerValue - 40; } double myDouble_FutureForeach = myDouble_ExactLength_Twenty * myIntCurrentSpinnerValue; double myDouble_ThisFarAlong; switch (myDouble_FutureForeach) { case double n when n < L1.Length: myDouble_ThisFarAlong = myDouble_FutureForeach; myXYZ_Result = L1.GetEndPoint(0) + (L1.GetEndPoint(1) - L1.GetEndPoint(0)).Normalize().Multiply(myDouble_ThisFarAlong); break; case double n when n >= L1.Length& n < L1.Length + L2.Length: myDouble_ThisFarAlong = myDouble_FutureForeach - L1.Length; myXYZ_Result = L2.GetEndPoint(0) + (L2.GetEndPoint(1) - L2.GetEndPoint(0)).Normalize().Multiply(myDouble_ThisFarAlong); break; case double n when n >= L1.Length + L2.Length& n < L1.Length + L2.Length + L3.Length: myDouble_ThisFarAlong = myDouble_FutureForeach - L1.Length - L2.Length; myXYZ_Result = L3.GetEndPoint(0) + (L3.GetEndPoint(1) - L3.GetEndPoint(0)).Normalize().Multiply(myDouble_ThisFarAlong); break; case double n when n >= L1.Length + L2.Length + L3.Length: myDouble_ThisFarAlong = myDouble_FutureForeach - L1.Length - L2.Length - L3.Length; myXYZ_Result = L4.GetEndPoint(0) + (L4.GetEndPoint(1) - L4.GetEndPoint(0)).Normalize().Multiply(myDouble_ThisFarAlong); break; } XYZ myXYZ_MoveThisMuch = myXYZ_Result - ((LocationPoint)myFamilyInstance.Location).Point; ElementTransformUtils.MoveElement(doc, myFamilyInstance.Id, myXYZ_MoveThisMuch); //SketchPlane mySketchPlane = SketchPlane.Create(doc, pickedRef); //myListElementID.Add(doc.Create.NewModelCurve(L1, mySketchPlane).Id); //myListElementID.Add(doc.Create.NewModelCurve(L2, mySketchPlane).Id); //myListElementID.Add(doc.Create.NewModelCurve(L3, mySketchPlane).Id); //myListElementID.Add(doc.Create.NewModelCurve(L4, mySketchPlane).Id); } tx.Commit(); } if (myWindow1.myIntegerUpDown_OneToTwentyCount.Value.Value == 40) { myWindow1.myIntegerUpDown_OneToTwentyCount.Value = 0; } myWindow1.myIntegerUpDown_OneToTwentyCount.Value++; } } #region catch and finally catch (Exception ex) { DatabaseMethods.writeDebug("EE08_MoveElementAroundHostingSurface" + Environment.NewLine + ex.Message + Environment.NewLine + ex.InnerException, true); } finally { } #endregion }
// return null if parent should be completely clipped. // TODO: determine whether or not to use face boundary. private static IFCAnyHandle ProcessClippingFace(ExporterIFC exporterIFC, CurveLoop outerBoundary, Plane boundaryPlane, Plane extrusionBasePlane, XYZ extrusionDirection, IFCRange range, bool useFaceBoundary, IFCAnyHandle bodyItemHnd) { if (outerBoundary == null || boundaryPlane == null) throw new Exception("Invalid face boundary."); double clippingSlant = boundaryPlane.Normal.DotProduct(extrusionDirection); if (useFaceBoundary) { if (MathUtil.IsAlmostZero(clippingSlant)) return bodyItemHnd; } bool clipCompletely; if (!IsInRange(range, outerBoundary, boundaryPlane, extrusionDirection, out clipCompletely)) return clipCompletely ? null : bodyItemHnd; if (MathUtil.IsAlmostZero(clippingSlant)) throw new Exception("Can't create clipping perpendicular to extrusion."); IFCFile file = exporterIFC.GetFile(); XYZ scaledOrig = ExporterIFCUtils.TransformAndScalePoint(exporterIFC, boundaryPlane.Origin); XYZ scaledNorm = ExporterIFCUtils.TransformAndScaleVector(exporterIFC, boundaryPlane.Normal); XYZ scaledXDir = ExporterIFCUtils.TransformAndScaleVector(exporterIFC, boundaryPlane.XVec); IFCAnyHandle planeAxisHnd = ExporterUtil.CreateAxis(file, scaledOrig, scaledNorm, scaledXDir); IFCAnyHandle surfHnd = IFCInstanceExporter.CreatePlane(file, planeAxisHnd); IFCAnyHandle clippedBodyItemHnd = null; IFCAnyHandle halfSpaceHnd = null; if (useFaceBoundary) { IFCAnyHandle boundedCurveHnd; if (boundaryPlane != null) { XYZ projScaledOrigin = ExporterIFCUtils.TransformAndScalePoint(exporterIFC, extrusionBasePlane.Origin); XYZ projScaledX = ExporterIFCUtils.TransformAndScaleVector(exporterIFC, extrusionBasePlane.XVec); XYZ projScaledY= ExporterIFCUtils.TransformAndScaleVector(exporterIFC, extrusionBasePlane.YVec); XYZ projScaledNorm = projScaledX.CrossProduct(projScaledY); Plane projScaledPlane = new Plane(projScaledX, projScaledY, projScaledOrigin); IList<UV> polylinePts = TransformAndProjectCurveLoopToPlane(exporterIFC, outerBoundary, projScaledPlane); polylinePts.Add(polylinePts[0]); boundedCurveHnd = ExporterUtil.CreatePolyline(file, polylinePts); IFCAnyHandle boundedAxisHnd = ExporterUtil.CreateAxis(file, projScaledOrigin, projScaledNorm, projScaledX); halfSpaceHnd = IFCInstanceExporter.CreatePolygonalBoundedHalfSpace(file, boundedAxisHnd, boundedCurveHnd, surfHnd, false); } else { throw new Exception("Can't create non-polygonal face boundary."); } } else { halfSpaceHnd = IFCInstanceExporter.CreateHalfSpaceSolid(file, surfHnd, false); } if (halfSpaceHnd == null) throw new Exception("Can't create clipping."); clippedBodyItemHnd = IFCInstanceExporter.CreateBooleanClippingResult(file, IFCBooleanOperator.Difference, bodyItemHnd, halfSpaceHnd); return clippedBodyItemHnd; }
/// <summary> /// Exports a roof or floor as a container of multiple roof slabs. Returns the handle, if successful. /// </summary> /// <param name="exporterIFC">The exporter.</param> /// <param name="ifcEnumType">The roof type.</param> /// <param name="element">The roof or floor element.</param> /// <param name="geometry">The geometry of the element.</param> /// <param name="productWrapper">The product wrapper.</param> /// <returns>The roof handle.</returns> /// <remarks>For floors, if there is only one component, return null, as we do not want to create a container.</remarks> public static IFCAnyHandle ExportRoofOrFloorAsContainer(ExporterIFC exporterIFC, string ifcEnumType, Element element, GeometryElement geometry, ProductWrapper productWrapper) { IFCFile file = exporterIFC.GetFile(); // We support ExtrusionRoofs, FootPrintRoofs, and Floors only. bool elementIsRoof = (element is ExtrusionRoof) || (element is FootPrintRoof); bool elementIsFloor = (element is Floor); if (!elementIsRoof && !elementIsFloor) { return(null); } Common.Enums.IFCEntityType elementClassTypeEnum = Common.Enums.IFCEntityType.IfcRoof; if (elementIsFloor) { elementClassTypeEnum = Common.Enums.IFCEntityType.IfcSlab; } // Check the intended IFC entity or type name is in the exclude list specified in the UI if (ExporterCacheManager.ExportOptionsCache.IsElementInExcludeList(elementClassTypeEnum)) { return(null); } using (IFCTransaction transaction = new IFCTransaction(file)) { using (PlacementSetter setter = PlacementSetter.Create(exporterIFC, element)) { IFCAnyHandle localPlacement = setter.LocalPlacement; IList <HostObjectSubcomponentInfo> hostObjectSubcomponents = null; try { hostObjectSubcomponents = ExporterIFCUtils.ComputeSubcomponents(element as HostObject); } catch { return(null); } if (hostObjectSubcomponents == null) { return(null); } int numSubcomponents = hostObjectSubcomponents.Count; if (numSubcomponents == 0 || (elementIsFloor && numSubcomponents == 1)) { return(null); } try { using (IFCExtrusionCreationData extrusionCreationData = new IFCExtrusionCreationData()) { IFCAnyHandle ownerHistory = ExporterCacheManager.OwnerHistoryHandle; extrusionCreationData.SetLocalPlacement(localPlacement); extrusionCreationData.ReuseLocalPlacement = true; using (TransformSetter trfSetter = TransformSetter.Create()) { IList <GeometryObject> geometryList = new List <GeometryObject>(); geometryList.Add(geometry); trfSetter.InitializeFromBoundingBox(exporterIFC, geometryList, extrusionCreationData); IFCAnyHandle prodRepHnd = null; string elementGUID = GUIDUtil.CreateGUID(element); //string hostObjectType = IFCValidateEntry.GetValidIFCPredefinedType(element, ifcEnumType); IFCAnyHandle hostObjectHandle = null; if (elementIsRoof) { hostObjectHandle = IFCInstanceExporter.CreateRoof(exporterIFC, element, elementGUID, ownerHistory, localPlacement, prodRepHnd, ifcEnumType); } else { hostObjectHandle = IFCInstanceExporter.CreateSlab(exporterIFC, element, elementGUID, ownerHistory, localPlacement, prodRepHnd, ifcEnumType); } if (IFCAnyHandleUtil.IsNullOrHasNoValue(hostObjectHandle)) { return(null); } IList <IFCAnyHandle> elementHandles = new List <IFCAnyHandle>(); elementHandles.Add(hostObjectHandle); // If element is floor, then the profile curve loop of hostObjectSubComponent is computed from the top face of the floor // else if element is roof, then the profile curve loop is taken from the bottom face of the roof instead XYZ extrusionDir = elementIsFloor ? new XYZ(0, 0, -1) : new XYZ(0, 0, 1); ElementId catId = CategoryUtil.GetSafeCategoryId(element); IList <IFCAnyHandle> slabHandles = new List <IFCAnyHandle>(); IList <CurveLoop> hostObjectOpeningLoops = new List <CurveLoop>(); double maximumScaledDepth = 0.0; using (IFCExtrusionCreationData slabExtrusionCreationData = new IFCExtrusionCreationData()) { slabExtrusionCreationData.SetLocalPlacement(extrusionCreationData.GetLocalPlacement()); slabExtrusionCreationData.ReuseLocalPlacement = false; slabExtrusionCreationData.ForceOffset = true; int loopNum = 0; int subElementStart = elementIsRoof ? (int)IFCRoofSubElements.RoofSlabStart : (int)IFCSlabSubElements.SubSlabStart; string subSlabType = elementIsRoof ? "ROOF" : ifcEnumType; foreach (HostObjectSubcomponentInfo hostObjectSubcomponent in hostObjectSubcomponents) { trfSetter.InitializeFromBoundingBox(exporterIFC, geometryList, slabExtrusionCreationData); Plane plane = hostObjectSubcomponent.GetPlane(); Transform lcs = GeometryUtil.CreateTransformFromPlane(plane); IList <CurveLoop> curveLoops = new List <CurveLoop>(); CurveLoop slabCurveLoop = hostObjectSubcomponent.GetCurveLoop(); curveLoops.Add(slabCurveLoop); double slope = Math.Abs(plane.Normal.Z); double scaledDepth = UnitUtil.ScaleLength(hostObjectSubcomponent.Depth); double scaledExtrusionDepth = scaledDepth * slope; IFCAnyHandle shapeRep = ExtrusionExporter.CreateExtrudedSolidFromCurveLoop(exporterIFC, null, curveLoops, lcs, extrusionDir, scaledExtrusionDepth, false); if (IFCAnyHandleUtil.IsNullOrHasNoValue(shapeRep)) { return(null); } ElementId matId = HostObjectExporter.GetFirstLayerMaterialId(element as HostObject); BodyExporter.CreateSurfaceStyleForRepItem(exporterIFC, element.Document, shapeRep, matId); HashSet <IFCAnyHandle> bodyItems = new HashSet <IFCAnyHandle>(); bodyItems.Add(shapeRep); shapeRep = RepresentationUtil.CreateSweptSolidRep(exporterIFC, element, catId, exporterIFC.Get3DContextHandle("Body"), bodyItems, null); IList <IFCAnyHandle> shapeReps = new List <IFCAnyHandle>(); shapeReps.Add(shapeRep); IFCAnyHandle repHnd = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, shapeReps); // Allow support for up to 256 named IfcSlab components, as defined in IFCSubElementEnums.cs. string slabGUID = (loopNum < 256) ? GUIDUtil.CreateSubElementGUID(element, subElementStart + loopNum) : GUIDUtil.CreateGUID(); IFCAnyHandle slabPlacement = ExporterUtil.CreateLocalPlacement(file, slabExtrusionCreationData.GetLocalPlacement(), null); IFCAnyHandle slabHnd = IFCInstanceExporter.CreateSlab(exporterIFC, element, slabGUID, ownerHistory, slabPlacement, repHnd, subSlabType); //slab quantities slabExtrusionCreationData.ScaledLength = scaledExtrusionDepth; slabExtrusionCreationData.ScaledArea = UnitUtil.ScaleArea(UnitUtil.ScaleArea(hostObjectSubcomponent.AreaOfCurveLoop)); slabExtrusionCreationData.ScaledOuterPerimeter = UnitUtil.ScaleLength(curveLoops[0].GetExactLength()); slabExtrusionCreationData.Slope = UnitUtil.ScaleAngle(MathUtil.SafeAcos(Math.Abs(slope))); productWrapper.AddElement(null, slabHnd, setter, slabExtrusionCreationData, false); elementHandles.Add(slabHnd); slabHandles.Add(slabHnd); hostObjectOpeningLoops.Add(slabCurveLoop); maximumScaledDepth = Math.Max(maximumScaledDepth, scaledDepth); loopNum++; } } productWrapper.AddElement(element, hostObjectHandle, setter, extrusionCreationData, true); ExporterUtil.RelateObjects(exporterIFC, null, hostObjectHandle, slabHandles); OpeningUtil.AddOpeningsToElement(exporterIFC, elementHandles, hostObjectOpeningLoops, element, null, maximumScaledDepth, null, setter, localPlacement, productWrapper); transaction.Commit(); return(hostObjectHandle); } } } finally { exporterIFC.ClearFaceWithElementHandleMap(); } } } }
/// <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> /// Create a swept geometry /// </summary> /// <param name="sweepPath">The sweep path, consisting of a set of contiguous curves</param> /// <param name="pathAttachmentCrvIdx">The index of the curve in the sweep path where the profile loops are situated</param> /// <param name="pathAttachmentParam">Parameter of the path curve specified by pathAttachmentCrvIdx</param> /// <param name="profileLoops">The curve loops defining the planar domain to be swept along the path</param> /// <returns>The created solid</returns> private Solid CreateSwept(CurveLoop sweepPath, int pathAttachmentCrvIdx, double pathAttachmentParam, List <CurveLoop> profileLoops) { return(GeometryCreationUtilities.CreateSweptGeometry(sweepPath, pathAttachmentCrvIdx, pathAttachmentParam, profileLoops)); }
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; }
/// <summary> /// Create a blend geometry /// </summary> /// <param name="firstLoop">The first curve loop</param> /// <param name="secondLoop">The second curve loop</param> /// <param name="vertexPairs">This input specifies how the two profile loops should be connected</param> /// <returns>The created solid</returns> private Solid CreateBlend(CurveLoop firstLoop, CurveLoop secondLoop, List <VertexPair> vertexPairs) { return(GeometryCreationUtilities.CreateBlendGeometry(firstLoop, secondLoop, vertexPairs)); }
/// <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); } }
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) { Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application(); Microsoft.Office.Interop.Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(@"D:\WerkStudent\Updated\General_WithOpening"); Microsoft.Office.Interop.Excel.Worksheet xlWorksheet = xlWorkbook.Sheets[3]; Microsoft.Office.Interop.Excel.Range xlRange = xlWorksheet.UsedRange; int rowCount = xlRange.Rows.Count; int colCount = xlRange.Columns.Count; //Get UI document UIDocument uidoc = commandData.Application.ActiveUIDocument; //Get document Document doc = uidoc.Document; string level = (String)xlRange.Cells[3, "A"].Value2; //Create levels Level levels = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Levels) .WhereElementIsNotElementType().Cast <Level>().First(x => x.Name == level); string ty1 = (String)xlRange.Cells[2, "A"].Value2; var FloorType = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Floors) .WhereElementIsElementType().Cast <FloorType>().First(x => x.Name == ty1); //string ty2 = (String)xlRange.Cells[2, "B"].Value2; ////var opening =sourceFloor.Document.Create.NewOpening(destFloor,openingCurveArray,true); //var Opening = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_FloorOpening) // .WhereElementIsElementType().Cast<Opening>(); double p01x = xlRange.Cells[4, "B"].value2; double p01y = xlRange.Cells[4, "C"].value2; double p01z = xlRange.Cells[4, "D"].value2; double p02x = xlRange.Cells[5, "B"].value2; double p02y = xlRange.Cells[5, "C"].value2; double p02z = xlRange.Cells[5, "D"].value2; double p03x = xlRange.Cells[6, "B"].value2; double p03y = xlRange.Cells[6, "C"].value2; double p03z = xlRange.Cells[6, "D"].value2; double p04x = xlRange.Cells[7, "B"].value2; double p04y = xlRange.Cells[7, "C"].value2; double p04z = xlRange.Cells[7, "D"].value2; double cF = 1 / 0.3048; XYZ p01 = new XYZ(p01x * cF, p01y * cF, p01z * cF); XYZ p02 = new XYZ(p02x * cF, p02y * cF, p02z * cF); XYZ p03 = new XYZ(p03x * cF, p03y * cF, p03z * cF); XYZ p04 = new XYZ(p04x * cF, p04y * cF, p04z * cF); double p11x = xlRange.Cells[9, "B"].value2; double p11y = xlRange.Cells[9, "C"].value2; double p11z = xlRange.Cells[9, "D"].value2; double p12x = xlRange.Cells[10, "B"].value2; double p12y = xlRange.Cells[10, "C"].value2; double p12z = xlRange.Cells[10, "D"].value2; double p13x = xlRange.Cells[11, "B"].value2; double p13y = xlRange.Cells[11, "C"].value2; double p13z = xlRange.Cells[11, "D"].value2; double p14x = xlRange.Cells[12, "B"].value2; double p14y = xlRange.Cells[12, "C"].value2; double p14z = xlRange.Cells[12, "D"].value2; XYZ p11 = new XYZ(p11x * cF, p11y * cF, p11z * cF); XYZ p12 = new XYZ(p12x * cF, p12y * cF, p12z * cF); XYZ p13 = new XYZ(p13x * cF, p13y * cF, p13z * cF); XYZ p14 = new XYZ(p14x * cF, p14y * cF, p14z * cF); double pf1x = xlRange.Cells[14, "B"].value2; double pf1y = xlRange.Cells[14, "C"].value2; double pf1z = xlRange.Cells[14, "D"].value2; double pf2x = xlRange.Cells[15, "B"].value2; double pf2y = xlRange.Cells[15, "C"].value2; double pf2z = xlRange.Cells[15, "D"].value2; double pf3x = xlRange.Cells[16, "B"].value2; double pf3y = xlRange.Cells[16, "C"].value2; double pf3z = xlRange.Cells[16, "D"].value2; double pf4x = xlRange.Cells[17, "B"].value2; double pf4y = xlRange.Cells[17, "C"].value2; double pf4z = xlRange.Cells[17, "D"].value2; XYZ pf1 = new XYZ(pf1x * cF, pf1y * cF, pf1z * cF); XYZ pf2 = new XYZ(pf2x * cF, pf2y * cF, pf2z * cF); XYZ pf3 = new XYZ(pf3x * cF, pf3y * cF, pf3z * cF); XYZ pf4 = new XYZ(pf4x * cF, pf4y * cF, pf4z * cF); Line l01 = Line.CreateBound(p01, p02); Line l02 = Line.CreateBound(p02, p03); Line l03 = Line.CreateBound(p03, p04); Line l04 = Line.CreateBound(p04, p01); Line l11 = Line.CreateBound(p11, p12); Line l12 = Line.CreateBound(p12, p13); Line l13 = Line.CreateBound(p13, p14); Line l14 = Line.CreateBound(p14, p11); Line lf1 = Line.CreateBound(pf1, pf2); Line lf2 = Line.CreateBound(pf2, pf3); Line lf3 = Line.CreateBound(pf3, pf4); Line lf4 = Line.CreateBound(pf4, pf1); List <Curve> curves = new List <Curve>(); curves.Add(l01); curves.Add(l02); curves.Add(l03); curves.Add(l04); List <Curve> curves1 = new List <Curve>(); curves1.Add(l11); curves1.Add(l12); curves1.Add(l13); curves1.Add(l14); List <Curve> curvesf = new List <Curve>(); curvesf.Add(lf1); curvesf.Add(lf2); curvesf.Add(lf3); curvesf.Add(lf4); // Making a curve in a loop CurveLoop crvloop = CurveLoop.Create(curves); CurveLoop crvloop1 = CurveLoop.Create(curves1); CurveLoop crvloopf = CurveLoop.Create(curvesf); CurveLoop offcr = CurveLoop.CreateViaOffset(crvloop, 0.1 * cF, new XYZ(0, 0, 1)); CurveLoop offcr1 = CurveLoop.CreateViaOffset(crvloop1, 0.1 * cF, new XYZ(0, 0, 1)); CurveLoop offcrf = CurveLoop.CreateViaOffset(crvloopf, 0.1 * cF, new XYZ(0, 0, 1)); // Creating a curve array object required for method CurveArray curArr = new CurveArray(); CurveArray curArr1 = new CurveArray(); CurveArray openingCurveArray = new CurveArray(); foreach (Curve c in offcr) { //Put the curves to curve array curArr.Append(c); } foreach (Curve c in offcr1) { //Put the curves to curve array curArr1.Append(c); } foreach (Curve c in offcrf) { //Put the curves to curve array openingCurveArray.Append(c); } try { using (Transaction trans = new Transaction(doc, "Bungalow/Flair110/Flair152RE")) { trans.Start(); doc.Create.NewFloor(curArr, FloorType, levels, false); // doc.Create.NewFloor(curArr1, FloorType, levels, false); //////Floor flaw = doc.Create.NewFloor(curArr,false); //Floor fl = doc.Create.NewFloor(curArr1, FloorType, levels, false); //doc.Create.NewOpening(fl, curArr1, false); //XYZ openingEdges1 = pf1; //XYZ openingEdges2 = pf2; //XYZ openingEdges3 = pf3; //XYZ openingEdges4 = pf4; //var openingEdges = {openingEdges1, openingEdges2, openingEdges3, openingEdges4}; //var openingCurveArray = openingEdges; var opening = doc.Create.NewFloor(curArr, FloorType, levels, false); doc.Create.NewOpening(opening, openingCurveArray, true); trans.Commit(); } return(Result.Succeeded); } catch (Exception e) { message = e.Message; return(Result.Failed); } }