Site Tools


Differences

This shows you the differences between two versions of the page.

Link to this comparison view

developer:rhinocommonsamples:elevation [2015/09/14]
developer:rhinocommonsamples:elevation [2020/08/14] (current)
Line 1: Line 1:
 +===== Sample: Furthest Z value on Surface for Given X,Y =====
 +
 +===== C# =====
 +<code c#>
 +[System.Runtime.InteropServices.Guid("F26DAC86-F6D6-46D7-9796-8770E6B51F18")]
 +public class FurthestZOnSurfaceCommand : Command
 +{
 +  public override string EnglishName { get { return "csFurthestZOnSurfaceGivenXY"; } }
 +
 +  protected override Result RunCommand(RhinoDoc doc, RunMode mode)
 +  {
 +    #region user input
 +    // select a surface
 +    var gs = new GetObject();
 +    gs.SetCommandPrompt("select surface");
 +    gs.GeometryFilter = ObjectType.Surface;
 +    gs.DisablePreSelect();
 +    gs.SubObjectSelect = false;
 +    gs.Get();
 +    if (gs.CommandResult() != Result.Success)
 +      return gs.CommandResult();
 +    // get the brep
 +    var brep = gs.Object(0).Brep();
 +    if (brep == null)
 +      return Result.Failure;
 +
 +    // get X and Y
 +    double x = 0.0, y = 0.0;
 +    var rc = RhinoGet.GetNumber("value of X coordinate", true, ref x);
 +    if (rc != Result.Success)
 +      return rc;
 +    rc = RhinoGet.GetNumber("value of Y coordinate", true, ref y);
 +    if (rc != Result.Success)
 +      return rc;
 +    #endregion
 +    
 +    // an earlier version of this sample used a curve-brep intersection to find Z
 +    //var maxZ = maxZIntersectionMethod(brep, x, y, doc.ModelAbsoluteTolerance);
 +
 +    // projecting points is another way to find Z
 +    var maxZ = maxZProjectionMethod(brep, x, y, doc.ModelAbsoluteTolerance);
 +
 +    if (maxZ != null)
 +    {
 +      RhinoApp.WriteLine(string.Format("Maximum surface Z coordinate at X={0}, Y={1} is {2}", x, y, maxZ));
 +      doc.Objects.AddPoint(new Point3d(x, y, maxZ.Value));
 +      doc.Views.Redraw();
 +    }
 +    else
 +      RhinoApp.WriteLine(string.Format("no maximum surface Z coordinate at X={0}, Y={1} found.", x, y));
 +
 +    return Result.Success;
 +  }
 +
 +  private double? maxZProjectionMethod(Brep brep, double x, double y, double tolerance)
 +  {
 +    double? maxZ = null;
 +    var breps = new List<Brep> {brep};
 +    var points = new List<Point3d> {new Point3d(x, y, 0)};
 +    // grab all the points projected in Z dir.  Aggregate finds furthest Z from XY plane
 +    try {
 +      maxZ = (from pt in Intersection.ProjectPointsToBreps(breps, points, new Vector3d(0, 0, 1), tolerance) select pt.Z)
 +              // Here you might be tempted to use .Max() to get the largest Z value but that doesn't work because
 +              // Z might be negative.  This custom aggregate returns the max Z independant of the sign.  If it had a name
 +              // it could be MaxAbs()
 +              .Aggregate((z1, z2) => Math.Abs(z1) > Math.Abs(z2) ? z1 : z2);
 +    } catch (InvalidOperationException) {/*Sequence contains no elements*/}
 +    return maxZ;
 +  }
 +
 +  private double? maxZIntersectionMethod(Brep brep, double x, double y, double tolerance)
 +  {
 +    double? maxZ = null;
 +
 +    var bbox = brep.GetBoundingBox(true);
 +    var maxDistFromXY = (from corner in bbox.GetCorners() select corner.Z)
 +                        // furthest Z from XY plane.
 +                        // Here you might be tempted to use .Max() to get the largest Z value but that doesn't work because
 +                        // Z might be negative.  This custom aggregate returns the max Z independant of the sign.  If it had a name
 +                        // it could be MaxAbs()
 +                        .Aggregate((z1, z2) => Math.Abs(z1) > Math.Abs(z2) ? z1 : z2);
 +    // multiply distance by 2 to make sure line intersects completely
 +    var lineCurve = new LineCurve(new Point3d(x, y, 0), new Point3d(x, y, maxDistFromXY*2));
 +
 +    Curve[] overlapCurves;
 +    Point3d[] interPoints;
 +    if (Intersection.CurveBrep(lineCurve, brep, tolerance, out overlapCurves, out interPoints))
 +    {
 +      if (overlapCurves.Length > 0 || interPoints.Length > 0)
 +      {
 +        // grab all the points resulting frem the intersection. 
 +        //    1st set: points from overlapping curves, 
 +        //    2nd set: points when there was no overlap
 +        //    .Aggregate: furthest Z from XY plane.
 +        maxZ = (from c in overlapCurves select Math.Abs(c.PointAtEnd.Z) > Math.Abs(c.PointAtStart.Z) ? c.PointAtEnd.Z : c.PointAtStart.Z)
 +               .Union
 +               (from p in interPoints select p.Z)
 +                // Here you might be tempted to use .Max() to get the largest Z value but that doesn't work because
 +                // Z might be negative.  This custom aggregate returns the max Z independant of the sign.  If it had a name
 +                // it could be MaxAbs()
 +               .Aggregate((z1, z2) => Math.Abs(z1) > Math.Abs(z2) ? z1 : z2);
 +      }
 +    }
 +    return maxZ;
 +  }
 +}
 +</code>
 +===== VB.NET =====
 +<code vb>
 +<System.Runtime.InteropServices.Guid("61256DAE-8491-4D18-B757-70212215CB29")> _
 +Public Class FurthestZOnSurfaceCommand
 +  Inherits Command
 +  Public Overrides ReadOnly Property EnglishName() As String
 +    Get
 +      Return "vbFurthestZOnSurfaceGivenXY"
 +    End Get
 +  End Property
 +
 +  Protected Overrides Function RunCommand(doc As RhinoDoc, mode As RunMode) As Result
 +    '#Region "user input"
 +    ' select a surface
 +    Dim gs = New GetObject()
 +    gs.SetCommandPrompt("select surface")
 +    gs.GeometryFilter = ObjectType.Surface
 +    gs.DisablePreSelect()
 +    gs.SubObjectSelect = False
 +    gs.[Get]()
 +    If gs.CommandResult() <> Result.Success Then
 +      Return gs.CommandResult()
 +    End If
 +    ' get the brep
 +    Dim brep = gs.[Object](0).Brep()
 +    If brep Is Nothing Then
 +      Return Result.Failure
 +    End If
 +
 +    ' get X and Y
 +    Dim x As Double = 0.0, y As Double = 0.0
 +    Dim rc = RhinoGet.GetNumber("value of X coordinate", True, x)
 +    If rc <> Result.Success Then
 +      Return rc
 +    End If
 +    rc = RhinoGet.GetNumber("value of Y coordinate", True, y)
 +    If rc <> Result.Success Then
 +      Return rc
 +    End If
 +    '#End Region
 +
 +    ' an earlier version of this sample used a curve-brep intersection to find Z
 +    'var maxZ = maxZIntersectionMethod(brep, x, y, doc.ModelAbsoluteTolerance);
 +
 +    ' projecting points is another way to find Z
 +    Dim maxZ = maxZProjectionMethod(brep, x, y, doc.ModelAbsoluteTolerance)
 +
 +    If maxZ IsNot Nothing Then
 +      RhinoApp.WriteLine(String.Format("Maximum surface Z coordinate at X={0}, Y={1} is {2}", x, y, maxZ))
 +      doc.Objects.AddPoint(New Point3d(x, y, maxZ.Value))
 +      doc.Views.Redraw()
 +    Else
 +      RhinoApp.WriteLine(String.Format("no maximum surface Z coordinate at X={0}, Y={1} found.", x, y))
 +    End If
 +
 +    Return Result.Success
 +  End Function
 +
 +  Private Function maxZProjectionMethod(brep As Brep, x As Double, y As Double, tolerance As Double) As System.Nullable(Of Double)
 +    Dim maxZ As System.Nullable(Of Double) = Nothing
 +    Dim breps = New List(Of Brep)() From { _
 +      brep _
 +    }
 +    Dim points = New List(Of Point3d)() From { _
 +      New Point3d(x, y, 0) _
 +    }
 +    ' grab all the points projected in Z dir.  Aggregate finds furthest Z from XY plane
 +    Try
 +      maxZ = (From pt In Intersection.ProjectPointsToBreps(breps, points, New Vector3d(0, 0, 1), tolerance) Select pt.Z).Aggregate(Function(z1, z2) If(Math.Abs(z1) > Math.Abs(z2), z1, z2))
 +      'Sequence contains no elements
 +    Catch generatedExceptionName As InvalidOperationException
 +    End Try
 +    Return maxZ
 +  End Function
 +
 +  Private Function maxZIntersectionMethod(brep As Brep, x As Double, y As Double, tolerance As Double) As System.Nullable(Of Double)
 +    Dim maxZ As System.Nullable(Of Double) = Nothing
 +
 +    Dim bbox = brep.GetBoundingBox(True)
 +    ' furthest Z from XY plane.  Max() doesn't work because of possible negative Z values
 +    Dim maxDistFromXY = (From corner In bbox.GetCorners() Select corner.Z).Aggregate(Function(z1, z2) If(Math.Abs(z1) > Math.Abs(z2), z1, z2))
 +    ' multiply distance by 2 to make sure line intersects completely
 +    Dim lineCurve = New LineCurve(New Point3d(x, y, 0), New Point3d(x, y, maxDistFromXY * 2))
 +
 +    Dim overlapCurves As Curve()
 +    Dim interPoints As Point3d()
 +    If Intersection.CurveBrep(lineCurve, brep, tolerance, overlapCurves, interPoints) Then
 +      If overlapCurves.Length > 0 OrElse interPoints.Length > 0 Then
 +        ' grab all the points resulting frem the intersection. 
 +        '    1st set: points from overlapping curves, 
 +        '    2nd set: points when there was no overlap
 +        '    .Aggregate: furthest Z from XY plane.
 +        Dim overlapCrvsZs As IEnumerable(Of Double) = (From c In overlapCurves Select DirectCast(IIf(Math.Abs(c.PointAtEnd.Z) > Math.Abs(c.PointAtStart.Z), c.PointAtEnd.Z, c.PointAtStart.Z), Double))
 +        Dim intersectPtsZs As IEnumerable(Of Double) = (From p In interPoints Select p.Z)
 +        Dim allZs = overlapCrvsZs.Union(intersectPtsZs).ToArray()
 +        maxZ = allZs.Aggregate(Function(runZ, nextZ) DirectCast(IIf(Math.Abs(runZ) > Math.Abs(nextZ), runZ, nextZ), Double))
 +      End If
 +    End If
 +    Return maxZ
 +  End Function
 +End Class
 +d Namespace
 +</code>
 +===== Python =====
 +<code python>
 +import rhinoscriptsyntax as rs
 +from Rhino.Geometry import Intersect, Point3d, Vector3d
 +from scriptcontext import doc
 +
 +def RunCommand():
 +  # select a surface
 +  srfid = rs.GetObject("select serface", rs.filter.surface | rs.filter.polysurface)
 +  if not srfid: return
 +  # get the brep
 +  brep = rs.coercebrep(srfid)
 +  if not brep: return
 +
 +  x = rs.GetReal("value of x", 0)
 +  y = rs.GetReal("value of y", 0)
 +
 +  pts = [(abs(point.Z), point.Z) for point in Intersect.Intersection.ProjectPointsToBreps(
 +           [brep], [Point3d(x, y, 0)], Vector3d(0, 0, 1), doc.ModelAbsoluteTolerance)]
 +           
 +  pts.sort(reverse=True)
 +  
 +  if pts == []:
 +    print "no Z for given X, Y"
 +  else:
 +    rs.AddPoint(Point3d(x, y, pts[0][1]))
 +
 +if __name__ == "__main__":
 +  RunCommand()
 +</code>
 +
 +{{tag>Developer rhinocommon}}