protected void ScanSpacesFromElement(Element elm, MEPRevitGraph graph, HashSet <int> scannedElements) { var doc = elm.Document; if (elm is FamilyInstance) //elm.Category.Id.IntegerValue == (int)BuiltInCategory.OST_DuctTerminal || elm.Category.Id.IntegerValue == (int)BuiltInCategory.OST_MechanicalEquipment) { var fi = elm as FamilyInstance; var org = (elm.Location as LocationPoint).Point; var pos = (elm.Location as LocationPoint).Point; var phase = doc.GetElement(elm.CreatedPhaseId) as Phase; var sp = elm.Document.GetSpaceAtPoint(pos, phase); Level lvl = null; if (sp == null) { var lvPAram = elm.get_Parameter(BuiltInParameter.RBS_START_LEVEL_PARAM); if (lvPAram != null) { lvl = doc.GetElement(lvPAram.AsElementId()) as Level; if (lvl != null) { var lvPs = new XYZ(pos.X, pos.Y, lvl.ProjectElevation + 1); sp = elm.Document.GetSpaceAtPoint(lvPs, phase); } } } if (sp == null) { var lvPAram = elm.get_Parameter(BuiltInParameter.SCHEDULE_LEVEL_PARAM); if (lvPAram != null) { lvl = doc.GetElement(lvPAram.AsElementId()) as Level; if (lvl != null) { var lvPs = new XYZ(pos.X, pos.Y, lvl.ProjectElevation + 1); sp = elm.Document.GetSpaceAtPoint(lvPs, phase); } } } if (sp == null) { var hxOrt = fi.HandOrientation.Normalize().Negate(); pos = org + hxOrt.Multiply(1.64042); //stub is 1.64042 feet (0.5 meters) sp = elm.Document.GetSpaceAtPoint(pos, phase); } if (sp == null) { var hxOrt = fi.HandOrientation.Normalize().Negate(); pos = org + hxOrt.Multiply(-1.64042); //stub is 1.64042 feet (0.5 meters) sp = elm.Document.GetSpaceAtPoint(pos, phase); } if (sp == null) { pos = org + new XYZ(0, 0, -4); sp = elm.Document.GetSpaceAtPoint(pos, phase); } if (sp != null) { scannedElements.Add(sp.Id.IntegerValue); graph.AddConnection(elm, sp, pos, MEPPathConnectionType.Phyiscal, MEPGraph.Model.MEPEdgeTypes.IS_IN_SPACE); if (elm.Category.Id.IntegerValue == (int)BuiltInCategory.OST_DuctTerminal) { //try to find out if this terminal is supply or extract ConnectorManager currentCm = MEPUtils.GetConnectionManager(elm); var inConn = currentCm != null?currentCm.Connectors.OfType <Connector>().Where(cn => cn.Domain == Autodesk.Revit.DB.Domain.DomainHvac && (cn.ConnectorType == ConnectorType.End || cn.ConnectorType == ConnectorType.Curve) && cn.Direction == FlowDirectionType.In).FirstOrDefault() : null; if (inConn != null) { graph.AddConnection(elm, sp, pos, MEPPathConnectionType.Analytical, MEPGraph.Model.MEPEdgeTypes.FLOWS_TO_SPACE); } else { graph.AddConnection(sp, elm, pos, MEPPathConnectionType.Analytical, MEPGraph.Model.MEPEdgeTypes.FLOWS_TO_SPACE); } } } if (lvl != null) { graph.AddConnection(elm, lvl, MEPPathConnectionType.Proximity, MEPGraph.Model.MEPEdgeTypes.IS_ON); } } }
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); } }
public void Write(ICollection <Element> scanElements, ICollection <Element> geoSerchElements, int maxDepth, bool doGeometryMatch, Document doc) { Cache.connectorsCache = new PointOctree <ConnectorPointGeometrySegment>(6.56168F, XYZ.Zero, 2F); Cache.MaxDepth = maxDepth; Cache.geoCache = new BoundsOctree <GeometrySegment>(2, XYZ.Zero, 2F, 1.001f); Cache.geoCacheWriter = new BoundsOctreeElementWriter(Cache.geoCache); Cache.ParsedElements = new HashSet <int>(); Cache.rayhitCache = new PointOctree <FaceIntersectRay>(2, XYZ.Zero, 2F); var dsCount = geoSerchElements.Count; foreach (var elm in geoSerchElements) { var cmn = MEPUtils.GetConnectionManager(elm); if (cmn != null) { foreach (var conn in cmn.Connectors.OfType <Connector>()) { #if REVIT2016 var gesseg = new ConnectorPointGeometrySegment(elm.Id, conn.Origin, conn.Id); Cache.connectorsCache.Add(gesseg, conn.Origin); #else throw new Exception("Only supported in Revit 2016 onwards"); #endif } } if (doGeometryMatch) { Cache.geoCacheWriter.AddElement(elm, true); } } if (doGeometryMatch) { var li = DocUtils.GetLinkInstances(doc); dsCount = li.Count(); //cache geometry in linked documents. The geometry is expected to remain static, or changed as a block, so we don't need to keep track of each element. foreach (var linkedInstance in li) { Transform docTransform = linkedInstance.GetTotalTransform(); Transform docTransformInverse = docTransform.Inverse; //RevitLinkType linkType = (RevitLinkType)rDoc.GetElement(linkedInstance.GetTypeId()) as RevitLinkType; var ldoc = linkedInstance.GetLinkDocument();// HLRevitUtilities.GetLinkedDocumentFromType(_rdoc.Application, linkType); if (ldoc == null) { continue; } var lnGeoCol = new FilteredElementCollector(ldoc); var lnGeoFilter = new ElementMulticategoryFilter(new BuiltInCategory[] { BuiltInCategory.OST_Floors, BuiltInCategory.OST_Roofs }); foreach (var lnelm in lnGeoCol.WherePasses(lnGeoFilter).WhereElementIsNotElementType().ToElements()) { Cache.geoCacheWriter.AddElement(lnelm, true, docTransformInverse); } } } var elmcache = new HashSet <int>(); var parserCount = Parsers.Count; foreach (var parser in Parsers) { parser.InitializeGraph(this); var elms = scanElements.Where(el => parser.CanParse(el)).ToList(); dsCount = elms.Count(); foreach (var elm in elms) { parser.ParseFrom(elm, this); } parser.FinalizeGraph(this); } }
public virtual bool CanParse(Element elm) { return(MEPUtils.GetConnectionManager(elm) != null); }
protected void ScanSpacesFromElement(Element elm, MEPRevitGraph graph, HashSet <int> scannedElements, Transform hostTx, Document SpacesModel) { var elmDoc = elm.Document; var gpNode = graph.AddElement(elm, true); if (elm is FamilyInstance) //elm.Category.Id.IntegerValue == (int)BuiltInCategory.OST_DuctTerminal || elm.Category.Id.IntegerValue == (int)BuiltInCategory.OST_MechanicalEquipment) { var fi = elm as FamilyInstance; var org = (elm.Location as LocationPoint).Point; var pos = (elm.Location as LocationPoint).Point; if (fi.HasSpatialElementCalculationPoint) { pos = fi.GetSpatialElementCalculationPoint(); } pos = hostTx.OfPoint(pos); Level lvl = null; //need to do phase mapping if elmDoc is not the same as the SpacesModel var phase = SpacesModel.GetElement(elm.CreatedPhaseId) as Phase; var sp = fi.Space; if (sp == null) { sp = SpacesModel.GetSpaceAtPoint(pos, phase); } if (lvl == null) { var lvPAram = elm.get_Parameter(BuiltInParameter.RBS_START_LEVEL_PARAM); if (lvPAram != null) { lvl = elmDoc.GetElement(lvPAram.AsElementId()) as Level; } } if (lvl == null) { var lvPAram = elm.get_Parameter(BuiltInParameter.SCHEDULE_LEVEL_PARAM); if (lvPAram != null) { lvl = elmDoc.GetElement(lvPAram.AsElementId()) as Level; } } if (lvl == null && sp != null) { lvl = sp.Level; } if (lvl == null) { lvl = elmDoc.GetElement(fi.LevelId) as Level; } //check around element for a space double chDistance = 3.28084; //3.28084 = 1m if (sp == null) { var hxOrt = fi.HandOrientation.Normalize().Negate(); pos = org + hxOrt.Multiply(-chDistance); pos = hostTx.OfPoint(pos); sp = SpacesModel.GetSpaceAtPoint(pos, phase); } if (sp == null) { var hxOrt = fi.HandOrientation.Normalize().Negate(); pos = org + hxOrt.Multiply(chDistance); pos = hostTx.OfPoint(pos); sp = SpacesModel.GetSpaceAtPoint(pos, phase); } if (sp == null) { var hxOrt = fi.FacingOrientation.Normalize().Negate(); pos = org + hxOrt.Multiply(-chDistance); pos = hostTx.OfPoint(pos); sp = SpacesModel.GetSpaceAtPoint(pos, phase); } if (sp == null) { var hxOrt = fi.FacingOrientation.Normalize().Negate(); pos = org + hxOrt.Multiply(chDistance); pos = hostTx.OfPoint(pos); sp = SpacesModel.GetSpaceAtPoint(pos, phase); } if (sp == null) { pos = org + new XYZ(0, 0, -chDistance); pos = hostTx.OfPoint(pos); sp = SpacesModel.GetSpaceAtPoint(pos, phase); } if (sp != null && sp.Level != null) { lvl = sp.Level; } if (sp == null && lvl != null) { var lvPs = new XYZ(pos.X, pos.Y, lvl.ProjectElevation + 2); lvPs = hostTx.OfPoint(lvPs); sp = elm.Document.GetSpaceAtPoint(lvPs, phase); } if (sp != null) { scannedElements.Add(sp.Id.IntegerValue); graph.AddConnection(elm, sp, pos, MEPPathConnectionType.Phyiscal, Model.MEPEdgeTypes.IS_IN_SPACE); if (elm.Category.Id.IntegerValue == (int)BuiltInCategory.OST_DuctTerminal) { //try to find out if this terminal is supply or extract ConnectorManager currentCm = MEPUtils.GetConnectionManager(elm); var inConn = currentCm != null?currentCm.Connectors.OfType <Connector>().Where(cn => cn.Domain == Autodesk.Revit.DB.Domain.DomainHvac && (cn.ConnectorType == ConnectorType.End || cn.ConnectorType == ConnectorType.Curve) && cn.Direction == FlowDirectionType.In).FirstOrDefault() : null; if (inConn != null) { graph.AddConnection(elm, sp, pos, MEPPathConnectionType.Analytical, Model.MEPEdgeTypes.FLOWS_TO_SPACE); } else { graph.AddConnection(sp, elm, pos, MEPPathConnectionType.Analytical, Model.MEPEdgeTypes.FLOWS_TO_SPACE); } } } if (lvl != null) { gpNode.LevelId = lvl.Id.IntegerValue; } } }