protected override float ComputePixel(ref InstanceContext ctx) { var sd = SignedDistance.Infinite.Distance; for (var i = 0; i < Shape.Count; ++i) { var minDistance = SignedDistance.Infinite; EdgeSegment nearEdge = null; double nearParam = 0; foreach (var edge in Shape[i]) { double param = 0; var distance = edge.SignedDistance(ctx.P, ref param); if (distance < minDistance) { minDistance = distance; nearEdge = edge; nearParam = param; } } if (Math.Abs(minDistance.Distance) < Math.Abs(sd)) { sd = minDistance.Distance; ctx.Winding = -Windings[i]; } nearEdge?.DistanceToPseudoDistance(ref minDistance, ctx.P, nearParam); ContourSd[i] = new SingleDistance { Dist = minDistance.Distance }; ctx.UpdateDistance(Windings[i], minDistance.Distance); } return((float)(ComputeSd(Infinite, ref ctx).Dist / Range + 0.5)); }
public List <EdgeSegment> GetRawData(Room room, double DistanceToWall, double UnitWidth) { //Used to store the wall object. List <EdgeSegment> rSegments = new List <EdgeSegment>(); #region The basics and datas const double er = 0.0001;//used for error correction. Document doc = room.Document; Autodesk.Revit.ApplicationServices.Application app = doc.Application; //get the level height of floor and ceiling //!!!!!current not consider different ceiling height or floor.Need improving. double levelC = room.ClosedShell.GetBoundingBox().Max.Z; double levelF = room.ClosedShell.GetBoundingBox().Min.Z; //Custom input data. double dist2W = DistanceToWall; double unitW = UnitWidth; #endregion //get the boundary segments list IList <IList <BoundarySegment> > boundarys = room.GetBoundarySegments(new SpatialElementBoundaryOptions()); //Loop through all the wall segment needed to oprate on //first layer is each boundary loop(in case a room has multiple boundaries) foreach (IList <BoundarySegment> groupSegments in boundarys) { //The stack is for the segments(one wall can be several segments) //The queue is for the wall after merging the segments. Stack <EdgeSegment> eSegments = new Stack <EdgeSegment>(); List <EdgeSegment> eSegmentsMerged = new List <EdgeSegment>(); //Second layer is the actual segment //in this loop process each segment opening info and log them foreach (BoundarySegment segment in groupSegments) { #region Create the object,get the inner edge of a wall segment EdgeSegment theSeg = new EdgeSegment(); Curve segCrv = segment.GetCurve(); XYZ start = segCrv.GetEndPoint(0); XYZ end = segCrv.GetEndPoint(1); XYZ normal; theSeg.levelC = levelC; theSeg.levelF = levelF; theSeg.start = new XYZ(start.X, start.Y, levelF); theSeg.end = new XYZ(end.X, end.Y, levelF); #endregion //The boundary segment may not be a wall Element wallOrNot = doc.GetElement(segment.ElementId); #region Seperate different category(Wall,Column or others) Categories docCat = doc.Settings.Categories; ElementId idColumn = docCat.get_Item(BuiltInCategory.OST_Columns).Id; ElementId idWall = docCat.get_Item(BuiltInCategory.OST_Walls).Id; //Case 1-A column or the end of a single wall. if ((wallOrNot == null) || (wallOrNot.Category.Id.Equals(idColumn))) { //The room segments always search counterclockwise //Thus compute the normal as follow //Other data is not needed.Treat it as a full wall. XYZ line = end - start; normal = new XYZ(-line.Y, line.X, 0); theSeg.normal = normal / normal.GetLength(); eSegments.Push(theSeg); continue; } //Case 2-Not column or wall.(Most likely curtain)Mark as noPanel. if (!(wallOrNot.Category.Id.Equals(idWall))) { theSeg.NoPanel = true; eSegments.Push(theSeg); continue; } //Case 3-Walls Wall theWall = wallOrNot as Wall; #endregion #region Get the sideface of a wall and get the profile curves IList <Reference> sideFaces = HostObjectUtils.GetSideFaces(theWall, ShellLayerType.Exterior); //get the real face(why so long???) Face face = doc.GetElement(sideFaces[0]) .GetGeometryObjectFromReference(sideFaces[0]) as Face; //get edge loops as curveloops IList <CurveLoop> openLoops = face.GetEdgesAsCurveLoops(); #endregion //Some basic properties of the face. normal = face.ComputeNormal(new UV(0, 0)); Plane plane = Plane.CreateByNormalAndOrigin(normal, start); #region Check if curves are on the inner plane or not. //(Might be on the other side of the wall) //Log the correction vector in correction. Curve checkCurve = openLoops[0].GetEnumerator().Current; plane.Project(checkCurve.GetEndPoint(1), out UV uv, out double dist); Transform correction = Transform.CreateTranslation(new XYZ(0, 0, 0)); if (dist > er) //Same wired reason.See "const double er" up front. { normal = -normal; correction = Transform.CreateTranslation(dist * normal); plane = Plane.CreateByNormalAndOrigin(normal, start); } #endregion //Store all the endpoints and horizontal curves. List <XYZ> points = new List <XYZ>(); List <Curve> hoCrvs = new List <Curve>(); foreach (CurveLoop curveloop in openLoops) { foreach (Curve curve in curveloop) { points.Add(correction.OfPoint(curve.GetEndPoint(0))); //If curve is horizontal,and in the middle range,log it double cSz = curve.GetEndPoint(0).Z; double cEz = curve.GetEndPoint(1).Z; if ((Math.Abs(cSz - cEz) < er) && (cSz > levelF + er) && (cSz < levelC - er)) { hoCrvs.Add(curve.CreateTransformed(correction)); } } } #region Sort pts according to curve direction var tempPts = from point in points where ((point.Z > levelF + er) && (point.Z < levelC - er)) select new XYZ(point.X, point.Y, levelF); List <XYZ> relayPts = tempPts.ToList <XYZ>(); relayPts.Add(start); relayPts.Add(end); var sortPt = from point in relayPts where (segCrv.Distance(point) < er) orderby(point - start).GetLength() select point; List <XYZ> sortPtList = sortPt .Distinct(new PtEqualComparer()) .ToList <XYZ>(); if (!(sortPtList[0] == start)) { sortPtList.Reverse(); } sortPtList.RemoveAt(sortPtList.Count - 1); sortPtList.RemoveAt(0); #endregion #region log the data theSeg.crvList = hoCrvs; theSeg.ptList = sortPtList; theSeg.normal = normal; #endregion //Find insert element(and project on plane) List <ElementId> insertIds = theWall .FindInserts(true, true, true, true).Distinct().ToList(); foreach (ElementId eId in insertIds) { Element currentRoom = doc.GetElement(eId); BoundingBoxXYZ box = currentRoom.get_Geometry(new Options()).GetBoundingBox(); XYZ ept = 0.5 * (box.Max + box.Min); XYZ v = ept - plane.Origin; double signedDist = plane.Normal.DotProduct(v); XYZ eptnew = ept - signedDist * normal; theSeg.insertPts.Add(eptnew); } //Push to the stack. eSegments.Push(theSeg); } #region Merge from segments to walls... //Merge the segments that are on same curve. int segNum = eSegments.Count; EdgeSegment sNew; for (int i = 1; i < segNum; i++) { EdgeSegment s1 = eSegments.Pop(); EdgeSegment s2 = eSegments.Pop(); if (!(s2.MergeWith(s1, out sNew))) { eSegmentsMerged.Add(s1); } eSegments.Push(sNew); } //Compare the final one to the first one again EdgeSegment sf1 = eSegmentsMerged[0]; EdgeSegment sf2 = eSegments.Pop(); if (sf2.MergeWith(sf1, out sNew)) { eSegmentsMerged.RemoveAt(0); } eSegmentsMerged.Add(sNew); //Because the use of stack,the order need to be reversed back. eSegmentsMerged.Reverse(); #endregion #region Set the offset for each corner according to dist2W int wallNum = eSegmentsMerged.Count; eSegmentsMerged.Add(eSegmentsMerged[0]); for (int i = 0; i < wallNum; i++) { EdgeSegment SegCur = eSegmentsMerged[i]; EdgeSegment SegAft = eSegmentsMerged[i + 1]; double angle = SegCur.unitV.AngleOnPlaneTo(SegAft.unitV, XYZ.BasisZ); SegCur.end -= Math.Tan(0.5 * angle) * dist2W * SegCur.unitV; SegAft.start += Math.Tan(0.5 * angle) * (dist2W + UnitUtils.ConvertToInternalUnits(10, DisplayUnitType.DUT_MILLIMETERS)) * SegAft.unitV; } eSegmentsMerged.RemoveAt(eSegmentsMerged.Count - 1); #endregion rSegments.AddRange(eSegmentsMerged); } return(rSegments); }
public EdgeHolder(EdgeSegment segment) { this.edgeSegment = segment; }