/// <summary> /// Adds a new retaining pond. /// </summary> /// <param name="uiDoc">The document.</param> /// <param name="pondRadius">The radius of the pond.</param> private void AddNewRetainingPond(UIDocument uiDoc, double pondRadius) { Document doc = uiDoc.Document; // Find toposurfaces FilteredElementCollector tsCollector = new FilteredElementCollector(doc); tsCollector.OfClass(typeof(TopographySurface)); IEnumerable <TopographySurface> tsEnumerable = tsCollector.Cast <TopographySurface>().Where <TopographySurface>(ts => !ts.IsSiteSubRegion); int count = tsEnumerable.Count <TopographySurface>(); // If there is only on surface, use it. If there is more than one, let the user select the target. TopographySurface targetSurface = null; if (count > 1) // tmp { targetSurface = SiteUIUtils.PickTopographySurface(uiDoc); } else { targetSurface = tsEnumerable.First <TopographySurface>(); } // Pick point and project to plane at toposurface average elevation XYZ point = SiteUIUtils.PickPointNearToposurface(uiDoc, targetSurface, "Pick point for center of pond."); double elevation = point.Z; // Add subregion first, so that any previously existing points can be removed to avoid distorting the new region // Find material "Water" FilteredElementCollector collector = new FilteredElementCollector(doc); collector.OfClass(typeof(Material)); Material mat = collector.Cast <Material>().FirstOrDefault <Material>(m => m.Name == "Water"); // Create subregion curves List <Curve> curves = new List <Curve>(); curves.Add(Arc.Create(point, pondRadius, 0, Math.PI, XYZ.BasisX, XYZ.BasisY)); curves.Add(Arc.Create(point, pondRadius, Math.PI, 2 * Math.PI, XYZ.BasisX, XYZ.BasisY)); CurveLoop curveLoop = CurveLoop.Create(curves); List <CurveLoop> curveLoops = new List <CurveLoop>(); curveLoops.Add(curveLoop); // All changes are added to one transaction group - will create one undo item using (TransactionGroup addGroup = new TransactionGroup(doc, "Add pond group")) { addGroup.Start(); IList <XYZ> existingPoints = null; // Transacton for adding subregion. using (Transaction t2 = new Transaction(doc, "Add subregion")) { t2.Start(); SiteSubRegion region = SiteSubRegion.Create(doc, curveLoops, targetSurface.Id); if (mat != null) { region.TopographySurface.MaterialId = mat.Id; } t2.Commit(); // The boundary points for the subregion cannot be deleted, since they are generated // to represent the subregion boundary rather than representing real points in the host. // Get non-boundary points only to be deleted. existingPoints = SiteEditingUtils.GetNonBoundaryPoints(region.TopographySurface); // Average elevation of all points in the subregion to use as base elevation for the pond topography elevation = SiteEditingUtils.GetAverageElevation(region.TopographySurface.GetPoints()); } // Add the topography points to the target surface via edit scope. using (TopographyEditScope editScope = new TopographyEditScope(doc, "Edit TS")) { editScope.Start(targetSurface.Id); // Transaction for points changes using (Transaction t = new Transaction(doc, "Add points")) { t.Start(); // Delete existing points first to avoid conflict if (existingPoints.Count > 0) { targetSurface.DeletePoints(existingPoints); } // Generate list of points to add IList <XYZ> points = SiteEditingUtils.GeneratePondPointsSurrounding(new XYZ(point.X, point.Y, elevation - 3), pondRadius); targetSurface.AddPoints(points); t.Commit(); } editScope.Commit(new TopographyEditFailuresPreprocessor()); } addGroup.Assimilate(); } }
private Result SlopeSelectedBuildingPad(UIDocument targetUIdoc, ref string message, double maxPointDistInFeet, double targetAngleInRadians) { Document doc = targetUIdoc.Document; Selection sel = targetUIdoc.Selection; View3D current3dView = doc.ActiveView as View3D; if (current3dView == null) { message = Properties.Messages.SlopeGradingFromPads_Not3DView; return(Result.Failed); } BuildingPad selectedBuildingPad = doc.GetElement(sel.PickObject(ObjectType.Element, new PadSelectionFilter(), Properties.Messages.SlopeGradingFromPads_SelectPad)) as BuildingPad; //Check if the Pad is associate with a Surface (never seen one doesnt, but anyways) ElementId topoElementID = selectedBuildingPad.HostId; if (topoElementID.Equals(ElementId.InvalidElementId)) { message = Properties.Messages.SlopeGradingFromPads_NoTopoAssociate; return(Result.Failed); } TopographySurface currentTopo = doc.GetElement(topoElementID) as TopographySurface; if (currentTopo == null) { message = Properties.Messages.SlopeGradingFromPads_NoTopoAssociate;; return(Result.Failed); } IList <CurveLoop> PadBoundaryLoops = new List <CurveLoop>(); CurveLoop outerLoop = null; IList <Reference> TopFacesReferences = HostObjectUtils.GetTopFaces(selectedBuildingPad); if (TopFacesReferences.Count > 1) { message = Properties.Messages.SlopeGradingFromPads_PadsWithMoreThanOneUpperFace; return(Result.Failed); } XYZ plannarDirection = XYZ.BasisZ; XYZ plannarOrigin = XYZ.Zero; // interate on the only face foreach (Reference currentFaceRef in TopFacesReferences) { GeometryObject currentFaceObj = selectedBuildingPad.GetGeometryObjectFromReference(currentFaceRef); if (currentFaceObj is PlanarFace) { PlanarFace currentPlanarFace = currentFaceObj as PlanarFace; plannarDirection = currentPlanarFace.FaceNormal; plannarOrigin = currentPlanarFace.Origin; PadBoundaryLoops = currentPlanarFace.GetEdgesAsCurveLoops(); } else { message = Properties.Messages.SlopeGradingFromPads_UpperFaceNotPlanar; return(Result.Failed); } } //Sort the curves so the outer loop comes first IList <IList <CurveLoop> > curveLoopLoop = ExporterIFCUtils.SortCurveLoops(PadBoundaryLoops); if (curveLoopLoop.Count > 0) { IList <CurveLoop> firstList = curveLoopLoop.First(); if (firstList.Count > 0) { outerLoop = firstList.First(); } } if (outerLoop == null) { message = Properties.Messages.SlopeGradingFromPads_OuterLoopIssue; return(Result.Failed); } //This will be the list of elements that the ReferenceIntersector will shoot the rays //If we try to shoot the rays only in the toposurface and the it has subregions, the reference //intersection will not recognize these regions, so its necessary to shoot rays to the surface and its subregions IList <ElementId> currentSubRegionsAndSurface = currentTopo.GetHostedSubRegionIds(); currentSubRegionsAndSurface.Add(topoElementID); //Search for the max distance from the Pad to the topography //Doesnt matter if it is upwards or downwards, but we will check that, since the ray has to go to one direction //This is to estabilish what the distance will be using to create the slope to the right amount ReferenceIntersector topoRefIntersec = new ReferenceIntersector(currentSubRegionsAndSurface, FindReferenceTarget.Mesh, current3dView); double maxDist = double.NegativeInfinity; foreach (Curve currentCurve in outerLoop) { int numberOfInteractions = 0; double increaseAmount = 0; double currentParameter = 0; EstabilishInteractionPoints(currentCurve, maxPointDistInFeet, out numberOfInteractions, out increaseAmount); for (int i = 0; i < numberOfInteractions; i++) { if (i == 0) { currentParameter = 0; } else { currentParameter += increaseAmount; } XYZ currentPointToEvaluate = currentCurve.Evaluate(currentParameter, true); ReferenceWithContext currentRefContext = topoRefIntersec.FindNearest(currentPointToEvaluate, XYZ.BasisZ); if (currentRefContext == null) { currentRefContext = topoRefIntersec.FindNearest(currentPointToEvaluate, XYZ.BasisZ.Negate()); } if (currentRefContext == null) { continue; } double currentDist = currentRefContext.Proximity; if (currentDist > maxDist) { maxDist = currentDist; } } } // if we haven't changed the maxdist yet, something went wrong if (maxDist == double.NegativeInfinity) { message = Properties.Messages.SlopeGradingFromPads_NoTopoAssociate; return(Result.Failed); } //Estabilish the offset from the pad double offsetDist = maxDist / Math.Tan(targetAngleInRadians); using (TopographyEditScope topoEditGroup = new TopographyEditScope(doc, Properties.Messages.SlopeGradingFromPads_Transaction)) { topoEditGroup.Start(topoElementID); using (Transaction t = new Transaction(doc, Properties.Messages.SlopeGradingFromPads_Transaction)) { t.Start(); CurveLoop offsetLoop = null; try { offsetLoop = CurveLoop.CreateViaOffset(outerLoop, offsetDist, plannarDirection); } catch { message += Properties.Messages.SlopeGradingFromPads_OuterOffsetLoopIssue; return(Result.Failed); } #region DebugCurve Loop //Plane p = new Plane(plannarDirection, plannarOrigin); //SketchPlane sktP = SketchPlane.Create(doc, p); //foreach (Curve currentOffsetCurve in offsetLoop) //{ // doc.Create.NewModelCurve(currentOffsetCurve, sktP); //} #endregion foreach (Curve currentOffsetCurve in offsetLoop) { int numberOfInteractions = 0; double increaseAmount = 0; double currentParameter = 0; EstabilishInteractionPoints(currentOffsetCurve, maxPointDistInFeet, out numberOfInteractions, out increaseAmount); for (int i = 0; i < numberOfInteractions; i++) { if (i == 0) { currentParameter = 0; } else { currentParameter += increaseAmount; } XYZ currentPointOffset = currentOffsetCurve.Evaluate(currentParameter, true); ReferenceWithContext currentRefContext = topoRefIntersec.FindNearest(currentPointOffset, XYZ.BasisZ); if (currentRefContext == null) { currentRefContext = topoRefIntersec.FindNearest(currentPointOffset, XYZ.BasisZ.Negate()); } //if we couldn't find points upwards and downwards, the topo is near the border, so we cant add points if (currentRefContext == null) { continue; } Reference currentReference = currentRefContext.GetReference(); XYZ currentPointToAdd = currentReference.GlobalPoint; if (currentTopo.ContainsPoint(currentPointToAdd)) { continue; } IList <XYZ> ListPointToAdd = new List <XYZ>(); ListPointToAdd.Add(currentPointToAdd); currentTopo.AddPoints(ListPointToAdd); } } foreach (Curve currentCurve in outerLoop) { int numberOfInteractions = 0; double increaseAmount = 0; double currentParameter = 0; EstabilishInteractionPoints(currentCurve, maxPointDistInFeet, out numberOfInteractions, out increaseAmount); for (int i = 0; i < numberOfInteractions; i++) { if (i == 0) { currentParameter = 0; } else { currentParameter += increaseAmount; } XYZ currentPointToAdd = currentCurve.Evaluate(currentParameter, true); if (currentTopo.ContainsPoint(currentPointToAdd)) { continue; } IList <XYZ> ListPointToAdd = new List <XYZ>(); ListPointToAdd.Add(currentPointToAdd); currentTopo.AddPoints(ListPointToAdd); } } t.Commit(); } topoEditGroup.Commit(new TopographyFailurePreprocessor()); return(Result.Succeeded); } }