Пример #1
0
        /// <summary>
        /// Use this function on a Xbim Model that has just been creted from IFC content
        /// This will create the default 3D mesh geometry for all IfcProducts and add it to the model
        /// </summary>
        /// <param name="model"></param>
        public static void GenerateGeometry(XbimModel model, ILogger Logger = null, ReportProgressDelegate progDelegate = null, IEnumerable<IfcProduct> toMesh = null)
        {
            //Create the geometry engine by reflection to allow dynamic loading of different binary platforms (32, 64 etc)
            Assembly assembly = AssemblyResolver.GetModelGeometryAssembly();
            if (assembly == null)
            {
                if (Logger != null)
                {
#if DEBUG
                    Logger.Error("Failed to load Xbim.ModelGeometry.OCCd.dll Please ensure it is installed correctly");
#else
                    Logger.Error("Failed to load Xbim.ModelGeometry.OCC.dll Please ensure it is installed correctly");
#endif
                }
                return;
            }
            IXbimGeometryEngine engine = (IXbimGeometryEngine)assembly.CreateInstance("Xbim.ModelGeometry.XbimGeometryEngine");
            engine.Init(model);
            if (engine == null)
            {
                if (Logger != null)
                {                   
#if DEBUG
                    Logger.Error("Failed to create Xbim Geometry engine. Please ensure Xbim.ModelGeometry.OCCd.dll is installed correctly");
#else
                    Logger.Error("Failed to create Xbim Geometry engine. Please ensure Xbim.ModelGeometry.OCC.dll is installed correctly");
#endif
                }
                return;
            }
           
            //now convert the geometry
            IEnumerable<IfcProduct> toDraw;
            if (toMesh != null)
                toDraw = toMesh;
            else
                toDraw = model.InstancesLocal.OfType<IfcProduct>().Where(t => !(t is IfcFeatureElement));
            //List<IfcProduct> toDraw = new List<IfcProduct>();
            //  toDraw.Add(model.Instances[513489] as IfcProduct);
            if (!toDraw.Any()) return; //othing to do
            TransformGraph graph = new TransformGraph(model);
            //create a new dictionary to hold maps
            ConcurrentDictionary<int, Object> maps = new ConcurrentDictionary<int, Object>();
            //add everything that may have a representation
            graph.AddProducts(toDraw); //load the products as we will be accessing their geometry

            ConcurrentDictionary<int, MapData> mappedModels = new ConcurrentDictionary<int, MapData>();
            ConcurrentQueue<MapRefData> mapRefs = new ConcurrentQueue<MapRefData>();
            ConcurrentDictionary<int, int[]> written = new ConcurrentDictionary<int, int[]>();

            int tally = 0;
            int percentageParsed = 0;
            int total = graph.ProductNodes.Values.Count;

            try
            {
                //use parallel as this improves the OCC geometry generation greatly
                ParallelOptions opts = new ParallelOptions();
                opts.MaxDegreeOfParallelism = 16;
                XbimRect3D bounds = XbimRect3D.Empty;
                double deflection =  model.ModelFactors.DeflectionTolerance;
#if DOPARALLEL
                Parallel.ForEach<TransformNode>(graph.ProductNodes.Values, opts, node => //go over every node that represents a product
#else
                foreach (var node in graph.ProductNodes.Values)
#endif
                {
                    IfcProduct product = node.Product(model);

                    try
                    {
                        IXbimGeometryModel geomModel = engine.GetGeometry3D(product, maps);
                        if (geomModel != null)  //it has geometry
                        {
                            XbimMatrix3D m3d = node.WorldMatrix();
                            
                            if (geomModel.IsMap) //do not process maps now
                            {
                                MapData toAdd = new MapData(geomModel, m3d, product);
                                if (!mappedModels.TryAdd(geomModel.RepresentationLabel, toAdd)) //get unique rep
                                    mapRefs.Enqueue(new MapRefData(toAdd)); //add ref
                            }
                            else
                            {
                                int[] geomIds;
                                XbimGeometryCursor geomTable = model.GetGeometryTable();

                                XbimLazyDBTransaction transaction = geomTable.BeginLazyTransaction();
                                if (written.TryGetValue(geomModel.RepresentationLabel, out geomIds))
                                {
                                    byte[] matrix = m3d.ToArray(true);
                                    short? typeId = IfcMetaData.IfcTypeId(product);
                                    foreach (var geomId in geomIds)
                                    {
                                        geomTable.AddMapGeometry(geomId, product.EntityLabel, typeId.Value, matrix, geomModel.SurfaceStyleLabel);
                                    }
                                }
                                else
                                {
                                    XbimTriangulatedModelCollection tm = geomModel.Mesh(deflection);
                                    XbimRect3D bb = tm.Bounds;

                                    byte[] matrix = m3d.ToArray(true);
                                    short? typeId = IfcMetaData.IfcTypeId(product);

                                    geomIds = new int[tm.Count + 1];
                                    geomIds[0] = geomTable.AddGeometry(product.EntityLabel, XbimGeometryType.BoundingBox, typeId.Value, matrix, bb.ToDoublesArray(), 0, geomModel.SurfaceStyleLabel);
                                    bb = XbimRect3D.TransformBy(bb, m3d);
                                    if (bounds.IsEmpty)
                                        bounds = bb;
                                    else
                                        bounds.Union(bb);
                                    short subPart = 0;
                                    foreach (XbimTriangulatedModel b in tm)
                                    {
                                        geomIds[subPart + 1] = geomTable.AddGeometry(product.EntityLabel, XbimGeometryType.TriangulatedMesh, typeId.Value, matrix, b.Triangles, subPart, b.SurfaceStyleLabel);
                                        subPart++;
                                    }

                                    //            Debug.Assert(written.TryAdd(geomModel.RepresentationLabel, geomIds));
                                    Interlocked.Increment(ref tally);
                                    if (progDelegate != null)
                                    {
                                        int newPercentage = Convert.ToInt32((double)tally / total * 100.0);
                                        if (newPercentage > percentageParsed)
                                        {
                                            percentageParsed = newPercentage;
                                            progDelegate(percentageParsed, "Meshing");
                                        }
                                    }
                                }
                                transaction.Commit();
                                model.FreeTable(geomTable);

                            }
                        }
                        else
                        {
                            // store a transform only if no geomtery is available
                            XbimGeometryCursor geomTable = model.GetGeometryTable();
                            XbimLazyDBTransaction transaction = geomTable.BeginLazyTransaction();
                            XbimMatrix3D m3dtemp = node.WorldMatrix();
                            byte[] matrix = m3dtemp.ToArray(true);
                            short? typeId = IfcMetaData.IfcTypeId(product);
                            geomTable.AddGeometry(product.EntityLabel, XbimGeometryType.TransformOnly, typeId.Value, matrix, new byte[] {});
                            transaction.Commit();
                            model.FreeTable(geomTable);

                            Interlocked.Increment(ref tally);
                            if (progDelegate != null)
                            {
                                int newPercentage = Convert.ToInt32((double)tally / total * 100.0);
                                if (newPercentage > percentageParsed)
                                {
                                    percentageParsed = newPercentage;
                                    progDelegate(percentageParsed, "Meshing");
                        }
                    }
                        }
                    }
                    catch (Exception e1)
                    {
                        String message = String.Format("Error Triangulating product geometry of entity #{0} - {1}",
                            product.EntityLabel,
                            product.GetType().Name
                            );
                        if (Logger != null) Logger.Error(message, e1);
                    }
                }
#if DOPARALLEL
                );
#endif
                graph = null;

                // Debug.WriteLine(tally);
#if DOPARALLEL
                //now sort out maps again in parallel
                Parallel.ForEach<KeyValuePair<int, MapData>>(mappedModels, opts, map =>
#else
                foreach (var map in mappedModels)
#endif
                {
                    IXbimGeometryModel geomModel = map.Value.Geometry;
                    XbimMatrix3D m3d = map.Value.Matrix;
                    IfcProduct product = map.Value.Product;

                    //have we already written it?
                    int[] writtenGeomids = new int[0];
                    if (!written.TryAdd(geomModel.RepresentationLabel, writtenGeomids))
                    {
                        //make maps    
                        mapRefs.Enqueue(new MapRefData(map.Value)); //add ref
                    }
                    else
                    {
                        m3d = XbimMatrix3D.Multiply(geomModel.Transform, m3d);
                        WriteGeometry(model, written, geomModel, ref bounds, m3d, product, deflection);

                    }

                    Interlocked.Increment(ref tally);
                    if (progDelegate != null)
                    {
                        int newPercentage = Convert.ToInt32((double)tally / total * 100.0);
                        if (newPercentage > percentageParsed)
                        {
                            percentageParsed = newPercentage;
                            progDelegate(percentageParsed, "Meshing");
                        }
                    }
                    map.Value.Clear(); //release any native memory we are finished with this
                }
#if DOPARALLEL
                );
#endif
                //clear up maps
                mappedModels.Clear();
                XbimGeometryCursor geomMapTable = model.GetGeometryTable();
                XbimLazyDBTransaction mapTrans = geomMapTable.BeginLazyTransaction();
                foreach (var map in mapRefs) //don't do this in parallel to avoid database thrashing as it is very fast
                {

                    int[] geomIds;
                    if (!written.TryGetValue(map.RepresentationLabel, out geomIds))
                    {
                        if (Logger != null) Logger.WarnFormat("A geometry mapped reference (#{0}) has been found that has no base geometry", map.RepresentationLabel);
                    }
                    else
                    {

                        byte[] matrix = map.Matrix.ToArray(true);
                        foreach (var geomId in geomIds)
                        {
                            geomMapTable.AddMapGeometry(geomId, map.EntityLabel, map.EntityTypeId, matrix, map.SurfaceStyleLabel);
                        }
                        mapTrans.Commit();
                        mapTrans.Begin();

                    }
                    Interlocked.Increment(ref tally);
                    if (progDelegate != null)
                    {
                        int newPercentage = Convert.ToInt32((double)tally / total * 100.0);
                        if (newPercentage > percentageParsed)
                        {
                            percentageParsed = newPercentage;
                            progDelegate(percentageParsed, "Meshing");
                        }
                    }
                    if (tally % 100 == 100)
                    {
                        mapTrans.Commit();
                        mapTrans.Begin();
                    }

                }
                mapTrans.Commit();

                // Store model regions in the database.
                // all regions are stored for the project in one row and need to be desirialised to XbimRegionCollection before being enumerated on read.
                //
                // todo: bonghi: currently geometry labels of partitioned models are not stored, only their bounding box and count are.
                //
                mapTrans.Begin();
                XbimRegionCollection regions = PartitionWorld(model, bounds);
                IfcProject project = model.IfcProject;
                int projectId = 0;
                if (project != null)
                    projectId = Math.Abs(project.EntityLabel);
                geomMapTable.AddGeometry(projectId, XbimGeometryType.Region, IfcMetaData.IfcTypeId(typeof(IfcProject)), XbimMatrix3D.Identity.ToArray(), regions.ToArray());
                mapTrans.Commit();


                model.FreeTable(geomMapTable);
                if (progDelegate != null)
                {
                    progDelegate(0, "Ready");
                }
            }
            catch (Exception e2)
            {
                if (Logger != null) Logger.Warn("General Error Triangulating geometry", e2);
            }
            finally
            {

            }
        }
Пример #2
0
        private static void WriteGeometry(XbimModel model, ConcurrentDictionary<int, int[]> written, IXbimGeometryModel geomModel, ref XbimRect3D bounds, XbimMatrix3D m3d, IfcProduct product, double deflection)
        {
            XbimTriangulatedModelCollection tm = geomModel.Mesh(deflection);
            XbimRect3D bb = tm.Bounds;
            byte[] matrix = m3d.ToArray(true);
            short? typeId = IfcMetaData.IfcTypeId(product);
            XbimGeometryCursor geomTable = model.GetGeometryTable();

            XbimLazyDBTransaction transaction = geomTable.BeginLazyTransaction();
            int[] geomIds = new int[tm.Count + 1];
            geomIds[0] = geomTable.AddGeometry(product.EntityLabel, XbimGeometryType.BoundingBox, typeId.Value, matrix, bb.ToDoublesArray(), 0, geomModel.SurfaceStyleLabel);

            bb = XbimRect3D.TransformBy(bb, m3d);

            if (bounds.IsEmpty)
                bounds = bb;
            else
                bounds.Union(bb);
            short subPart = 0;
            foreach (XbimTriangulatedModel b in tm)
            {
                geomIds[subPart + 1] = geomTable.AddGeometry(product.EntityLabel, XbimGeometryType.TriangulatedMesh, typeId.Value, matrix, b.Triangles, subPart, b.SurfaceStyleLabel);
                subPart++;
            }
            transaction.Commit();
            written.AddOrUpdate(geomModel.RepresentationLabel, geomIds, (k, v) => v = geomIds);
            model.FreeTable(geomTable);
        }