예제 #1
0
        private IEnumerable <IfcProduct> GetCandidatesFromNode(IfcProduct original, XbimOctree <IfcProduct> node)
        {
            if (original != null && node != null)
            {
                //content which if from other models
                var nodeContent = node.Content().Where(nc => (nc.ModelOf != original.ModelOf) && (nc.GetType() == original.GetType()));
                var prodBBox    = XbimRect3D.Empty;

                foreach (var candidate in nodeContent)
                {
                    //check BBoxes for equality
                    var contBBox = _prodBBsB[candidate];
                    prodBBox = _prodBBsA[original];
                    if (XbimAABBoxAnalyser.AlmostEqual(contBBox, prodBBox, _precision))
                    {
                        if (!_processedFromB.Contains(candidate))
                        {
                            _processedFromB.Add(candidate);
                        }
                        yield return(candidate);
                    }

                    //cope with the situation when product's bbox is on the border and
                    //it's equivalent from the second model might have end up on the higher level
                    var borderDirections = BBoxBorderDirections(node.Bounds, prodBBox);
                    var parents          = GetParentsInDirections(borderDirections, node);
                    foreach (var parent in parents)
                    {
                        foreach (var item in GetCandidatesFromNode(original, parent))//recursion
                        {
                            if (!_processedFromB.Contains(candidate))
                            {
                                _processedFromB.Add(candidate);
                            }
                            yield return(candidate);
                        }
                    }
                }
            }
        }
        /// <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);
        }