rs.Distance() Python 3 can't compute distance between points

Hi,

I recently upgraded to the latest Rhino. I get a bug with a script which worked fine on previous versions.

I can’t get Python to compute distances between 3D Points. This test script for example

#! python3

import rhinoscriptsyntax as rs
import rhinoscript.utility as rhutil

pt1 = rs.CreatePoint(1.0, 2.0, 3.0)
pt2 = rs.CreatePoint(4.0, 2.0, 3.0)

print(rs.Distance(pt1,pt2))

outputs : AttributeError: 'Point3d' object has no attribute 'Length'

I have also tried feeding rs.Distance() with an array of doubles or Point3D objects created via coerce3dpoint and got similar results.

Any idea why ?

Edit: the bug happens only with Python 3

Dunno, I get “3.0” as a result of running the script here.

By the way, you can also use dist=pt1.DistanceTo(pt2)

3 Likes

Wow that’s weird, it works with DistanceTo but not with rs.Distance - but thanks for the tip, I can fix my script now.

See below the tests

OK, I see that when running it as a P3 script in ScriptEditor. It runs fine as a P2 script.

There must be something funky with the definition in the P3 rhinoscriptsyntax code - I have no idea where this actually resides, only the P2 stuff - because the error message says this:

Distance
    if to_pt: return (to_pt - from_pt).Length
AttributeError: 'Point3d' object has no attribute 'Length'

Subtracting one point from another like this to_pt - from_pt results in a Vector3d object, which has a property .Length (the distance from A to B) which is returned. But somehow the results in P3 is that instead of returning a vector, it is returning a Point3d object - which has no length property.

@eirannejad

I came to the same conclusion.

Looks like it coerces the points, makes a vector by subtracting the two, and measures its length:

def Distance(point1, point2):
    """Measures distance between two 3D points, or between a 3D point and
    an array of 3D points.
    Parameters:
      point1 (point): The first 3D point.
      point2 (point): The second 3D point or list of 3-D points.
    Returns:
      point: If point2 is a 3D point then the distance if successful.
      point: If point2 is a list of points, then an list of distances if successful.
      None: if not successful
    Example:
      import rhinoscriptsyntax as rs
      point1 = rs.GetPoint("First point")
      if point1:
          point2 = rs.GetPoint("Second point")
          if point2:
              print "Distance: ", rs.Distance(point1, point2)
    See Also:
      Angle
      Angle2
    """
    from_pt = coerce3dpoint(point1, True)
    to_pt = coerce3dpoint(point2)
    if to_pt: return (to_pt - from_pt).Length
    # check if we have a list of points
    to_pt = coerce3dpointlist(point2, True)
    distances = [(point - from_pt).Length for point in to_pt]
    if distances: return distances

Yeah, I got that, problem is that it seems to be returning a point instead of a vector in Py3…

Check this:

#! python3

import Rhino

pt1 = Rhino.Geometry.Point3d(1.0, 2.0, 3.0)
pt2 = Rhino.Geometry.Point3d(4.0, 2.0, 3.0)

print(type(pt2-pt1))

<class 'Rhino.Geometry.Point3d'>

Something wrong there…

#! python 2

import Rhino

pt1 = Rhino.Geometry.Point3d(1.0, 2.0, 3.0)
pt2 = Rhino.Geometry.Point3d(4.0, 2.0, 3.0)

print(type(pt2-pt1))

<type 'Vector3d'>

What I meant by that is I didn’t know where the folder with the code for Py3 rhinoscriptsyntax was located. Now I found it. But the rs.Distance() method is the same in both.

1 Like

I’ve logged this issue - thanks.

https://mcneel.myjetbrains.com/youtrack/issue/RH-79852

– Dale

Including what has already been demonstrated, the following shows output type discrepancies for a couple of Python 3’s Point3d’s Subtract methods and operator overloads and one Add method overload:

3.9.10 (tags/v3.9.10:f2f3f53, Jan 17 2022, 15:14:21) [MSC v.1929 64 bit (AMD64)] 

p2 - p1  : Point3d
rg.Point3d.Subtract(p2, p1): Point3d

v2 - p1  : Vector3d
rg.Point3d.Subtract(v2, p1): Point3d

v2 + p1  : Vector3d
2.7.12 (2.7.12.1000)
[.NETCoreApp,Version=v3.1 on .NET 7.0.14 (64-bit)] 

p2 - p1  : Vector3d
rg.Point3d.Subtract(p2, p1): Vector3d

v2 - p1  : unsupported operand type(s) for -: 'Vector3d' and 'Point3d'
rg.Point3d.Subtract(v2, p1): expected Point3d, got Vector3d

v2 + p1  : Point3d

Python 2’s output matches the return values stated on:
https://developer.rhino3d.com/api/rhinocommon/rhino.geometry.point3d/-
https://developer.rhino3d.com/api/rhinocommon/rhino.geometry.point3d/subtract
https://developer.rhino3d.com/api/rhinocommon/rhino.geometry.point3d/+

Python script
from __future__ import print_function
import Rhino.Geometry as rg

import sys
print(sys.version, "\n")

def pet(s):
    """Print eval type"""
    try:
        print("{:<9}: {}".format(s, eval(s).GetType().Name))
    except Exception as e:
        print("{:<9}: {}".format(s, e))

p1 = rg.Point3d(1.0, 2.0, 3.0)
p2 = rg.Point3d(4.0, 2.0, 3.0)

v1 = rg.Vector3d(7.0, 11.0, 13.0)
v2 = rg.Vector3d(23.0, 19.0, 17.0)

pet("p2 - p1")
pet("rg.Point3d.Subtract(p2, p1)")
print('\n')
pet("v2 - p1")
pet("rg.Point3d.Subtract(v2, p1)")
print('\n')
pet("v2 + p1")
1 Like

Thank you for posting this - I was also finding this issue with rs.Distance()

2 Likes

Issue is resolved in 8.5 RC

2 Likes