/// <summary> /// Bounding box of all hidden elements, aligned to the XYZ axis, containing all points in this mesh /// </summary> /// <param name="forceRecalculation">if true the bounding box is recalculated, if false the previous cached version is returned</param> /// <returns></returns> public XbimRect3D BoundingBoxHidden(bool forceRecalculation = false) { if (!forceRecalculation && !_boundingBoxHidden.IsEmpty) { return(_boundingBoxHidden); } var first = true; foreach (var pos in Hidden.Positions) { if (first) { _boundingBoxHidden = new XbimRect3D(pos); first = false; } else { _boundingBoxHidden.Union(pos); } } foreach (var sublayer in _subLayerMap) { XbimRect3D subBox = sublayer.BoundingBoxHidden(forceRecalculation); if (!subBox.IsEmpty) { _boundingBoxHidden.Union(subBox); } } return(_boundingBoxHidden); }
/// <summary> /// Constructor of spatial relations analyser of axis aligned bounding boxes of the products. /// If you already have a dictionary of the AABBoxes and products you should use the other constructor /// </summary> /// <param name="model">Building model</param> public XbimAABBoxAnalyser(XbimModel model) { _model = model; Xbim3DModelContext context = new Xbim3DModelContext(model); if (model.GeometriesCount == 0) { context.CreateContext(); } //create cached BBoxes foreach (var prod in model.IfcProducts.Cast <IfcProduct>()) { XbimRect3D prodBox = XbimRect3D.Empty; foreach (var shp in context.ShapeInstancesOf(prod)) { //bounding boxes are lightweight and are produced when geometry is created at first place //get or cast to BBox var bb = shp.BoundingBox; bb = XbimRect3D.TransformBy(bb, shp.Transformation); if (prodBox.IsEmpty) { prodBox = bb; } else { prodBox.Union(bb); } //add every BBox to the world to get the size and position of the world } _prodBBs.Add(prod, prodBox); } }
/// <summary> /// 获取一个ifcproduct的boundingbox /// </summary> /// <param name="product">指定的product</param> /// <returns>XbimRect3D精度为2位的盒子</returns> public XbimRect3D GetAABB(IIfcProduct product) { //Xbim3DModelContext context = new Xbim3DModelContext(model); //context.CreateContext(); XbimRect3D prodBox = XbimRect3D.Empty; if (context.ShapeInstancesOf(product).Count() == 0) { return(prodBox); } foreach (var shp in context.ShapeInstancesOf(product)) { var bb = shp.BoundingBox; bb = XbimRect3D.TransformBy(bb, shp.Transformation); if (prodBox.IsEmpty) { prodBox = bb; } else { prodBox.Union(bb); } } //精度为2位小数 prodBox.Round(2); return(prodBox); //Console.WriteLine(prodBox.ToString()); }
public static bool Touches(XbimRect3D a, XbimRect3D b, double tolerance) { XbimRect3D envelope = XbimRect3D.Empty; envelope.Union(a); envelope.Union(b); var xSize = a.SizeX + b.SizeX; var ySize = a.SizeY + b.SizeY; var zSize = a.SizeZ + b.SizeZ; return ((xSize >= envelope.SizeX && ySize >= envelope.SizeY && AlmostEqual(zSize, envelope.SizeZ, tolerance)) || (xSize >= envelope.SizeX && AlmostEqual(ySize, envelope.SizeY, tolerance) && zSize >= envelope.SizeZ) || (AlmostEqual(xSize, envelope.SizeX, tolerance) && ySize >= envelope.SizeY && zSize >= envelope.SizeZ) ); }
private XbimRegion Merge(XbimRegion selectedRegion, XbimRegion reg) { var s1 = MinMaxPoints(selectedRegion); var s2 = MinMaxPoints(reg); var r1 = new XbimRect3D(s1[0], s1[1]); var r2 = new XbimRect3D(s2[0], s2[1]); r1.Union(r2); var merged = new XbimRegion("Merged", r1, selectedRegion.Population + reg.Population); return(merged); }
public static bool Intersects(XbimRect3D a, XbimRect3D b, double tolerance) { XbimRect3D envelope = XbimRect3D.Empty; envelope.Union(a); envelope.Union(b); var xSize = a.SizeX + b.SizeX; var ySize = a.SizeY + b.SizeY; var zSize = a.SizeZ + b.SizeZ; return (( xSize > envelope.SizeX && ySize > envelope.SizeY && zSize > envelope.SizeZ ) && !( //avoid identical geometries to be supposed to be intersection AlmostEqual(xSize / 2f, envelope.SizeX, tolerance) && AlmostEqual(ySize / 2f, envelope.SizeY, tolerance) && AlmostEqual(zSize / 2f, envelope.SizeZ, tolerance) ) ); }
private void LoadObjectBuffer(IfcStore model) { _bboxBuffer = new Dictionary <int, XbimRect3D>(); _labelBuffer = new Dictionary <int, string>(); _boundingBox = XbimRect3D.Empty; var context = new Xbim3DModelContext(model); context.CreateContext(); List <IfcProduct> prods = model.Instances.OfType <IfcProduct>().ToList(); foreach (var prod in prods) { List <XbimShapeInstance> prodShapes = context.ShapeInstancesOf(prod).Where(p => p.RepresentationType != XbimGeometryRepresentationType.OpeningsAndAdditionsExcluded).Distinct().ToList(); if (prodShapes == null || prodShapes.Count == 0) { continue; } XbimRect3D bbox = XbimRect3D.Empty; foreach (var shape in prodShapes) { if (bbox.IsEmpty) { bbox = shape.BoundingBox; } else { bbox.Union(shape.BoundingBox); } } _bboxBuffer.Add(prod.EntityLabel, bbox); _labelBuffer.Add(prod.EntityLabel, prod.GetType().Name); if (_boundingBox.IsEmpty) { _boundingBox = bbox; } else { _boundingBox.Union(bbox); } } log.InfoFormat("{0} Objects loaded from the file.", _bboxBuffer.Count); }
/// <summary> /// Returns the total bounds for all contetn under this node /// </summary> /// <returns></returns> public XbimRect3D ContentBounds() { XbimRect3D b = contentBounds; if (children != null) { foreach (var child in children) { XbimRect3D cb = child.ContentBounds(); if (!cb.IsEmpty) { b.Union(cb); } } } return(b); }
private XbimRegion Merge(XbimRegion reg1, XbimRegion reg2) { // todo: needs to review the merge function to consider region's WorldCoordinateSystem // var s1 = MinMaxPoints(reg1); var s2 = MinMaxPoints(reg2); var r1 = new XbimRect3D(s1[0], s1[1]); var r2 = new XbimRect3D(s2[0], s2[1]); r1.Union(r2); var merged = new XbimRegion( "Merged", r1, reg1.Population + reg2.Population, reg1.WorldCoordinateSystem ); return(merged); }
/// <summary> /// Adds the given object to the octree. /// </summary> /// <param name="o">The object to add.</param> /// <param name="b">The object's bounds.</param> /// <param name="centre">The object's centre coordinates.</param> /// <param name="radius">The object's radius.</param> /// <returns></returns> private XbimOctree <T> Add(T o, XbimRect3D b, XbimPoint3D centre, double radius) { lock (this.objects) { if (this.children == null && this.bounds.Length() > this.targetCanvasSize) { this.Split(); } } if (this.children != null) { // Find which child the object is closest to based on where the // object's centre is located in relation to the octree's centre. int index = (centre.X <= this.centre.X ? 0 : 1) + (centre.Y >= this.centre.Y ? 0 : 4) + (centre.Z <= this.centre.Z ? 0 : 2); // Add the object to the child if it is fully contained within // it. if (this.children[index].bounds.Contains(b)) { return(this.children[index].Add(o, b, centre, radius)); } } // Debug.WriteLine("Addedto: " + this.Name); this.objects.Add(o); //otherwise add it to here if (contentBounds.IsEmpty) { contentBounds = b; } else { contentBounds.Union(b); } return(this); }
public int AddNode(int face, double px, double py, double pz, double nx, double ny, double nz, double u, double v) { PointCount++; BoundingBox.Union(new XbimPoint3D(px, py, pz)); return(PointCount); }
/// <summary> /// Add a Bounding Box extrusion onto the ifcProduct /// </summary> /// <param name="row">COBieCoordinateRow holding the data for one corner</param> /// <param name="rowNext">COBieCoordinateRow holding the data for the other corner</param> /// <param name="placementRelToIfcProduct">Product which is parent of ifcProduct passed product to add extrusion onto</param> /// <param name="ifcProduct">IfcProduct to add the extrusion onto</param> private void AddExtrudedRectangle(COBieCoordinateRow row, COBieCoordinateRow rowNext, IfcProduct ifcProduct, IfcProduct placementRelToIfcProduct) { if (ifcProduct != null) { COBieCoordinateRow lowerLeftRow, upperRightRow; if (row.Category.ToLower() == "box-lowerleft") { lowerLeftRow = row; upperRightRow = rowNext; } else { lowerLeftRow = rowNext; upperRightRow = row; } IfcLocalPlacement objectPlacement = CalcObjectPlacement(lowerLeftRow, placementRelToIfcProduct); if (objectPlacement != null) { //set the object placement for the space ifcProduct.ObjectPlacement = objectPlacement; //get matrix to the space placement XbimMatrix3D matrix3D = ConvertMatrix3D(objectPlacement); //invert matrix so we can convert row points back to the object space matrix3D.Invert(); //lets get the points from the two rows XbimPoint3D lowpt, highpt; if ((GetPointFromRow(upperRightRow, out highpt)) && (GetPointFromRow(lowerLeftRow, out lowpt)) ) { //transform the points back to object space lowpt = matrix3D.Transform(lowpt); highpt = matrix3D.Transform(highpt); //in object space so we can use Rect3D as this will be aligned with coordinates systems X and Y XbimRect3D bBox = new XbimRect3D(); bBox.Location = lowpt; bBox.Union(highpt); if ((double.NaN.CompareTo(bBox.SizeX) != 0) && (double.NaN.CompareTo(bBox.SizeY) != 0)) { XbimPoint3D ctrPt = new XbimPoint3D(bBox.X + (bBox.SizeX / 2.0), bBox.Y + (bBox.SizeY / 2.0), bBox.Z + (bBox.SizeZ / 2.0)); //Create IfcRectangleProfileDef IfcCartesianPoint IfcCartesianPointCtr = Model.Instances.New <IfcCartesianPoint>(cp => { cp.X = ctrPt.X; cp.Y = ctrPt.Y; cp.Z = 0.0; }); //centre point of 2D box IfcDirection IfcDirectionXDir = Model.Instances.New <IfcDirection>(d => { d.X = 1.0; d.Y = 0; d.Z = 0.0; }); //default to X direction IfcAxis2Placement2D ifcAxis2Placement2DCtr = Model.Instances.New <IfcAxis2Placement2D>(a2p => { a2p.Location = IfcCartesianPointCtr; a2p.RefDirection = IfcDirectionXDir; }); IfcRectangleProfileDef ifcRectangleProfileDef = Model.Instances.New <IfcRectangleProfileDef>(rpd => { rpd.ProfileType = IfcProfileTypeEnum.AREA; rpd.ProfileName = row.RowName; rpd.Position = ifcAxis2Placement2DCtr; rpd.XDim = bBox.SizeX; rpd.YDim = bBox.SizeY; }); //Create IfcExtrudedAreaSolid IfcDirection IfcDirectionAxis = Model.Instances.New <IfcDirection>(d => { d.X = 0.0; d.Y = 0; d.Z = 1.0; }); //default to Z direction IfcDirection IfcDirectionRefDir = Model.Instances.New <IfcDirection>(d => { d.X = 1.0; d.Y = 0; d.Z = 0.0; }); //default to X direction IfcCartesianPoint IfcCartesianPointPosition = Model.Instances.New <IfcCartesianPoint>(cp => { cp.X = 0.0; cp.Y = 0.0; cp.Z = 0.0; }); //centre point of 2D box IfcAxis2Placement3D ifcAxis2Placement3DPosition = Model.Instances.New <IfcAxis2Placement3D>(a2p3D => { a2p3D.Location = IfcCartesianPointPosition; a2p3D.Axis = IfcDirectionAxis; a2p3D.RefDirection = IfcDirectionRefDir; }); IfcDirection IfcDirectionExtDir = Model.Instances.New <IfcDirection>(d => { d.X = 0.0; d.Y = 0; d.Z = 1.0; }); //default to Z direction IfcExtrudedAreaSolid ifcExtrudedAreaSolid = Model.Instances.New <IfcExtrudedAreaSolid>(eas => { eas.SweptArea = ifcRectangleProfileDef; eas.Position = ifcAxis2Placement3DPosition; eas.ExtrudedDirection = IfcDirectionExtDir; eas.Depth = bBox.SizeZ; }); var project = Model.FederatedInstances.OfType <IfcProject>().FirstOrDefault(); //Create IfcShapeRepresentation IfcShapeRepresentation ifcShapeRepresentation = Model.Instances.New <IfcShapeRepresentation>(sr => { sr.ContextOfItems = project.ModelContext; sr.RepresentationIdentifier = "Body"; sr.RepresentationType = "SweptSolid"; }); ifcShapeRepresentation.Items.Add(ifcExtrudedAreaSolid); //create IfcProductDefinitionShape IfcProductDefinitionShape ifcProductDefinitionShape = Model.Instances.New <IfcProductDefinitionShape>(pds => { pds.Name = row.Name; pds.Description = row.SheetName; }); ifcProductDefinitionShape.Representations.Add(ifcShapeRepresentation); //Link to the IfcProduct ifcProduct.Representation = ifcProductDefinitionShape; } else { #if DEBUG Console.WriteLine("Failed to calculate box size for {0}", row.Name); #endif } } } else { #if DEBUG Console.WriteLine("Failed to add Object placement for {0}", row.Name); #endif } } }
/// <summary> /// This version uses the new Geometry representation /// </summary> /// <param name="model"></param> /// <param name="context"></param> /// <param name="exclude">List of type to exclude, by default excplict openings and spaces are excluded if exclude = null</param> /// <returns></returns> private void BuildScene(Xbim3DModelContext context) { //get a list of all the unique styles Dictionary <int, WpfMaterial> styles = new Dictionary <int, WpfMaterial>(); Dictionary <int, MeshGeometry3D> shapeGeometries = new Dictionary <int, MeshGeometry3D>(); Dictionary <int, WpfMeshGeometry3D> meshSets = new Dictionary <int, WpfMeshGeometry3D>(); Model3DGroup opaques = new Model3DGroup(); Model3DGroup transparents = new Model3DGroup(); foreach (var shapeGeom in context.ShapeGeometries()) { MeshGeometry3D wpfMesh = new MeshGeometry3D(); wpfMesh.SetValue(TagProperty, shapeGeom); //don't read the geometry into the mesh yet as we do not know where the instance is located shapeGeometries.Add(shapeGeom.ShapeLabel, wpfMesh); } foreach (var style in context.SurfaceStyles()) { WpfMaterial wpfMaterial = new WpfMaterial(); wpfMaterial.CreateMaterial(style); styles.Add(style.DefinedObjectId, wpfMaterial); WpfMeshGeometry3D mg = new WpfMeshGeometry3D(wpfMaterial, wpfMaterial); meshSets.Add(style.DefinedObjectId, mg); if (style.IsTransparent) { transparents.Children.Add(mg); } else { opaques.Children.Add(mg); } } ////if (!styles.Any()) return ; //this should always have something unless the model is empty ////double metre = model.ModelFactors.OneMetre; ////XbimMatrix3D wcsTransform = XbimMatrix3D.CreateTranslation(_modelTranslation) * XbimMatrix3D.CreateScale((float)(1 / metre)); ////foreach (var shapeInstance in context.ShapeInstances() //// .Where(s => s.RepresentationType == XbimGeometryRepresentationType.OpeningsAndAdditionsIncluded && //// !typeof(IfcFeatureElement).IsAssignableFrom(IfcMetaData.GetType(s.IfcTypeId)) && //// !typeof(IfcSpace).IsAssignableFrom(IfcMetaData.GetType(s.IfcTypeId)))) ////{ //// int styleId = shapeInstance.StyleLabel > 0 ? shapeInstance.StyleLabel : shapeInstance.IfcTypeId * -1; //// //GET THE ACTUAL GEOMETRY //// MeshGeometry3D wpfMesh; //// //see if we have already read it //// if (shapeGeometries.TryGetValue(shapeInstance.ShapeGeometryLabel, out wpfMesh)) //// { //// GeometryModel3D mg = new GeometryModel3D(wpfMesh, styles[styleId]); //// mg.SetValue(TagProperty, new XbimInstanceHandle(model, shapeInstance.IfcProductLabel, shapeInstance.IfcTypeId)); //// mg.BackMaterial = mg.Material; //// mg.Transform = XbimMatrix3D.Multiply(shapeInstance.Transformation, wcsTransform).ToMatrixTransform3D(); //// if (styles[styleId].IsTransparent) //// transparents.Children.Add(mg); //// else //// opaques.Children.Add(mg); //// } //// else //we need to get the shape geometry //// { //// XbimShapeGeometry shapeGeom = context.ShapeGeometry(shapeInstance.ShapeGeometryLabel); //// if (shapeGeom.ReferenceCount > 1) //only store if we are going to use again //// { //// wpfMesh = new MeshGeometry3D(); //// wpfMesh.Read(shapeGeom.ShapeData); //// shapeGeometries.Add(shapeInstance.ShapeGeometryLabel, wpfMesh); //// GeometryModel3D mg = new GeometryModel3D(wpfMesh, styles[styleId]); //// mg.SetValue(TagProperty, new XbimInstanceHandle(model, shapeInstance.IfcProductLabel, shapeInstance.IfcTypeId)); //// mg.BackMaterial = mg.Material; //// mg.Transform = XbimMatrix3D.Multiply(shapeInstance.Transformation, wcsTransform).ToMatrixTransform3D(); //// if (styles[styleId].IsTransparent) //// transparents.Children.Add(mg); //// else //// opaques.Children.Add(mg); //// } //// else //it is a one off, merge it with shapes of a similar material //// { //// WpfMeshGeometry3D mg = meshSets[styleId]; //// mg.Add(shapeGeom.ShapeData, //// shapeInstance.IfcTypeId, //// shapeInstance.IfcProductLabel, //// shapeInstance.InstanceLabel, //// XbimMatrix3D.Multiply(shapeInstance.Transformation, wcsTransform), 0); //// } //// } ////} if (opaques.Children.Any()) { ModelVisual3D mv = new ModelVisual3D(); mv.Content = opaques; Opaques.Children.Add(mv); if (_modelBounds.IsEmpty) { _modelBounds = mv.Content.Bounds.ToXbimRect3D(); } else { _modelBounds.Union(mv.Content.Bounds.ToXbimRect3D()); } } if (transparents.Children.Any()) { ModelVisual3D mv = new ModelVisual3D(); mv.Content = transparents; Transparents.Children.Add(mv); if (_modelBounds.IsEmpty) { _modelBounds = mv.Content.Bounds.ToXbimRect3D(); } else { _modelBounds.Union(mv.Content.Bounds.ToXbimRect3D()); } } }
private XbimShapeGeometry MeshPolyhedronBinary(IIfcTriangulatedFaceSet triangulation) { XbimShapeGeometry shapeGeometry = new XbimShapeGeometry(); shapeGeometry.Format = XbimGeometryType.PolyhedronBinary; using (var ms = new MemoryStream(0x4000)) using (var binaryWriter = new BinaryWriter(ms)) { // Prepare the header uint verticesCount = (uint)triangulation.Coordinates.CoordList.Count(); uint triangleCount = (uint)triangulation.CoordIndex.Count(); uint facesCount = 1;//at the moment just write one face for all triangles, may change to support styed faces in future shapeGeometry.BoundingBox = XbimRect3D.Empty; //Write out the header binaryWriter.Write((byte)1); //stream format version // ReSharper disable once RedundantCast //now write out the faces if (triangulation.Normals.Any()) //we have normals so obey them { List <IEnumerable <IfcPositiveInteger> > normalIndex = new List <IEnumerable <IfcPositiveInteger> >(); bool hasPnIndex = triangulation.PnIndex.Any(); if (hasPnIndex) { if (triangulation.PnIndex is List <IItemSet <IfcPositiveInteger> > ) //the list of triplets has not been flattened { foreach (var item in triangulation.PnIndex as List <IItemSet <IfcPositiveInteger> > ) { normalIndex.Add(item); } } else { for (int i = 0; i < triangulation.PnIndex.Count; i += 3) { var item = new List <IfcPositiveInteger>() { triangulation.PnIndex[i], triangulation.PnIndex[i + 1], triangulation.PnIndex[i + 2] }; normalIndex.Add(item); } } } else { foreach (var item in triangulation.CoordIndex) { normalIndex.Add(item); } } binaryWriter.Write(verticesCount); //number of vertices binaryWriter.Write(triangleCount); //number of triangles XbimRect3D bb = XbimRect3D.Empty; foreach (var coordList in triangulation.Coordinates.CoordList) { var pt = coordList.AsTriplet(); binaryWriter.Write((float)pt.A); binaryWriter.Write((float)pt.B); binaryWriter.Write((float)pt.C); var rect = new XbimRect3D(pt.A, pt.B, pt.C, 0, 0, 0); bb.Union(rect); } binaryWriter.Write(facesCount); shapeGeometry.BoundingBox = bb; Int32 numTrianglesInFace = triangulation.CoordIndex.Count(); binaryWriter.Write(-numTrianglesInFace); //not a planar face so make negative var packedNormals = new List <XbimPackedNormal>(triangulation.Normals.Count()); foreach (var normal in triangulation.Normals) { var tpl = normal.AsTriplet <IfcParameterValue>(); packedNormals.Add(new XbimPackedNormal(tpl.A, tpl.B, tpl.C)); } int triangleIndex = 0; foreach (var triangle in triangulation.CoordIndex) { var triangleTpl = triangle.AsTriplet(); var normalsIndexTpl = normalIndex[triangleIndex].AsTriplet(); WriteIndex(binaryWriter, (uint)triangleTpl.A - 1, (uint)verticesCount); packedNormals[(int)normalsIndexTpl.A - 1].Write(binaryWriter); WriteIndex(binaryWriter, (uint)triangleTpl.B - 1, (uint)verticesCount); packedNormals[(int)normalsIndexTpl.B - 1].Write(binaryWriter); WriteIndex(binaryWriter, (uint)triangleTpl.C - 1, (uint)verticesCount); packedNormals[(int)normalsIndexTpl.C - 1].Write(binaryWriter); triangleIndex++; } } else //we need to calculate normals to get a better surface fit { var triangulatedMesh = Triangulate(triangulation); shapeGeometry.BoundingBox = triangulatedMesh.BoundingBox; verticesCount = triangulatedMesh.VertexCount; triangleCount = triangulatedMesh.TriangleCount; binaryWriter.Write(verticesCount); //number of vertices binaryWriter.Write(triangleCount); //number of triangles foreach (var vert in triangulatedMesh.Vertices) { binaryWriter.Write((float)vert.X); binaryWriter.Write((float)vert.Y); binaryWriter.Write((float)vert.Z); } facesCount = (uint)triangulatedMesh.Faces.Count; binaryWriter.Write((UInt32)facesCount); foreach (var faceGroup in triangulatedMesh.Faces) { var numTrianglesInFace = faceGroup.Value.Count; //we need to fix this var planar = (ushort.MaxValue != faceGroup.Key); //we have a mesh of faces that all have the same normals at their vertices if (!planar) { numTrianglesInFace *= -1; //set flag to say multiple normals } // ReSharper disable once RedundantCast binaryWriter.Write((Int32)numTrianglesInFace); bool first = true; foreach (var triangle in faceGroup.Value) { if (planar && first) { triangle[0].PackedNormal.Write(binaryWriter); first = false; } WriteIndex(binaryWriter, (uint)triangle[0].StartVertexIndex, verticesCount); if (!planar) { triangle[0].PackedNormal.Write(binaryWriter); } WriteIndex(binaryWriter, (uint)triangle[0].NextEdge.StartVertexIndex, verticesCount); if (!planar) { triangle[0].NextEdge.PackedNormal.Write(binaryWriter); } WriteIndex(binaryWriter, (uint)triangle[0].NextEdge.NextEdge.StartVertexIndex, verticesCount); if (!planar) { triangle[0].NextEdge.NextEdge.PackedNormal.Write(binaryWriter); } } } } binaryWriter.Flush(); ((IXbimShapeGeometryData)shapeGeometry).ShapeData = ms.ToArray(); } return(shapeGeometry); }
public GeometryComparerII(XbimModel baselineModel, XbimModel revisedModel) { //Martin needs to be re-engineered for new Geometry if (baselineModel == null || revisedModel == null) { throw new ArgumentNullException(); } _baselineModel = baselineModel; _revisedModel = revisedModel; //check if all the model use the same units _meter = baselineModel.ModelFactors.OneMetre; _precision = baselineModel.ModelFactors.Precision; if (Math.Abs(revisedModel.ModelFactors.OneMetre - _meter) > 1e-9) { throw new ArgumentException("All models have to use the same length units."); } //if (Math.Abs(revisedModel.ModelFactors.Precision - _precision) > 1e-9) // throw new ArgumentException("All models have to use the same precision."); if (revisedModel.ModelFactors.Precision > _precision) { _precision = revisedModel.ModelFactors.Precision; } //create geometry context _baselineContext = new Xbim3DModelContext(_baselineModel); _revisedContext = new Xbim3DModelContext(_revisedModel); //get axis aligned BBoxes and overall world size XbimRect3D worldBB = XbimRect3D.Empty; foreach (var context in new [] { _revisedContext, _baselineContext }) { if (!context.CreateContext()) { throw new Exception("Geometry context not created."); } foreach (var shpInst in context.ShapeInstances()) { var bBox = shpInst.BoundingBox; var product = context.Model.Instances.Where <IfcProduct>(p => p.EntityLabel == shpInst.IfcProductLabel).FirstOrDefault(); if (product == null) { throw new Exception("Product not defined."); } if (context == _baselineContext) { _prodBBsA.Add(product, bBox); } else { _prodBBsB.Add(product, bBox); } //add every BBox to the world to get the size and position of the world //if it contains valid BBox if (!double.IsNaN(bBox.SizeX)) { worldBB.Union(bBox); } } } ////foreach (var model in new[] { baselineModel, revisedModel }) //Parallel.ForEach<XbimModel>(new[] { baselineModel, revisedModel }, model => //{ // //load geometry engine using local path // if (model.GeometriesCount == 0) // { // //load geometry engine if it is not loaded yet // string basePath = Path.GetDirectoryName(GetType().Assembly.Location); // AssemblyResolver.GetModelGeometryAssembly(basePath); // } // //initialize octree with all the objects // Xbim3DModelContext context = new Xbim3DModelContext(model); // context.CreateContext(); // var prodShapes = context.ProductShapes; // if (model == baselineModel) // _baselineContext = context; // else // _revisedContext = context; // //we need to preprocess all the products first to get the world size. Will keep results to avoid repetition. // foreach (var shp in prodShapes) // { // //bounding boxes are lightweight and are produced when geometry is created at first place // var bb = shp.BoundingBox; // if (shp.Product.ModelOf == baselineModel) // _prodBBsA.Add(shp.Product, bb); // else // _prodBBsB.Add(shp.Product, bb); // //add every BBox to the world to get the size and position of the world // //if it contains valid BBox // if (!float.IsNaN(bb.SizeX)) // worldBB.Union(bb); // } //} //); //create octree //target size must depend on the units of the model //size inflated with 0.5 meter so that there are not that many products on the boundary of the world var size = Math.Max(Math.Max(worldBB.SizeX, worldBB.SizeY), worldBB.SizeZ) + _meter / 2.0; var shift = (float)_meter / 4f; var position = worldBB.Location + new XbimVector3D() { X = size / 2f - shift, Y = size / 2f - shift, Z = size / 2f - shift }; _tree = new XbimOctree <IfcProduct>(size, (float)_meter, 1f, position); //add every product and its AABBox to octree foreach (var item in _prodBBsA) { _tree.Add(item.Key, item.Value); } foreach (var item in _prodBBsB) { _tree.Add(item.Key, item.Value); } }
/// <summary> /// Octree is created in the constructor. This method of spatial /// indexing should speed up spatial queries by doing simple /// computations on indexed geometries. /// </summary> /// <param name="model">Building model</param> public XbimSpatialAnalyser(XbimModel model) { _model = model; _bboxAnalyser = new XbimAABBoxAnalyser(model, _prodBBs); _semanticAnalyser = new XbimSemanticAnalyser(model); //generate geometry if there is no in the model if (model.GeometriesCount == 0) { //create geometry var m3D = new Xbim3DModelContext(model); m3D.CreateContext(true); } //initialize octree with all the objects var prods = model.Instances.OfType <IfcProduct>(); //Stopwatch sw = new Stopwatch(); //var report = new StringWriter(); //report.WriteLine("{0,-15}, {1,-40}, {2,5}, {3,5}", "Type", "Product name", "Geometry", "BBox"); //we need to preprocess all the products first to get world size. Will keep results to avoid repetition. XbimRect3D worldBB = XbimRect3D.Empty; foreach (var prod in prods) { //bounding boxes are lightweight and are produced when geometry is created at first place //sw.Start(); var geom = prod.Geometry3D(); var trans = prod.ObjectPlacement.ToMatrix3D(); //sw.Stop(); //var geomGeneration = sw.ElapsedMilliseconds; if (geom != null && geom.FirstOrDefault() != null) { //get or cast to BBox //sw.Restart(); var bb = geom.GetAxisAlignedBoundingBox(); bb = new XbimRect3D(trans.Transform(bb.Min), trans.Transform(bb.Max)); //sw.Stop(); //var gettingBbox = sw.ElapsedMilliseconds; //report.WriteLine("{0,-15}, {1,-40}, {2,5}, {3,5}", prod.GetType().Name, prod.Name, geomGeneration, gettingBbox); //add every BBox to the world to get the size and position of the world _prodBBs.Add(prod, bb); if (!double.IsNaN(bb.SizeX)) { worldBB.Union(bb); } //Debug.WriteLine("{0,-45} {1,10:F5} {2,10:F5} {3,10:F5} {4,10:F5} {5,10:F5} {6,10:F5}", // prod.Name, bb.X, bb.Y, bb.Z, bb.SizeX, bb.SizeY, bb.SizeZ); } } //Debug.WriteLine("{0,-45} {1,10:F5} {2,10:F5} {3,10:F5} {4,10:F5} {5,10:F5} {6,10:F5}", // "World", worldBB.X, worldBB.Y, worldBB.Z, worldBB.SizeX, worldBB.SizeY, worldBB.SizeZ); //create octree //target size must depend on the units of the model var meter = (float)model.ModelFactors.OneMetre; var size = Math.Max(Math.Max(worldBB.SizeX, worldBB.SizeY), worldBB.SizeZ) + meter / 2f; var shift = meter / 4f; var position = worldBB.Location + new XbimVector3D() { X = size / 2f - shift, Y = size / 2f - shift, Z = size / 2f - shift }; _tree = new XbimOctree <IfcProduct>(size, meter, 1f, position); //sw.Restart(); //add every product to the world foreach (var item in _prodBBs) { _tree.Add(item.Key, item.Value); } //sw.Stop(); //report.WriteLine("Generation of octree containing {0} products {1}", prods.Count(), sw.ElapsedMilliseconds); }
private XbimShapeGeometry MeshPolyhedronBinary(IIfcTriangulatedFaceSet triangulation) { XbimShapeGeometry shapeGeometry = new XbimShapeGeometry(); shapeGeometry.Format = XbimGeometryType.PolyhedronBinary; using (var ms = new MemoryStream(0x4000)) using (var binaryWriter = new BinaryWriter(ms)) { // Prepare the header uint verticesCount = (uint)triangulation.Coordinates.CoordList.Count(); uint triangleCount = (uint)triangulation.CoordIndex.Count(); uint facesCount = 1;//at the moment just write one face for all triangles, may change to support styed faces in future shapeGeometry.BoundingBox = XbimRect3D.Empty; //Write out the header binaryWriter.Write((byte)1); //stream format version // ReSharper disable once RedundantCast //now write out the faces if (triangulation.Normals.Any()) //we have normals so obey them { List <IEnumerable <IfcPositiveInteger> > normalIndex = new List <IEnumerable <IfcPositiveInteger> >(); bool hasPnIndex = triangulation.PnIndex.Any(); if (hasPnIndex) { if (triangulation.PnIndex is List <IItemSet <IfcPositiveInteger> > ) //the list of triplets has not been flattened { foreach (var item in triangulation.PnIndex as List <IItemSet <IfcPositiveInteger> > ) { normalIndex.Add(item); } } else { for (int i = 0; i < triangulation.PnIndex.Count; i += 3) { var item = new List <IfcPositiveInteger>() { triangulation.PnIndex[i], triangulation.PnIndex[i + 1], triangulation.PnIndex[i + 2] }; normalIndex.Add(item); } } } else { foreach (var item in triangulation.CoordIndex) { normalIndex.Add(item); } } binaryWriter.Write(verticesCount); //number of vertices binaryWriter.Write(triangleCount); //number of triangles XbimRect3D bb = XbimRect3D.Empty; // use first point as a local origin for large coordinates. It doesn't matter if // we use min, max or centroid for this. var origin = triangulation.Coordinates?.CoordList.FirstOrDefault()?.AsTriplet() ?? new XbimTriplet <IfcLengthMeasure>(); var isLarge = IsLarge(origin.A) || IsLarge(origin.B) || IsLarge(origin.C); if (isLarge) { shapeGeometry.LocalShapeDisplacement = new XbimVector3D(origin.A, origin.B, origin.C); } var points = isLarge ? triangulation.Coordinates.CoordList.Select(c => c.AsTriplet()).Select(t => new XbimTriplet <IfcLengthMeasure> { A = t.A - origin.A, B = t.B - origin.B, C = t.C - origin.C }) : triangulation.Coordinates.CoordList.Select(c => c.AsTriplet()); foreach (var pt in points) { binaryWriter.Write((float)pt.A); binaryWriter.Write((float)pt.B); binaryWriter.Write((float)pt.C); var rect = new XbimRect3D(pt.A, pt.B, pt.C, 0, 0, 0); bb.Union(rect); } binaryWriter.Write(facesCount); shapeGeometry.BoundingBox = bb; Int32 numTrianglesInFace = triangulation.CoordIndex.Count(); binaryWriter.Write(-numTrianglesInFace); //not a planar face so make negative var packedNormals = new List <XbimPackedNormal>(triangulation.Normals.Count()); foreach (var normal in triangulation.Normals) { var tpl = normal.AsTriplet <IfcParameterValue>(); packedNormals.Add(new XbimPackedNormal(tpl.A, tpl.B, tpl.C)); } int triangleIndex = 0; foreach (var triangle in triangulation.CoordIndex) { var triangleTpl = triangle.AsTriplet(); var normalsIndexTpl = normalIndex[triangleIndex].AsTriplet(); WriteIndex(binaryWriter, (uint)triangleTpl.A - 1, (uint)verticesCount); packedNormals[(int)normalsIndexTpl.A - 1].Write(binaryWriter); WriteIndex(binaryWriter, (uint)triangleTpl.B - 1, (uint)verticesCount); packedNormals[(int)normalsIndexTpl.B - 1].Write(binaryWriter); WriteIndex(binaryWriter, (uint)triangleTpl.C - 1, (uint)verticesCount); packedNormals[(int)normalsIndexTpl.C - 1].Write(binaryWriter); triangleIndex++; } } else //we need to calculate normals to get a better surface fit { var triangulatedMesh = Triangulate(triangulation); shapeGeometry.BoundingBox = triangulatedMesh.BoundingBox; verticesCount = triangulatedMesh.VertexCount; triangleCount = triangulatedMesh.TriangleCount; binaryWriter.Write(verticesCount); //number of vertices binaryWriter.Write(triangleCount); //number of triangles // use minimum bbox as a local origin var origin = triangulatedMesh.BoundingBox.Min; var isLarge = IsLarge(origin.X) || IsLarge(origin.Y) || IsLarge(origin.Z); var vertices = isLarge ? triangulatedMesh.Vertices.Select(v => new Vec3(v.X - origin.X, v.Y - origin.Y, v.Z - origin.Z)) : triangulatedMesh.Vertices; foreach (var vert in vertices) { binaryWriter.Write((float)vert.X); binaryWriter.Write((float)vert.Y); binaryWriter.Write((float)vert.Z); } if (isLarge) { var bb = triangulatedMesh.BoundingBox; shapeGeometry.BoundingBox = new XbimRect3D(bb.X - origin.X, bb.Y = origin.Y, bb.Z - origin.Z, bb.SizeX, bb.SizeY, bb.SizeZ); shapeGeometry.LocalShapeDisplacement = new XbimVector3D(origin.X, origin.Y, origin.Z); } facesCount = (uint)triangulatedMesh.Faces.Count; binaryWriter.Write((UInt32)facesCount); foreach (var faceGroup in triangulatedMesh.Faces) { var numTrianglesInFace = faceGroup.Value.Count; //we need to fix this var planar = (ushort.MaxValue != faceGroup.Key); //we have a mesh of faces that all have the same normals at their vertices if (!planar) { numTrianglesInFace *= -1; //set flag to say multiple normals } // ReSharper disable once RedundantCast binaryWriter.Write((Int32)numTrianglesInFace); bool first = true; foreach (var triangle in faceGroup.Value) { if (planar && first) { triangle[0].PackedNormal.Write(binaryWriter); first = false; } WriteIndex(binaryWriter, (uint)triangle[0].StartVertexIndex, verticesCount); if (!planar) { triangle[0].PackedNormal.Write(binaryWriter); } WriteIndex(binaryWriter, (uint)triangle[0].NextEdge.StartVertexIndex, verticesCount); if (!planar) { triangle[0].NextEdge.PackedNormal.Write(binaryWriter); } WriteIndex(binaryWriter, (uint)triangle[0].NextEdge.NextEdge.StartVertexIndex, verticesCount); if (!planar) { triangle[0].NextEdge.NextEdge.PackedNormal.Write(binaryWriter); } } } } binaryWriter.Flush(); ((IXbimShapeGeometryData)shapeGeometry).ShapeData = ms.ToArray(); } return(shapeGeometry); }
public IfcElementSignature(IfcElement elem, Xbim3DModelContext geometryContext) { XbimMatrix3D m3D = XbimMatrix3D.Identity; if (elem.ObjectPlacement != null) { m3D = elem.ObjectPlacement.ToMatrix3D(); } var geomManager = elem.ModelOf.GeometryManager; ShapeId = 0; //get the 3D shape var shapes = geometryContext.ShapeInstancesOf(elem); if (shapes.Any()) { XbimRect3D r3D = XbimRect3D.Empty; foreach (var shape in shapes) { if (r3D.IsEmpty) { r3D = shape.BoundingBox; } else { r3D.Union(shape.BoundingBox); } } XbimPoint3D p3D = r3D.Centroid(); p3D = m3D.Transform(p3D); BoundingSphereRadius = r3D.Length() / 2; CentroidX = p3D.X; CentroidY = p3D.Y; CentroidZ = p3D.Z; } //get the defining type IfcTypeObject ot = elem.GetDefiningType(); IfcMaterialSelect material = elem.GetMaterial(); //sort out property definitions List <IfcPropertySet> psets = elem.GetAllPropertySets(); PropertyCount = psets.SelectMany(p => p.HasProperties).Count(); psets.Sort(new PropertySetNameComparer()); foreach (var pset in psets) { PropertySetNamesKey ^= pset.Name.GetHashCode(); } List <IfcPropertySingleValue> props = psets.SelectMany(p => p.HasProperties).OfType <IfcPropertySingleValue>().ToList(); props.Sort(new PropertySingleValueNameComparer()); foreach (var prop in props) { PropertyNamesKey ^= prop.Name.GetHashCode(); } props.Sort(new PropertySingleValueValueComparer()); foreach (var prop in props) { PropertyValuesKey ^= prop.NominalValue.GetHashCode(); } ModelID = elem.EntityLabel; SchemaType = elem.GetType().Name; DefinedTypeId = (ot == null ? "" : ot.GlobalId.ToPart21); GlobalId = elem.GlobalId; OwningUser = elem.OwnerHistory.LastModifyingUser != null?elem.OwnerHistory.LastModifyingUser.ToString() : elem.OwnerHistory.OwningUser.ToString(); Name = elem.Name ?? ""; Description = elem.Description ?? ""; HasAssignmentsKey = elem.HasAssignments.Count(); IsDecomposedByKey = elem.IsDecomposedBy.Count(); DecomposesKey = elem.Decomposes.Count(); HasAssociationsKey = elem.HasAssociations.Count(); ObjectType = elem.ObjectType ?? ""; MaterialName = material == null ? "" : material.Name; ReferencedByKey = elem.ReferencedBy.Count(); Tag = elem.Tag ?? ""; HasStructuralMemberKey = elem.HasStructuralMember.Count(); FillsVoidsKey = elem.FillsVoids.Count(); ConnectedToKey = elem.ConnectedTo.Count(); HasCoveringsKey = elem.HasCoverings.Count(); HasProjectionsKey = elem.HasProjections.Count(); ReferencedInStructuresKey = elem.ReferencedInStructures.Count(); HasPortsKey = elem.HasPorts.Count(); HasOpeningsKey = elem.HasOpenings.Count(); IsConnectionRealizationKey = elem.IsConnectionRealization.Count(); ProvidesBoundariesKey = elem.ProvidesBoundaries.Count(); ConnectedFromKey = elem.ConnectedFrom.Count(); ContainedInStructureKey = elem.ContainedInStructure.Count(); }