/// <summary>
        /// Returns an array of objects that intersect with the specified bounds, if any. Otherwise returns an empty array. See also: IsColliding.
        /// </summary>
        /// <param name="checkBounds">Bounds to check. Passing by ref as it improve performance with structs.</param>
        /// <param name="result">List result.</param>
        /// <returns>Objects that intersect with the specified bounds.</returns>
        public void GetColliding(ref HLBoundingBoxXYZ checkBounds, List <T> result, Filter <T> flt)
        {
            // Are the input bounds at least partially in this node?
            if (!bounds.Intersects(checkBounds))
            {
                return;
            }

            // Check against any objects in this node
            for (int i = 0; i < objects.Count; i++)
            {
                if (objects[i].Bounds.Intersects(checkBounds))
                {
                    result.Add(objects[i].Obj);
                }
            }

            // Check children
            if (children != null)
            {
                for (int i = 0; i < 8; i++)
                {
                    children[i].GetColliding(ref checkBounds, result, flt);
                }
            }
        }
        /*
         * /// <summary>
         * /// Get the total amount of objects in this node and all its children, grandchildren etc. Useful for debugging.
         * /// </summary>
         * /// <param name="startingNum">Used by recursive calls to add to the previous total.</param>
         * /// <returns>Total objects in this node and its children, grandchildren etc.</returns>
         * public int GetTotalObjects(int startingNum = 0) {
         *  int totalObjects = startingNum + objects.Count;
         *  if (children != null) {
         *      for (int i = 0; i < 8; i++) {
         *          totalObjects += children[i].GetTotalObjects();
         *      }
         *  }
         *  return totalObjects;
         * }
         */

        // #### PRIVATE METHODS ####

        /// <summary>
        /// Set values for this node.
        /// </summary>
        /// <param name="baseLengthVal">Length of this node, not taking looseness into account.</param>
        /// <param name="minSizeVal">Minimum size of nodes in this octree.</param>
        /// <param name="loosenessVal">Multiplier for baseLengthVal to get the actual size.</param>
        /// <param name="centerVal">Centre position of this node.</param>
        void SetValues(float baseLengthVal, float minSizeVal, float loosenessVal, XYZ centerVal)
        {
            BaseLength = baseLengthVal;
            minSize    = minSizeVal;
            looseness  = loosenessVal;
            Center     = centerVal;
            adjLength  = looseness * baseLengthVal;

            // Create the bounding box.
            var size = new XYZ(adjLength, adjLength, adjLength);

            bounds = new HLBoundingBoxXYZ(Center, size);

            float quarter           = BaseLength / 4f;
            float childActualLength = (BaseLength / 2) * looseness;
            var   childActualSize   = new XYZ(childActualLength, childActualLength, childActualLength);

            childBounds    = new HLBoundingBoxXYZ[8];
            childBounds[0] = new HLBoundingBoxXYZ(Center + new XYZ(-quarter, quarter, -quarter), childActualSize);
            childBounds[1] = new HLBoundingBoxXYZ(Center + new XYZ(quarter, quarter, -quarter), childActualSize);
            childBounds[2] = new HLBoundingBoxXYZ(Center + new XYZ(-quarter, quarter, quarter), childActualSize);
            childBounds[3] = new HLBoundingBoxXYZ(Center + new XYZ(quarter, quarter, quarter), childActualSize);
            childBounds[4] = new HLBoundingBoxXYZ(Center + new XYZ(-quarter, -quarter, -quarter), childActualSize);
            childBounds[5] = new HLBoundingBoxXYZ(Center + new XYZ(quarter, -quarter, -quarter), childActualSize);
            childBounds[6] = new HLBoundingBoxXYZ(Center + new XYZ(-quarter, -quarter, quarter), childActualSize);
            childBounds[7] = new HLBoundingBoxXYZ(Center + new XYZ(quarter, -quarter, quarter), childActualSize);
        }
        /// <summary>
        /// Check if the specified bounds intersect with anything in the tree. See also: GetColliding.
        /// </summary>
        /// <param name="checkBounds">Bounds to check.</param>
        /// <returns>True if there was a collision.</returns>
        public bool IsColliding(ref HLBoundingBoxXYZ checkBounds, Filter <T> flt)
        {
            // Are the input bounds at least partially in this node?
            if (!GeoUtils.DoBoxesIntersect(bounds, checkBounds, 0))
            {
                return(false);
            }

            // Check against any objects in this node
            for (int i = 0; i < objects.Count; i++)
            {
                var obj = objects[i];
                if ((flt == null || flt.Invoke(obj.Obj)) && GeoUtils.DoBoxesIntersect(objects[i].Bounds, checkBounds, 0))
                {
                    return(true);
                }
            }

            // Check children
            if (children != null)
            {
                for (int i = 0; i < 8; i++)
                {
                    if (children[i].IsColliding(ref checkBounds, flt))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
        /// <summary>
        /// Private counterpart to the public Add method.
        /// </summary>
        /// <param name="obj">Object to add.</param>
        /// <param name="objBounds">3D bounding box around the object.</param>
        void SubAdd(T obj, HLBoundingBoxXYZ objBounds)
        {
            // We know it fits at this level if we've got this far
            // Just add if few objects are here, or children would be below min size
            if (objects.Count < numObjectsAllowed || (BaseLength / 2) < minSize)
            {
                OctreeObject newObj = new OctreeObject {
                    Obj = obj, Bounds = objBounds
                };
                //Debug.Log("ADD " + obj.name + " to depth " + depth);
                objects.Add(newObj);
            }
            else
            {
                // Fits at this level, but we can go deeper. Would it fit there?

                // Create the 8 children
                int bestFitChild;
                if (children == null)
                {
                    Split();
                    if (children == null)
                    {
                        // Debug.Log("Child creation failed for an unknown reason. Early exit.");
                        return;
                    }

                    // Now that we have the new children, see if this node's existing objects would fit there
                    for (int i = objects.Count - 1; i >= 0; i--)
                    {
                        OctreeObject existingObj = objects[i];
                        // Find which child the object is closest to based on where the
                        // object's center is located in relation to the octree's center.
                        bestFitChild = BestFitChild(existingObj.Bounds);
                        // Does it fit?
                        if (Encapsulates(children[bestFitChild].bounds, existingObj.Bounds))
                        {
                            children[bestFitChild].SubAdd(existingObj.Obj, existingObj.Bounds); // Go a level deeper
                            objects.Remove(existingObj);                                        // Remove from here
                        }
                    }
                }

                // Now handle the new object we're adding now
                bestFitChild = BestFitChild(objBounds);
                if (Encapsulates(children[bestFitChild].bounds, objBounds))
                {
                    children[bestFitChild].SubAdd(obj, objBounds);
                }
                else
                {
                    OctreeObject newObj = new OctreeObject {
                        Obj = obj, Bounds = objBounds
                    };
                    //Debug.Log("ADD " + obj.name + " to depth " + depth);
                    objects.Add(newObj);
                }
            }
        }
        // #### PUBLIC METHODS ####

        /// <summary>
        /// Add an object.
        /// </summary>
        /// <param name="obj">Object to add.</param>
        /// <param name="objBounds">3D bounding box around the object.</param>
        /// <returns>True if the object fits entirely within this node.</returns>
        public bool Add(T obj, HLBoundingBoxXYZ objBounds)
        {
            if (!Encapsulates(bounds, objBounds))
            {
                return(false);
            }
            SubAdd(obj, objBounds);
            return(true);
        }
Esempio n. 6
0
        /// <summary>
        /// Check if the specified bounds intersect with anything in the tree. See also: GetColliding.
        /// </summary>
        /// <param name="checkBounds">bounds to check.</param>
        /// <returns>True if there was a collision.</returns>
        public bool IsColliding(HLBoundingBoxXYZ checkBounds, Filter <T> flt = null)
        {
            //#if UNITY_EDITOR
            // For debugging
            //AddCollisionCheck(checkBounds);
            //#endif


            return(rootNode.IsColliding(ref checkBounds, flt));
        }
Esempio n. 7
0
        /// <summary>
        /// Returns an array of objects that intersect with the specified bounds, if any. Otherwise returns an empty array. See also: IsColliding.
        /// </summary>
        /// <param name="checkBounds">bounds to check.</param>
        /// <returns>Objects that intersect with the specified bounds.</returns>
        public T[] GetColliding(HLBoundingBoxXYZ checkBounds, Filter <T> flt = null)
        {
            //#if UNITY_EDITOR
            // For debugging
            //AddCollisionCheck(checkBounds);
            //#endif
            List <T> collidingWith = new List <T>();

            rootNode.GetColliding(ref checkBounds, collidingWith, flt);
            return(collidingWith.ToArray());
        }
Esempio n. 8
0
        // #### PUBLIC METHODS ####

        /// <summary>
        /// Add an object.
        /// </summary>
        /// <param name="obj">Object to add.</param>
        /// <param name="objBounds">3D bounding box around the object.</param>
        public void Add(T obj, HLBoundingBoxXYZ objBounds)
        {
            // Add object or expand the octree until it can be added
            int count = 0; // Safety check against infinite/excessive growth

            while (!rootNode.Add(obj, objBounds))
            {
                Grow(objBounds.MidPoint - rootNode.Center);
                if (++count > 20)
                {
                    //Debug.LogError("Aborted Add operation as it seemed to be going on forever (" + (count - 1) + ") attempts at growing the octree.");
                    return;
                }
            }
            Count++;
        }
Esempio n. 9
0
        /// <summary>
        /// Return objects that are within maxDistance of the specified ray.
        /// </summary>
        /// <param name="ray">The ray.</param>
        /// <param name="maxDistance">Maximum distance from the ray to consider.</param>
        /// <param name="result">List result.</param>
        /// <returns>Objects within range.</returns>
        public void GetNearby(ref XYZ point, ref float maxDistance, List <T> result)
        {
            // Does the ray hit this node at all?
            // Note: Expanding the bounds is not exactly the same as a real distance check, but it's fast.
            // TODO: Does someone have a fast AND accurate formula to do this check?
            //bounds.ExpandToContain(new XYZ(maxDistance * 2, maxDistance * 2, maxDistance * 2));
            HLBoundingBoxXYZ d = new HLBoundingBoxXYZ(bounds.MidPoint, bounds.Size);

            d.ExpandToContain(new XYZ(bounds.Max.X + maxDistance, bounds.Max.Y + maxDistance, bounds.Max.Z + maxDistance));
            d.ExpandToContain(new XYZ(bounds.Min.X - maxDistance, bounds.Min.Y - maxDistance, bounds.Min.Z - maxDistance));

            bool intersected = d.Contains(point);

            d.Size = actualBoundsSize;
            if (!intersected)
            {
                return;
            }

            // Check against any objects in this node
            for (int i = 0; i < objects.Count; i++)
            {
                if (System.Math.Abs(objects[i].Pos.DistanceTo(point)) <= maxDistance)
                {
                    result.Add(objects[i].Obj);
                }
            }

            // Check children
            if (children != null)
            {
                for (int i = 0; i < 8; i++)
                {
                    children[i].GetNearby(ref point, ref maxDistance, result);
                }
            }
        }
Esempio n. 10
0
        /*
         * /// <summary>
         * /// Get the total amount of objects in this node and all its children, grandchildren etc. Useful for debugging.
         * /// </summary>
         * /// <param name="startingNum">Used by recursive calls to add to the previous total.</param>
         * /// <returns>Total objects in this node and its children, grandchildren etc.</returns>
         * public int GetTotalObjects(int startingNum = 0) {
         *  int totalObjects = startingNum + objects.Count;
         *  if (children != null) {
         *      for (int i = 0; i < 8; i++) {
         *          totalObjects += children[i].GetTotalObjects();
         *      }
         *  }
         *  return totalObjects;
         * }
         */

        // #### PRIVATE METHODS ####

        /// <summary>
        /// Set values for this node.
        /// </summary>
        /// <param name="baseLengthVal">Length of this node, not taking looseness into account.</param>
        /// <param name="minSizeVal">Minimum size of nodes in this octree.</param>
        /// <param name="centerVal">Centre position of this node.</param>
        void SetValues(float baseLengthVal, float minSizeVal, XYZ centerVal)
        {
            SideLength = baseLengthVal;
            minSize    = minSizeVal;
            Center     = centerVal;

            // Create the bounding box.
            actualBoundsSize = new XYZ(SideLength, SideLength, SideLength);
            bounds           = new HLBoundingBoxXYZ(Center, actualBoundsSize);

            float quarter           = SideLength / 4f;
            float childActualLength = SideLength / 2;
            var   childActualSize   = new XYZ(childActualLength, childActualLength, childActualLength);

            childBounds    = new HLBoundingBoxXYZ[8];
            childBounds[0] = new HLBoundingBoxXYZ(Center + new XYZ(-quarter, quarter, -quarter), childActualSize);
            childBounds[1] = new HLBoundingBoxXYZ(Center + new XYZ(quarter, quarter, -quarter), childActualSize);
            childBounds[2] = new HLBoundingBoxXYZ(Center + new XYZ(-quarter, quarter, quarter), childActualSize);
            childBounds[3] = new HLBoundingBoxXYZ(Center + new XYZ(quarter, quarter, quarter), childActualSize);
            childBounds[4] = new HLBoundingBoxXYZ(Center + new XYZ(-quarter, -quarter, -quarter), childActualSize);
            childBounds[5] = new HLBoundingBoxXYZ(Center + new XYZ(quarter, -quarter, -quarter), childActualSize);
            childBounds[6] = new HLBoundingBoxXYZ(Center + new XYZ(-quarter, -quarter, quarter), childActualSize);
            childBounds[7] = new HLBoundingBoxXYZ(Center + new XYZ(quarter, -quarter, quarter), childActualSize);
        }
Esempio n. 11
0
        /// <summary>
        /// Returns an axis aligned box which for extents of only visible geometry
        /// Solid.GetBoundingBox method includes planes and non-visible geometry
        /// </summary>
        /// <param name="geoObj"></param>
        /// <param name="parentTransform"></param>
        /// <returns></returns>
        public static HLBoundingBoxXYZ GetGeoBoundingBox(Solid geoObj, Transform parentTransform)
        {
            HLBoundingBoxXYZ box = null;

            var sld = geoObj as Solid;

            foreach (var edge in sld.Edges.OfType <Edge>())
            {
                foreach (var pt in edge.Tessellate())
                {
                    var ptx = parentTransform.OfPoint(pt);
                    if (box == null)
                    {
                        box = new HLBoundingBoxXYZ(ptx, new XYZ(0.01, 0.01, 0.01));
                    }
                    else
                    {
                        box.ExpandToContain(ptx);
                    }
                }
            }

            return(box);
        }
Esempio n. 12
0
        public virtual void ParseFrom(Element elm, MEPRevitGraphWriter writer)
        {
            var scannedElements = writer.Cache.ParsedElements;
            var cpTree          = writer.Cache.connectorsCache;
            var geoTree         = writer.Cache.geoCache;
            var maxDepth        = writer.Cache.MaxDepth;
            var graph           = writer.Graph;


            var elmStack = new Stack <Tuple <Element, XYZ> >();

            elmStack.Push(new Tuple <Element, XYZ>(elm, null));


            var previouseConnections = new HashSet <Connector>();

            while (elmStack.Count >= 1)
            {
                var currentElementAndpt = elmStack.Pop();
                var currentElement      = currentElementAndpt.Item1;
                var orgPoint            = currentElementAndpt.Item2;
                scannedElements.Add(currentElement.Id.IntegerValue);

                ConnectorManager currentCm = Utils.MEPUtils.GetConnectionManager(currentElement);
                if (currentCm == null)
                {
                    continue;
                }

                var connStack = new Stack <Connector>();
                foreach (var conn in currentCm.Connectors.OfType <Connector>().Where(cn => cn.ConnectorType == ConnectorType.End || cn.ConnectorType == ConnectorType.Curve))// && !previouseConnections.Any(pc => pc.IsConnectedTo(cn))))
                {
                    connStack.Push(conn);
                }

                XYZ nextOrigin = null;
                while (connStack.Count >= 1)
                {
                    var       currentConn   = connStack.Pop();
                    Connector nextConnector = null;
                    Element   nextElement   = null;
                    nextOrigin = currentConn.Origin;
                    MEPRevitEdge edge = null;

                    var meps     = GetSectionForConnctor(currentConn);
                    var edgeType = MEPGraph.Model.MEPEdgeTypes.FLOWS_TO;
                    switch (currentConn.Domain)
                    {
                    case Autodesk.Revit.DB.Domain.DomainCableTrayConduit:
                        edgeType = MEPGraph.Model.MEPEdgeTypes.CABLETRAY_FLOW_TO;
                        break;

                    case Autodesk.Revit.DB.Domain.DomainElectrical:
                        edgeType = MEPGraph.Model.MEPEdgeTypes.ELECTRICAL_FLOW_TO;
                        break;

                    case Autodesk.Revit.DB.Domain.DomainPiping:
                        edgeType = MEPGraph.Model.MEPEdgeTypes.HYDRONIC_FLOW_TO;
                        break;

                    case Autodesk.Revit.DB.Domain.DomainHvac:
                        edgeType = MEPGraph.Model.MEPEdgeTypes.AIR_FLOW_TO;
                        break;

                    case Autodesk.Revit.DB.Domain.DomainUndefined:
                        edgeType = MEPGraph.Model.MEPEdgeTypes.FLOWS_TO;
                        break;
                    }

                    if (currentConn.IsConnected)
                    {
                        //var ci = currentConn.GetMEPConnectorInfo();
                        //connection search
                        nextConnector = currentConn.AllRefs.OfType <Connector>().Where(cn => (cn.ConnectorType == ConnectorType.End || cn.ConnectorType == ConnectorType.Curve) && cn.IsConnectedTo(currentConn) && cn.Owner.Id.IntegerValue != currentElement.Id.IntegerValue).FirstOrDefault();
                        if (nextConnector != null)
                        {
                            previouseConnections.Add(currentConn);
                            edge        = graph.AddConnection(currentConn, nextConnector, MEPPathConnectionType.Phyiscal, edgeType);
                            nextElement = nextConnector.Owner;
                        }
                    }

                    if (nextConnector == null)
                    {
                        //geometry search
                        var connPoint         = currentConn.Origin;
                        var nearPoints        = cpTree.GetNearby(connPoint, 1F);
                        var nearPointsOrdered = nearPoints.Where(el => el.OriginatingElement.IntegerValue != currentElement.Id.IntegerValue).OrderBy(d => d.Point.DistanceTo(connPoint)).ToList();
                        var nearest           = nearPointsOrdered.FirstOrDefault();
                        if (nearest != null)
                        {
                            var distance = nearest.Point.DistanceTo(connPoint);
                            if (distance < 0.01F)
                            {
                                var nearElm = elm.Document.GetElement(nearest.OriginatingElement);
                                if (nearElm != null)
                                {
                                    var mepm = MEPUtils.GetConnectionManager(nearElm);
#if REVIT2016
                                    nextConnector = (mepm != null) ? mepm.Connectors.OfType <Connector>().Where(cn => (cn.ConnectorType == ConnectorType.End || cn.ConnectorType == ConnectorType.Curve) && cn.Id == nearest.ConnectorIndex).FirstOrDefault() : null;
#else
                                    throw new Exception("Only supported in Revit 2016 onwards");
#endif
                                    if (nextConnector != null)
                                    {
                                        previouseConnections.Add(currentConn);
                                        edge        = graph.AddConnection(currentConn, nextConnector, MEPPathConnectionType.Proximity, edgeType);
                                        nextElement = nextConnector.Owner;
                                        //nextOrigin = nextConnector.Origin;
                                    }
                                }
                            }
                        }

                        if (nextConnector == null && geoTree != null)
                        {
                            //todo: curve - point intersection check
                            var colBox       = new HLBoundingBoxXYZ(connPoint, new XYZ(0.1, 0.1, 0.1));
                            var nearbyCurves = geoTree.GetColliding(colBox);

                            var nearbyCurve = nearbyCurves.OfType <CurveGeometrySegment>().Where(nb => nb.OriginatingElement.IntegerValue != currentConn.Owner.Id.IntegerValue).OrderBy(nd => nd.Geometry.Distance(connPoint)).FirstOrDefault();
                            if (nearbyCurve != null)
                            {
                                var distance = nearbyCurve.Geometry.Distance(connPoint);
                                //check if connector is sitting near or with extent of the mepcurve
                                var tolerence = 0.01;
                                if (distance < tolerence ||
                                    nearbyCurve.Radius > 0.001 && distance <= (nearbyCurve.Radius + tolerence) ||
                                    nearbyCurve.Width > 0.001 && distance <= (nearbyCurve.Width + tolerence) ||
                                    nearbyCurve.Height > 0.001 && distance <= (nearbyCurve.Height + tolerence))
                                {
                                    //how to add this connection to the graph with no next connector??
                                    var orgElme = elm.Document.GetElement(nearbyCurve.OriginatingElement);
                                    edge        = graph.AddConnection(currentConn, connPoint, orgElme, MEPPathConnectionType.ProximityNoConnector, edgeType);
                                    nextElement = orgElme;
                                    //nextOrigin = connPoint;
                                }
                            }
                        }
                    }

                    if (edge != null && edge.Length < 0.1)
                    {
                        if (meps != null)
                        {
                            edge.Length = meps.TotalCurveLength;
                            edge.SetWeight("Roughness", meps.Roughness);
                            edge.SetWeight("ReynoldsNumber", meps.ReynoldsNumber);
                            edge.SetWeight("Velocity", meps.Velocity);
                            edge.SetWeight("VelocityPressure", meps.VelocityPressure);
                            edge.SetWeight("Flow", meps.Flow);
                        }
                        else if (orgPoint != null && nextOrigin != null)
                        {
                            var length = Math.Abs(orgPoint.DistanceTo(nextOrigin));
                            //very crude way to get length, should really be using MEPSection
                            if (length >= 0.1)
                            {
                                edge.Length = length;
                            }
                        }
                    }


                    ScanSpacesFromElement(currentConn, graph, scannedElements, nextElement == null);


                    var currentDepth = elmStack.Count;
                    if (nextElement != null && (maxDepth == -1 || currentDepth < maxDepth) && !scannedElements.Contains(nextElement.Id.IntegerValue))// && !graph.ContainsElement(nextElement))
                    {
                        elmStack.Push(new Tuple <Element, XYZ>(nextElement, nextOrigin));

                        //ScanFromElement(elm, graph, cpTree, maxDepth, currentDepth++);
                    }
                }

                //check curve for nearby unconnected points
                if (cpTree != null && currentElement is MEPCurve)
                {
                    //point - curve intersection check
                    var curveElm = currentElement as MEPCurve;

                    var locCurve     = curveElm.Location as LocationCurve;
                    var curve        = locCurve.Curve;
                    var nearbyCurve  = new CurveGeometrySegment(curve, currentElement);
                    var P1           = curve.GetEndPoint(0);
                    var P2           = curve.GetEndPoint(1);
                    var curveAsLine  = curve is Line ? curve as Line : Line.CreateBound(P1, P2);
                    var nearbyCurves = cpTree.GetNearby(curveAsLine, (float)nearbyCurve.MaxDimension);

                    foreach (var cb in nearbyCurves)
                    {
                        if (cb.OriginatingElement.IntegerValue == currentElement.Id.IntegerValue)
                        {
                            continue;
                        }
                        if (P1.DistanceTo(cb.Point) < 0.01)
                        {
                            continue;
                        }
                        if (P2.DistanceTo(cb.Point) < 0.01)
                        {
                            continue;
                        }

                        var tolerence = 0.01;
                        var cnpoint   = curveAsLine.Project(cb.Point);
                        var distance  = cnpoint.Distance;

                        //distance check is a crude way to check this element is sitting in the duct/pipe, could be nearby but intended to be connected.
                        if (distance < (nearbyCurve.MaxDimension / 2) + tolerence)
                        {
                            var orgElme = elm.Document.GetElement(cb.OriginatingElement);
                            if (orgElme == null)
                            {
                                continue;
                            }
                            var cmgr = MEPUtils.GetConnectionManager(orgElme);
                            if (cmgr == null)
                            {
                                continue;
                            }
#if REVIT2016
                            var nc = cmgr.Connectors.OfType <Connector>().FirstOrDefault(cn => cn.Id == cb.ConnectorIndex);
#else
                            Connector nc = null;
#endif
                            if (nc == null || nc.IsConnected)
                            {
                                continue;
                            }

                            //further check that direction of point intersects curve
                            var prjInX  = nc.CoordinateSystem.OfPoint(new XYZ(0, 0, 5));
                            var prjInnX = nc.CoordinateSystem.OfPoint(new XYZ(0, 0, -5));

                            var prjLine = Line.CreateBound(prjInnX, prjInX);
                            var ix      = curveAsLine.Intersect(prjLine);
                            if (ix != SetComparisonResult.Overlap)
                            {
                                continue;
                            }


                            var edge = graph.AddConnection(nc, cnpoint.XYZPoint, currentElement, MEPPathConnectionType.ProximityNoConnector, MEPGraph.Model.MEPEdgeTypes.FLOWS_TO);

                            if (orgPoint != null)
                            {
                                edge.Length = Math.Abs(orgPoint.DistanceTo(cnpoint.XYZPoint));
                            }


                            if (!scannedElements.Contains(orgElme.Id.IntegerValue) && !elmStack.Any(el => el.Item1 == orgElme))// && !graph.ContainsElement(nextElement))
                            {
                                elmStack.Push(new Tuple <Element, XYZ>(orgElme, cnpoint.XYZPoint));
                            }
                        }
                    }
                }

                ScanSpacesFromElement(currentElement, graph, scannedElements);
            }
        }
Esempio n. 13
0
 /// <summary>
 /// Checks if outerBounds encapsulates the given point.
 /// </summary>
 /// <param name="outerBounds">Outer bounds.</param>
 /// <param name="point">Point.</param>
 /// <returns>True if innerBounds is fully encapsulated by outerBounds.</returns>
 static bool Encapsulates(HLBoundingBoxXYZ outerBounds, XYZ point)
 {
     return(outerBounds.Contains(point));
 }
Esempio n. 14
0
        public void ParseFrom(Element elm, MEPRevitGraphWriter writer)
        {
            var space = elm as Autodesk.Revit.DB.Mechanical.Space;

            if (space == null)
            {
                return;
            }

            if (space.Volume < 0.5)
            {
                return;
            }

            var scannedElements = writer.Cache.ParsedElements;
            var cpTree          = writer.Cache.connectorsCache;
            var geoTree         = writer.Cache.geoCache;
            var maxDepth        = writer.Cache.MaxDepth;
            var graph           = writer.Graph;

            var lvl = space.Level;

            if (lvl != null)
            {
                graph.AddConnection(elm, lvl, MEPPathConnectionType.Proximity, MEPEdgeTypes.IS_ON);
            }

            //get elements in the space


            //get areas with edges and add to walls

            var sbopt = new SpatialElementBoundaryOptions();

            sbopt.SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Finish;
            sbopt.StoreFreeBoundaryFaces         = true;

            //var geoOpt = new Options();
            //var spgeo = space.get_Geometry(geoOpt);

            //get nearby spaces by extending bb of space
            //foreach each face of space geometry
            //split into uv gripd
            //construct line from each point
            //get intersect with faces on nearby faces
            //if it hits increment area count for direction

            var doc = space.Document;
            SpatialElementGeometryCalculator sg = new SpatialElementGeometryCalculator(doc, sbopt);
            var spgets = sg.CalculateSpatialElementGeometry(space);
            var spgeo  = spgets.GetGeometry();
            //var spbb = spgeo.GetBoundingBox();
            var spbb = elm.get_BoundingBox(null);

            //var spbbhl = new HLBoundingBoxXYZ(spbb);
            //spbbhl.Size = spbbhl.Size + new XYZ(2, 2, 4);


            //get faces
            var uvdensity   = 0.75;
            var maxDistance = 4D;
            //var nearbyFaces = nearbySpaces.OfType<SolidGeometrySegment>().Where(spc => spc.OriginatingElement != space.Id).SelectMany(sp => sp.Geometry.Faces.OfType<Face>());

            var rayIncidents = new HashSet <FaceIntersectRay>();


            //get all the faces in the geometry
            var spfaces = spgeo.Faces.OfType <Face>().ToList();

            foreach (var gface in spfaces)
            {
                //extract the faces which bound with other elements (Walls, floors, ceilings, windows etc)
                var sfaceInfos = spgets.GetBoundaryFaceInfo(gface);
                foreach (var sfaceInfo in sfaceInfos)
                {
                    //get the geo face and element of this bounding face
                    var sface = sfaceInfo.GetSubface();

                    var elmId = sfaceInfo.SpatialBoundaryElement;

                    var lelm     = GetElementFromLinkedElement(elmId, doc);
                    var docIdent = string.Empty;
                    //if (lelm == null) continue; //ignore this face if it doesn't resolve to a valid element

                    //find the bounding uv box so we can work out a grid of points
                    var fbb  = sface.GetBoundingBox();
                    var uExt = uvdensity; // (fbb.Max.U - fbb.Min.U) / uvdensity;
                    var vExt = uvdensity; // (fbb.Max.V - fbb.Min.V) / uvdensity;

                    var u = fbb.Min.U;
                    var v = fbb.Min.V;

                    //var sb = new GeoLib.C2DPolygon();

                    //construct grid for ray tracing
                    Stack <UV> gridPoints = new Stack <UV>();
                    while (u <= fbb.Max.U)
                    {
                        v = fbb.Min.V;
                        while (v <= fbb.Max.V)
                        {
                            var uvp = new UV(u, v);
                            v += uvdensity;
                            if (!sface.IsInside(uvp))
                            {
                                continue;                       //only include points that are actually on this face
                            }
                            gridPoints.Push(uvp);
                        }
                        u += uvdensity;
                    }

                    var nerbyCheckCats         = new int[] { };
                    IList <ElementId> hostElms = new List <ElementId>();

                    if (lelm != null && !(lelm is HostObject))
                    {
                        var n = lelm;
                    }

                    if (lelm != null)
                    {
                        docIdent = DocUtils.GetDocumentIdent(lelm.Document);
                        //get cutting elemtns if it's a wall so we can find door and windows
                        if (lelm is HostObject)
                        {
                            var whost = lelm as HostObject;
                            hostElms = whost.FindInserts(true, true, true, true);
                            //build oct tree of hostelems so we can quickly ray trace them later
                            foreach (var hostElm in hostElms)
                            {
                                //ignoring any link and transform for now
                                var ehl = whost.Document.GetElement(hostElm);
                                writer.Cache.geoCacheWriter.AddElement(ehl, true);
                            }
                        }

                        //we need the nearby check to find the cut out elements
                        nerbyCheckCats = new int[] { (int)BuiltInCategory.OST_Doors, (int)BuiltInCategory.OST_Windows };
                    }
                    else
                    {
                        nerbyCheckCats = new int[] { (int)BuiltInCategory.OST_Doors, (int)BuiltInCategory.OST_Windows, (int)BuiltInCategory.OST_Floors, (int)BuiltInCategory.OST_Walls, (int)BuiltInCategory.OST_Roofs };

                        //we need the nearby check to find the bounding element
                        switch (sfaceInfo.SubfaceType)
                        {
                        case SubfaceType.Bottom:
                            nerbyCheckCats = new int[] { (int)BuiltInCategory.OST_Floors };
                            break;

                        case SubfaceType.Top:
                            nerbyCheckCats = new int[] { (int)BuiltInCategory.OST_Roofs, (int)BuiltInCategory.OST_Floors, (int)BuiltInCategory.OST_Windows };
                            break;

                        case SubfaceType.Side:
                            nerbyCheckCats = new int[] { (int)BuiltInCategory.OST_Doors, (int)BuiltInCategory.OST_Windows, (int)BuiltInCategory.OST_Walls };
                            break;
                        }
                    }

                    //option 1 - brute force ray trace
                    //option 2 - construct 2d polygon from edges of each face, translate each face into the same plane, then boolean intersect, get area of each intersect
                    //calc space boundaries at midpoint?
                    Face optLastIntermeidateFace = null;
                    SolidGeometrySegment optLastIntermeidateSegment = null;
                    Face optLastHitFace = null;
                    SolidGeometrySegment optLastHitSegment = null;
                    var arWeight = sface.Area / gridPoints.Count;
                    while (gridPoints.Count > 0)
                    {
                        var pt          = gridPoints.Pop();
                        var rayIncident = new FaceIntersectRay();

                        var nv = sface.ComputeNormal(pt).Normalize();
                        //var mx = sface.ComputeSecondDerivatives(pt).MixedDerivative.Normalize();
                        rayIncident.SourceElement = space;
                        rayIncident.SourceFace    = sface;
                        rayIncident.SourceUV      = pt;

                        rayIncident.RayVecotor          = nv;
                        rayIncident.IntermediatDocIdent = docIdent;
                        rayIncident.IntermeidateElement = lelm != null ? lelm.Id : ElementId.InvalidElementId;
                        rayIncident.AreaWeight          = arWeight;
                        rayIncident.SubFaceType         = sfaceInfo.SubfaceType;
                        rayIncidents.Add(rayIncident);

                        var sp = sface.Evaluate(pt);
                        rayIncident.SourceXYZ = sp;
                        var ray   = Line.CreateBound(sp, sp + nv * 4);
                        var rayBB = new HLBoundingBoxXYZ(sp, (sp + nv * 4), true);
                        //rayBB.Size = rayBB.Size + new XYZ(0.5, 0.5, 0.5);
                        //Plane geoPlane = Plane.c(sp, sp + nv * 5, sp + nv * 5 + (mx * 0.2));
                        //SketchPlane skPlane = SketchPlane.Create(doc, geoPlane);
                        //doc.Create.NewModelCurve(ray, skPlane);

                        //check cache for hit on otherside, if there is one nearby on this face we can ignore it as we're not including both sides
                        //var nearbyrayHits = writer.Cache.rayhitCache.GetNearby(ray, 0.4F);
                        //var validSimilarHit = nearbyrayHits.FirstOrDefault(rh => rh.HittingSegment != null && rh.HittingSegment.OriginatingElement == space.Id && rh.IntermeidateElement == rayIncident.IntermeidateElement);
                        //if (validSimilarHit != null && sface.IsInside(validSimilarHit.HittingUV))
                        //{
                        //    rayIncident.Ignore = true;
                        //    log.Info("Got hit on other side, ignoring");
                        //    continue;
                        // }

                        if (optLastIntermeidateFace != null)
                        {
                            IntersectionResultArray issRes = null;
                            var issGeoHit = getIntersect(pt, optLastIntermeidateFace, sface, maxDistance, out issRes, out double distance, nv, doc);
                            if (issGeoHit)
                            {
                                rayIncident.IntermediatDocIdent = optLastIntermeidateSegment.OriginatingDocIdent;
                                rayIncident.IntermeidateElement = optLastIntermeidateSegment.OriginatingElement;
                            }
                            else
                            {
                                optLastIntermeidateFace    = null;
                                optLastIntermeidateSegment = null;
                            }
                        }

                        GeometrySegment[] nearbyElements = null;

                        if (optLastIntermeidateFace == null)
                        {
                            nearbyElements = geoTree.GetColliding(rayBB);

                            var nearbyCutoutElements = nearbyElements.Where(iel =>
                                                                            (hostElms.Count == 0 || hostElms.Contains(iel.OriginatingElement)) &&
                                                                            nerbyCheckCats.Contains(iel.OriginatingElementCategory.IntegerValue))
                                                       .OfType <SolidGeometrySegment>();


                            IntersectionResultArray isRes = null;
                            bool isGeoHit = false;
                            foreach (var extSegment in nearbyCutoutElements)
                            {
                                foreach (var extFace in extSegment.Geometry.Faces.OfType <Face>())
                                {
                                    isGeoHit = getIntersect(pt, extFace, sface, maxDistance, out isRes, out double distance, nv, doc);
                                    if (isGeoHit)
                                    {
                                        rayIncident.IntermediatDocIdent = extSegment.OriginatingDocIdent;
                                        rayIncident.IntermeidateElement = extSegment.OriginatingElement;
                                        optLastIntermeidateFace         = extFace;
                                        optLastIntermeidateSegment      = extSegment;
                                        break;
                                    }
                                }
                                if (isGeoHit)
                                {
                                    break;
                                }
                            }
                        }



                        if (optLastHitFace != null)
                        {
                            var isHit = getIntersect(pt, optLastHitFace, sface, maxDistance, out var isRe, out double distance, nv, doc);
                            var isRes = isRe;
                            //project point onto other face instead?
                            var srcXYZ   = sface.Evaluate(pt);
                            var otXYZRes = optLastHitFace.Project(srcXYZ);

                            if (isHit)
                            {
                                var itx = isRes.OfType <IntersectionResult>().FirstOrDefault();
                                rayIncident.HittingFace    = optLastHitFace;
                                rayIncident.HittingSegment = optLastHitSegment;
                                rayIncident.HittingUV      = itx.UVPoint;
                                rayIncident.HittingXYZ     = itx.XYZPoint;
                                rayIncident.Distance       = distance;
                                nv = sface.ComputeNormal(pt).Normalize();
                                continue; //shortcut if we find a hit on the same face again
                            }
                            else
                            {
                                optLastHitFace    = null;
                                optLastHitSegment = null;
                            }
                        }


                        if (nearbyElements == null)
                        {
                            nearbyElements = geoTree.GetColliding(rayBB, (ob) => { return(ob.OriginatingElementCategory.IntegerValue == (int)BuiltInCategory.OST_MEPSpaces); });
                        }

                        //BoundingBoxIntersectsFilter bif = new BoundingBoxIntersectsFilter(new Outline(sp - new XYZ(0.1, 0.1, 0.1), (sp + nv * 2) + new XYZ(0.1, 0.1, 0.1)));
                        //var sfv = new FilteredElementCollector(space.Document);
                        //var sepl = sfv.WherePasses(bif).ToElements();

                        var nearbySpaces = nearbyElements.Where(ne => ne.OriginatingElementCategory.IntegerValue == (int)BuiltInCategory.OST_MEPSpaces).OfType <SolidGeometrySegment>().Distinct().ToList();

                        //find the extents of this face which face faces on other nearby faces (whaaat?)
                        //check each face of each nearby space for intersect with ray
                        foreach (var nearSpace in nearbySpaces)
                        {
                            var isHit = false;
                            foreach (var otFace in nearSpace.Geometry.Faces.OfType <Face>())
                            {
                                isHit = getIntersect(pt, otFace, sface, maxDistance, out var isRe, out double distance, nv, doc);
                                var isRes = isRe;
                                //project point onto other face instead?
                                var srcXYZ   = sface.Evaluate(pt);
                                var otXYZRes = otFace.Project(srcXYZ);

                                if (isHit)
                                {
                                    if (nearSpace.OriginatingElement.IntegerValue != elm.Id.IntegerValue)
                                    {
                                        var itx = isRes.OfType <IntersectionResult>().FirstOrDefault();
                                        rayIncident.HittingFace    = otFace;
                                        rayIncident.HittingSegment = nearSpace;
                                        rayIncident.HittingUV      = itx.UVPoint;
                                        rayIncident.HittingXYZ     = itx.XYZPoint;
                                        rayIncident.Distance       = distance;

                                        nv = sface.ComputeNormal(pt).Normalize();

                                        //optimization: check this face again first for the next ray check, since it's likely to be another hit
                                        optLastHitFace    = otFace;
                                        optLastHitSegment = nearSpace;

                                        rayIncident.Ignore = false;
                                    }
                                    else
                                    {
                                        if (distance < 0.1)
                                        {
                                            isHit = false;                 //looks like we hit our own face, ouch!
                                        }
                                        rayIncident.Ignore = true;
                                    }

                                    break;
                                }
                            }
                            if (isHit)
                            {
                                break;
                            }
                        }
                    }
                }

                /*
                 * space
                 * face
                 *    intermediate element (Wall/window/door)
                 *        face (space)
                 * face
                 *
                 *
                 * add connection
                 * this space -> section -> other space
                 * wall ------------^
                 */
            }

            //var ec = new elmComparer();
            var              srcNode        = graph.AddElement(space);
            double           minIncluedArea = 4;
            VectorBucketiser vbw            = new VectorBucketiser(8, 5);

            var includeRays = rayIncidents.Where(r => !r.Ignore);

            var outsideNode = graph.Nodes.FirstOrDefault(n => n.Name == "Outside");
            var groundNode  = graph.Nodes.FirstOrDefault(n => n.Name == "Ground");

            //group by the intermediate element (wall/floor/etc)
            foreach (var docGroup in includeRays.GroupBy(ri => ri.IntermediatDocIdent))//, ec))
            {
                var sdoc = DocUtils.GetDocument(docGroup.Key, elm.Document.Application);

                foreach (var intermediateElemGroup in docGroup.GroupBy(ri => ri.IntermeidateElement.IntegerValue))//, ec))
                {
                    var     selmid = new ElementId(intermediateElemGroup.Key);
                    Element selm   = sdoc != null?sdoc.GetElement(selmid) : null;

                    //group similar vectors into buckets
                    foreach (var rayVectorBuckets in intermediateElemGroup.GroupBy(ri => vbw.GetBucket(ri.RayVecotor)))
                    {
                        var rg = rayVectorBuckets.ToList();

                        var gs = rg.GroupBy(vr => vr.HittingSegment == null ? null : vr.HittingSegment.OriginatingElement).ToList();
                        //group each vector and intermediate element by the element it hits
                        foreach (var orgElmGroup in gs)
                        {
                            //find a section already matching this section
                            //actually easier to treat each path as separate sections
                            //var edNodes = graph.GetEdges(intermediateElemGroup.Key).Where(ed => ed.NextNode.AsAbstractNode.Name == "Surface"
                            //&& ed.NextNode.Connections.Any(cn => cn.NextNode.OriginId == spNode.OriginId)).Where(ed => ed.;

                            var apporxIntersect = orgElmGroup.Sum(et => et.AreaWeight);
                            var vector          = orgElmGroup.First().RayVecotor;
                            if (apporxIntersect < minIncluedArea)
                            {
                                continue;
                            }

                            var direction = VectorBucketiser.GetZeroClamppedPoint(orgElmGroup.First().RayVecotor); //should be rayVectorGroup.Key.AverageVector, but not yet implemented;

                            MEPRevitNode spNode = null;
                            if (orgElmGroup.Key != null)
                            {
                                var otherSpace = doc.GetElement(orgElmGroup.Key);
                                spNode = graph.AddElement(otherSpace);
                            }
                            else
                            {
                                if (selm != null && (selm.Name.ToLower().Contains("exterior") || selm is Autodesk.Revit.DB.Opening || selm.Name.ToLower().Contains("window") || selm is Autodesk.Revit.DB.RoofBase))
                                {
                                    if (outsideNode == null)
                                    {
                                        outsideNode = new MEPRevitNode("Outside", "Boundary", "OutsideBoundary", new MEPGraph.Model.Environment());
                                    }
                                    spNode = outsideNode;
                                }
                                else if (selm != null && (selm.Name.ToLower().Contains("floor") || selm is Autodesk.Revit.DB.Floor))
                                {
                                    if (groundNode == null)
                                    {
                                        groundNode = new MEPRevitNode("Ground", "Boundary", "GroundBoundary", new MEPGraph.Model.Environment());
                                    }
                                    spNode = groundNode;
                                }
                                else
                                {
                                    spNode = new MEPRevitNode("Void", "Boundary", "OtherBoundary", new MEPGraph.Model.VoidVolume());
                                    continue; //ignore void boundaries for now
                                }
                            }


                            var sectionN = graph.NewSection(selm, MEPGraph.Model.MEPEdgeTypes.IS_ON);

                            if (selm == null)
                            {
                                var emptyBondary = new MEPRevitNode();
                                emptyBondary.AsAbstractNode.Name = "OpenBoundary";
                                var cl = graph.AddConnection(emptyBondary, sectionN, MEPPathConnectionType.SectionOf, MEPGraph.Model.MEPEdgeTypes.IS_ON);
                                cl.AsNodeEdge.ExtendedProperties.Add("rvid", intermediateElemGroup.Key);
                            }

                            sectionN.AsAbstractNode.Name = "Surface";
                            var edgesf = graph.AddConnection(srcNode, sectionN, MEPPathConnectionType.Analytical, MEPGraph.Model.MEPEdgeTypes.BOUNDED_BY);

                            //total up intersecting area
                            var sampleIntersect = orgElmGroup.First();


                            edgesf.SetWeight("Area", apporxIntersect);
                            //edgesf.SetWeight("Direction", new HoareLea.MEPGraph.Model.MEPPoint(direction.X, direction.Y, direction.Z));
                            edgesf.SetWeight("DirectionX", direction.X);
                            edgesf.SetWeight("DirectionY", direction.Y);
                            edgesf.SetWeight("DirectionZ", direction.Z);
                            edgesf.SetWeight("SubFaceType", (int)sampleIntersect.SubFaceType);

                            /*
                             * HLBoundingBoxXYZ bb = new HLBoundingBoxXYZ();
                             * foreach (var et in orgElmGroup)
                             * {
                             *  if (et.HittingXYZ != null)
                             *  {
                             *      bb.ExpandToContain(et.HittingXYZ);
                             *  }
                             * }
                             * if (!bb.IsInvalid)
                             * {
                             *  sectionN.BoundingBox = bb;
                             *  var avgCenterPoint = bb.MidPoint;
                             *  var size = bb.Size;
                             *  sectionN.SetProperty("OriginX", avgCenterPoint.X);
                             *  sectionN.SetProperty("OriginY", avgCenterPoint.Y);
                             *  sectionN.SetProperty("OriginZ", avgCenterPoint.Z);
                             *  sectionN.SetProperty("SizeX", size.X);
                             *  sectionN.SetProperty("SizeY", size.Y);
                             *  sectionN.SetProperty("SizeZ", size.Z);
                             * }*/



                            var edgest     = graph.AddConnection(sectionN, spNode, MEPPathConnectionType.Analytical, MEPGraph.Model.MEPEdgeTypes.BOUNDED_BY);
                            var directionn = direction;//.Negate();
                            edgest.SetWeight("Area", apporxIntersect);
                            edgest.SetWeight("DirectionX", directionn.X);
                            edgest.SetWeight("DirectionY", directionn.Y);
                            edgest.SetWeight("DirectionZ", directionn.Z);
                            edgest.SetWeight("SubFaceType", (int)sampleIntersect.SubFaceType);
                        }
                    }
                }
            }
        }
Esempio n. 15
0
 /// <summary>
 /// Find which child node this object would be most likely to fit in.
 /// </summary>
 /// <param name="objBounds">The object's bounds.</param>
 /// <returns>One of the eight child octants.</returns>
 int BestFitChild(HLBoundingBoxXYZ objBounds)
 {
     return((objBounds.MidPoint.X <= Center.X ? 0 : 1) + (objBounds.MidPoint.Y >= Center.Y ? 0 : 4) + (objBounds.MidPoint.Z <= Center.Z ? 0 : 2));
 }
Esempio n. 16
0
 /// <summary>
 /// Checks if outerBounds encapsulates innerBounds.
 /// </summary>
 /// <param name="outerBounds">Outer bounds.</param>
 /// <param name="innerBounds">Inner bounds.</param>
 /// <returns>True if innerBounds is fully encapsulated by outerBounds.</returns>
 static bool Encapsulates(HLBoundingBoxXYZ outerBounds, HLBoundingBoxXYZ innerBounds)
 {
     return(outerBounds.Contains(innerBounds.Min) && outerBounds.Contains(innerBounds.Max));
 }
Esempio n. 17
0
 public static bool DoBoxesIntersect(HLBoundingBoxXYZ r1, HLBoundingBoxXYZ r2, double tolerance)
 {
     return(r1.Min.X <= r2.Max.X && r1.Max.X >= r2.Min.X && r1.Min.Y <= r2.Max.Y && r1.Max.Y >= r2.Min.Y && r1.Min.Z <= r2.Max.Z && r1.Max.Z >= r2.Min.Z);
 }