public virtual void ParseFrom(ICollection <Element> elms, MEPRevitGraphWriter writer) { foreach (var elm in elms) { ParseFrom(elm, writer); } }
public override void ParseFrom(Element elm, MEPRevitGraphWriter writer) { var fi = elm as FamilyInstance; if (fi == null) { return; } var elmHost = fi.Host; Transform tsx = Transform.Identity; if (elmHost is RevitLinkInstance) { RevitLinkInstance rl = elmHost as RevitLinkInstance; var ldoc = rl.GetLinkDocument(); var sRef = fi.HostFace.ConvertToStableRepresentation(elm.Document); //dcdb8503-82b6-4a11-a408-754c3e8e7289-0026baca:0:RVTLINK:3791865:0:INSTANCE:3769400:94:SURFACE string[] refTokens = sRef.Split(':'); var extIdst = refTokens[3]; //6ths index contains the elementID in host document! var extId = new ElementId(int.Parse(extIdst)); var lelmHost = ldoc.GetElement(extId); if (lelmHost != null) { writer.Graph.AddConnection(elm, lelmHost, MEPPathConnectionType.Analytical, Model.MEPEdgeTypes.SENSING); } tsx = rl.GetTotalTransform().Inverse; elmHost = lelmHost; } else if (elmHost != null && !(elmHost is ReferencePlane)) { writer.Graph.AddConnection(elm, elmHost, MEPPathConnectionType.Analytical, Model.MEPEdgeTypes.SENSING); } else if (fi.Space != null) { writer.Graph.AddConnection(elm, fi.Space, MEPPathConnectionType.Analytical, Model.MEPEdgeTypes.SENSING); } //find space, level, etc of host element. if (elmHost != null && !(elmHost is ReferencePlane)) { base.ScanSpacesFromElement(elmHost, writer.Graph, writer.Cache.ParsedElements, tsx, elm.Document); } }
public override void ParseFrom(Element elm, MEPRevitGraphWriter writer) { //connect db panels to their circuits if (elm is FamilyInstance) { var fi = elm as FamilyInstance; var sysElm = fi.MEPModel; if (sysElm != null && sysElm.ElectricalSystems != null) { var panleSystems = sysElm.ElectricalSystems.OfType <Autodesk.Revit.DB.Electrical.ElectricalSystem>().Where(sy => sy.BaseEquipment != null && sy.BaseEquipment.Id == elm.Id); foreach (var sys in panleSystems) { writer.Graph.AddConnection(elm, sys, MEPPathConnectionType.Analytical, MEPGraph.Model.MEPEdgeTypes.ELECTRICAL_FLOW_TO); try { var elmsINSys = sys.Elements.OfType <FamilyInstance>(); foreach (var emms in elmsINSys) { writer.Graph.AddConnection(sys, emms, MEPPathConnectionType.Analytical, MEPGraph.Model.MEPEdgeTypes.ELECTRICAL_FLOW_TO); ParseFrom(emms, writer); } } catch { //log exception } } } } base.ParseFrom(elm, writer); }
public void FinalizeGraph(MEPRevitGraphWriter writer) { }
public void InitializeGraph(MEPRevitGraphWriter writer) { }
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 FinalizeGraph(MEPRevitGraphWriter writer) { //remove duplicate paths }
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); } } } } }