예제 #1
0
        /// <summary>
        /// Allocate each geometry into appropriate tile
        /// </summary>
        /// <param name="geometries">Dictionary that contains geometries</param>
        /// <param name="tiles">Dictionary that contains tiles</param>
        /// <param name="maxElementPerTile">Maximum number of elements in each tile</param>
        public static void AllocateGeometryToTile(ref Dictionary <string, GeometryStore> geometries, ref Dictionary <XbimRect3D, List <GeometryStore> > tiles, int maxElementPerTile)
        {
            // allocate element to appropriate tile according to intersect volume
            foreach (GeometryStore gs in geometries.Values)
            {
                XbimRect3D candicateTile   = XbimRect3D.Empty;
                double     intersectVolume = double.MinValue;
                foreach (XbimRect3D tile in tiles.Keys)
                {
                    double volume = GeometryStore.Intersect(gs.BoundBox, tile);
                    if (volume > intersectVolume)
                    {
                        candicateTile   = tile;
                        intersectVolume = volume;
                    }
                }
                if (!candicateTile.Equals(XbimRect3D.Empty))
                {
                    tiles[candicateTile].Add(gs);
                }
            }

            foreach (XbimRect3D bbox in tiles.Keys.ToList())
            {
                // remove empty tile
                if (tiles[bbox].Count == 0)
                {
                    tiles.Remove(bbox);
                }
                else if (tiles[bbox].Count > maxElementPerTile && bbox.SizeX > 1 && bbox.SizeY > 1 && bbox.SizeZ > 1) // retile a tile(tile size should be large than 1)
                {
                    Dictionary <XbimRect3D, List <GeometryStore> > subTiles = new Dictionary <XbimRect3D, List <GeometryStore> >();
                    SplitBoundingBox(bbox, ref subTiles, bbox.SizeX / 2.0, bbox.SizeY / 2.0, bbox.SizeZ / 2.0);

                    Dictionary <string, GeometryStore> elements = new Dictionary <string, GeometryStore>();
                    foreach (GeometryStore gs in tiles[bbox])
                    {
                        elements.Add(gs.GlobalId, gs);
                    }
                    AllocateGeometryToTile(ref elements, ref subTiles, maxElementPerTile);

                    tiles.Remove(bbox);
                    foreach (XbimRect3D subBbox in subTiles.Keys)
                    {
                        tiles.Add(subBbox, subTiles[subBbox]);
                    }
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Extract Geometries from IFC file.
        /// </summary>
        /// <param name="model">IfcStore model.</param>
        /// <param name="geometries">Geometries data.</param>
        /// <param name="modelBoundingBox">Bounding box of the ifc model.</param>
        public static void ExtractGeometries(IfcStore model, ref Dictionary <string, GeometryStore> geometries, ref XbimRect3D modelBoundingBox)
        {
            // context is used to extract geometry data
            var context = new Xbim3DModelContext(model);
            var meter   = context.Model.ModelFactors.OneMeter;

            context.CreateContext();

            // start to extract geometry data
            var           instances = context.ShapeInstances();
            XbimColourMap colorMap  = new XbimColourMap();

            foreach (var instance in instances) // each instance is a mesh
            {
                MeshStore meshStore = new MeshStore();

                // get the color of this mesh
                var        ss    = model.Instances[instance.StyleLabel] as IIfcSurfaceStyle;
                XbimColour color = XbimColour.DefaultColour;
                if (ss != null)
                {
                    var texture = XbimTexture.Create(ss);
                    color = texture.ColourMap.FirstOrDefault();
                }
                else
                {
                    var styleId = instance.StyleLabel > 0 ? instance.StyleLabel : instance.IfcTypeId;
                    var theType = model.Metadata.GetType((short)styleId);
                    color = colorMap[theType.Name];
                }

                meshStore.Color = string.Format("{0},{1},{2},{3}", (int)(color.Red * 255), (int)(color.Green * 255), (int)(color.Blue * 255), color.Alpha * 255);

                var geometry = context.ShapeGeometry(instance);
                var data     = (geometry as IXbimShapeGeometryData).ShapeData;

                // multiple geometry may belong to one product, like frame and glass belong to a ifcwindow
                var product = model.Instances[instance.IfcProductLabel] as IIfcProduct;

                if (!geometries.ContainsKey(product.GlobalId))
                {
                    geometries.Add(product.GlobalId, new GeometryStore(product.GlobalId, product.Name));
                }
                var geometryStore = geometries[product.GlobalId];

                // reading the real geometry data
                using (var stream = new MemoryStream(data))
                {
                    using (var reader = new BinaryReader(stream))
                    {
                        // triangle the instance and transform it to the correct position
                        var mesh = reader.ReadShapeTriangulation();
                        mesh = mesh.Transform(instance.Transformation);

                        // geometry data
                        var verticesData = new List <double>();
                        var normalsData  = new List <double>();
                        var indexesData  = new List <int>();

                        // bouding box for instance.
                        double minX = double.MaxValue, minY = double.MaxValue, minZ = double.MaxValue,
                               maxX = double.MinValue, maxY = double.MinValue, maxZ = double.MinValue;

                        var faces = mesh.Faces as List <XbimFaceTriangulation>;
                        foreach (var face in faces)
                        {
                            foreach (var indice in face.Indices)
                            {
                                indexesData.Add(indice);
                            }
                            foreach (var normal in face.Normals)
                            {
                                normalsData.Add(normal.Normal.X);
                                normalsData.Add(normal.Normal.Y);
                                normalsData.Add(normal.Normal.Z);
                            }
                        }
                        var vertices = mesh.Vertices as List <XbimPoint3D>;
                        foreach (var point in vertices)
                        {
                            double x = point.X / meter, y = point.Y / meter, z = point.Z / meter;
                            verticesData.Add(x); // convert to meter
                            verticesData.Add(y);
                            verticesData.Add(z);

                            // update bounding box
                            minX = Math.Min(minX, x);
                            minY = Math.Min(minY, y);
                            minZ = Math.Min(minZ, z);
                            maxX = Math.Max(maxX, x);
                            maxY = Math.Max(maxY, y);
                            maxZ = Math.Max(maxZ, z);
                        }

                        if (minX == double.MaxValue || minY == double.MaxValue || minZ == double.MaxValue ||
                            maxX == double.MinValue || maxY == double.MinValue || maxZ == double.MinValue)
                        {
                            throw new Exception("Invalid Boundingbox");
                        }

                        // do not trust instance.BoundingBox, it seems to be wrong.
                        XbimRect3D bbox = new XbimRect3D(minX, minY, minZ, maxX - minX, maxY - minY, maxZ - minZ);

                        // update boundingbox of current geometryStore
                        geometryStore.BoundBox = GeometryStore.Union(geometryStore.BoundBox, bbox);

                        // update boundingbox of ifc model
                        modelBoundingBox = GeometryStore.Union(modelBoundingBox, bbox);

                        meshStore.Vertexes = verticesData;
                        meshStore.Normals  = normalsData;
                        meshStore.Indexes  = indexesData;
                    }
                }
                geometryStore.Meshes.Add(meshStore);
            }
        }