Esempio n. 1
0
        /// <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);
        }
Esempio n. 2
0
        /// <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);
            }
        }
Esempio n. 3
0
        /// <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());
        }
Esempio n. 4
0
        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)
                );
        }
Esempio n. 5
0
        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);
        }
Esempio n. 6
0
        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);
        }
Esempio n. 8
0
        /// <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);
        }
Esempio n. 9
0
        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);
        }
Esempio n. 10
0
        /// <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);
        }
Esempio n. 11
0
 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);
        }
Esempio n. 15
0
        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);
        }
Esempio n. 17
0
        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();
        }