/// <summary> /// Does this ray intersect with the provided GeometricElement? Only GeometricElements with Solid Representations are currently supported, and voids will be ignored. /// </summary> /// <param name="element">The element to intersect with.</param> /// <param name="result">The list of intersection results.</param> /// <returns></returns> public bool Intersects(GeometricElement element, out List <Vector3> result) { if (element.Representation == null || element.Representation.SolidOperations == null || element.Representation.SolidOperations.Count == 0) { element.UpdateRepresentations(); } List <Vector3> resultsOut = new List <Vector3>(); var transformFromElement = new Transform(element.Transform); transformFromElement.Invert(); var transformToElement = new Transform(element.Transform); var transformedRay = new Ray(transformFromElement.OfPoint(Origin), transformFromElement.OfVector(Direction)); //TODO: extend to handle voids when void solids in Representations are supported generally var intersects = false; foreach (var solidOp in element.Representation.SolidOperations.Where(e => !e.IsVoid)) { if (transformedRay.Intersects(solidOp, out List <Vector3> tempResults)) { intersects = true; resultsOut.AddRange(tempResults.Select(t => transformToElement.OfPoint(t))); } ; } result = resultsOut; return(intersects); }
internal static List <IfcProduct> ToIfcProducts(this Element e, IfcRepresentationContext context, Document doc, Dictionary <Guid, List <IfcStyleAssignmentSelect> > styleAssignments) { var products = new List <IfcProduct>(); IfcProductDefinitionShape shape = null; GeometricElement geoElement = null; Transform trans = null; Guid id = default(Guid); if (e is ElementInstance) { // If we're using an element instance, get the transform // and the id and use those to uniquely position and // identify the element. var instance = (ElementInstance)e; geoElement = instance.BaseDefinition; id = instance.Id; trans = instance.Transform; } else if (e is GeometricElement) { // If we've go a geometric element, use its properties as-is. geoElement = (GeometricElement)e; id = geoElement.Id; trans = geoElement.Transform; } geoElement.UpdateRepresentations(); var localPlacement = trans.ToIfcLocalPlacement(doc); doc.AddEntity(localPlacement); var geoms = new List <IfcRepresentationItem>(); if (geoElement is MeshElement) { var meshEl = (MeshElement)geoElement; var lengths = meshEl.Mesh.Vertices.Select(v => v.Position.ToArray().Select(vi => new IfcLengthMeasure(vi)).ToList()).ToList(); var pts = new IfcCartesianPointList3D(lengths); doc.AddEntity(pts); var indices = meshEl.Mesh.Triangles.Select(t => t.Vertices.Select(vx => new IfcPositiveInteger(vx.Index + 1)).ToList()).ToList(); var idxs = new List <List <IfcPositiveInteger> >(indices); var geom = new IfcTriangulatedFaceSet(pts, indices); geom.Closed = false; doc.AddEntity(geom); geoms.Add(geom); shape = ToIfcProductDefinitionShape(geoms, "Tessellation", context, doc); } else { foreach (var op in geoElement.Representation.SolidOperations) { if (op is Sweep) { var sweep = (Sweep)op; // Neither of these entities, which are part of the // IFC4 specification, and which would allow a sweep // along a curve, are supported by many applications // which are supposedly IFC4 compliant (Revit). For // Those applications where these entities appear, // the rotation of the profile is often wrong or // inconsistent. // geom = sweep.ToIfcSurfaceCurveSweptAreaSolid(doc); // geom = sweep.ToIfcFixedReferenceSweptAreaSolid(geoElement.Transform, doc); // Instead, we'll divide the curve and create a set of // linear extrusions instead. Polyline pline; if (sweep.Curve is Line) { pline = sweep.Curve.ToPolyline(1); } else { pline = sweep.Curve.ToPolyline(); } foreach (var segment in pline.Segments()) { var position = segment.TransformAt(0.0).ToIfcAxis2Placement3D(doc); var extrudeDepth = segment.Length(); var extrudeProfile = sweep.Profile.Perimeter.ToIfcArbitraryClosedProfileDef(doc); var extrudeDirection = Vector3.ZAxis.Negate().ToIfcDirection(); var geom = new IfcExtrudedAreaSolid(extrudeProfile, position, extrudeDirection, new IfcPositiveLengthMeasure(extrudeDepth)); doc.AddEntity(extrudeProfile); doc.AddEntity(extrudeDirection); doc.AddEntity(position); doc.AddEntity(geom); geoms.Add(geom); } } else if (op is Extrude) { var extrude = (Extrude)op; var geom = extrude.ToIfcExtrudedAreaSolid(doc); doc.AddEntity(geom); geoms.Add(geom); } else if (op is Lamina) { var lamina = (Lamina)op; var geom = lamina.ToIfcShellBasedSurfaceModel(doc); doc.AddEntity(geom); geoms.Add(geom); } else { throw new Exception("Only IExtrude, ISweepAlongCurve, and ILamina representations are currently supported."); } } shape = ToIfcProductDefinitionShape(geoms, "SolidModel", context, doc); } doc.AddEntity(shape); // Can we use IfcMappedItem? // https://forums.buildingsmart.org/t/can-tessellation-typed-representation-hold-items-from-another-group/1621 // var rep = new IfcShapeRepresentation(context, "Body", "Solids", geoms); // doc.AddEntity(rep); // var axisPt = Vector3.Origin.ToIfcCartesianPoint(); // doc.AddEntity(axisPt); // var axis = new IfcAxis2Placement2D(axisPt); // doc.AddEntity(axis); // var repMap = new IfcRepresentationMap(new IfcAxis2Placement(axis), rep); // doc.AddEntity(repMap); // var x = trans.XAxis.ToIfcDirection(); // var y = trans.YAxis.ToIfcDirection(); // var z = trans.ZAxis.ToIfcDirection(); // var origin = trans.Origin.ToIfcCartesianPoint(); // var cart = new IfcCartesianTransformationOperator3D(x, y, origin, trans.XAxis.Length(), z); // doc.AddEntity(x); // doc.AddEntity(y); // doc.AddEntity(z); // doc.AddEntity(origin); // doc.AddEntity(cart); // var mappedItem = new IfcMappedItem(repMap, cart); // doc.AddEntity(mappedItem); // var shapeRep= new IfcShapeRepresentation(context, new List<IfcRepresentationItem>(){mappedItem}); // doc.AddEntity(shapeRep); // shape = new IfcProductDefinitionShape(new List<IfcRepresentation>(){shapeRep}); // doc.AddEntity(shape); var product = ConvertElementToIfcProduct(id, geoElement, localPlacement, shape); products.Add(product); doc.AddEntity(product); var ifcOpenings = doc.AllEntities.Where(ent => ent.GetType() == typeof(IfcOpeningElement)).Cast <IfcOpeningElement>(); // If the element has openings, make opening relationships in // the IfcElement. if (e is IHasOpenings) { var openings = (IHasOpenings)e; if (openings.Openings.Count > 0) { foreach (var o in openings.Openings) { var element = (IfcElement)product; // TODO: Find the opening that we've already created that relates here var opening = ifcOpenings.First(ifcO => ifcO.GlobalId == IfcGuid.ToIfcGuid(o.Id)); var voidRel = new IfcRelVoidsElement(IfcGuid.ToIfcGuid(Guid.NewGuid()), element, opening); element.HasOpenings.Add(voidRel); doc.AddEntity(voidRel); } } } foreach (var geom in geoms) { var styledItem = new IfcStyledItem(geom, styleAssignments[geoElement.Material.Id], null); doc.AddEntity(styledItem); } return(products); }
public void UnionWithProblematicPolygons() { var profile1 = JsonConvert.DeserializeObject <Polygon>( @"{ ""Vertices"": [ { ""X"": -348.82036858497275, ""Y"": 246.02759072077453, ""Z"": 30.25 }, { ""X"": -348.85572392403208, ""Y"": 246.06294605983385, ""Z"": 30.25 }, { ""X"": -350.60244308413706, ""Y"": 244.31622689972886, ""Z"": 30.25 }, { ""X"": -350.56708774507774, ""Y"": 244.28087156066954, ""Z"": 30.25 }, { ""X"": -350.53173240601842, ""Y"": 244.24551622161022, ""Z"": 30.25 }, { ""X"": -348.78501324591343, ""Y"": 245.9922353817152, ""Z"": 30.25 } ]} "); var profile2 = JsonConvert.DeserializeObject <Polygon>( @"{ ""Vertices"": [ { ""X"": -350.56708774507774, ""Y"": 244.28087156066954, ""Z"": 30.25 }, { ""X"": -350.51708774507773, ""Y"": 244.28087156066954, ""Z"": 30.25 }, { ""X"": -350.51708774507773, ""Y"": 247.77430988087954, ""Z"": 30.25 }, { ""X"": -350.56708774507774, ""Y"": 247.77430988087954, ""Z"": 30.25 }, { ""X"": -350.61708774507775, ""Y"": 247.77430988087954, ""Z"": 30.25 }, { ""X"": -350.61708774507775, ""Y"": 244.28087156066954, ""Z"": 30.25 } ]}" ); var element = new GeometricElement(); element.Representation = new Representation(new List <SolidOperation> { new Extrude(profile1, 1, Vector3.ZAxis, false), new Extrude(profile2, 1, Vector3.ZAxis, false) }); element.UpdateRepresentations(); var solid = element.GetFinalCsgFromSolids(); }