Vector3d.PerpendicularTo Method Elegance

I’ve managed to get this working, but feel I’ve gone the long way around, and not really got the satisfaction of knowing why it’s right / was wrong.

# Perpendicular Vectors
import rhinoscriptsyntax as rs
import Rhino

vector = rs.VectorCreate( [0,0,0] , [2,10,0] )
vector_perp = Rhino.Geometry.Vector3d(vector) #New instance
vector_perp.PerpendicularTo(vector_perp) # Operate on copy vs original

print vector
print vector_perp


I thought the below would have worked. But I got an exception for only providing one argument when two were required. Documentation says there is one parameter though for perpTo, ‘other’, and I can’t see how I’ve used two arguments when it worked.

# Thought it was good, Except it wasn't
import rhinoscriptsyntax as rs
import Rhino

vector = rs.VectorCreate( [0,0,0] , [2,10,0] )
vector_perp = Rhino.Geometry.Vector3d.PerpendicularTo(vector)


The thing is, PerpendicularTo mutates its first argument, and returns bool. In your first snippet you are calling it as an instance method of vector_perp, and in the second python is complaining because you are calling it without an instance, when it expects an explicit first self argument. See if this helps explain:

# calling instance method
x = Rhino.Geometry.Vector3d(1, 0, 0)
y = Rhino.Geometry.Vector3d(0, 1, 0)
ok = x.PerpendicularTo(y)
print("ok: %s, x: %s, y: %s"% (ok, x, y))

# calling instance method as static by providing explicit self
x = Rhino.Geometry.Vector3d(1, 0, 0)
y = Rhino.Geometry.Vector3d(0, 1, 0)
ok = Rhino.Geometry.Vector3d.PerpendicularTo(x, y)
print("ok: %s, x: %s, y: %s"% (ok, x, y))

This makes some sense, and with some print statements I noticed the mutation that was going on. Then it got a bit confusing as to which vector was being changed, the documentation threw me off ( ‘this’ to ‘another’ … which to what :sob: )

I think what I’ve overlooked is that my ‘starting point’ is two Point3d; I can simply treat them as Vector3d … although it isn’t what my mind would rush to immediately, even though I know a point describes a vector assuming it’s to that point from [0,0,0]. The centre of the transformation I’m doing isn’t from the origin though. This is all for a perpendicular plane, also.

So my desire to explicitly declare vector = rs.VectorCreate( [0,0,0] , [2,10,0] ) seems to be hampering me.

And so also with your example, the x vector is basically a redundant vector that can be set to anything?

I’m not really sure what you are asking, but I think of the difference between points & vectors as the difference ordinal & cardinal numbers, where a point refers to a specific location in space, and a vector describes only a direction & magnitude. So your use of rs.VectorCreate here is the same as saying Vector(-2,-10,0), since you are passing zero to VectorCreate as the to point.

In the example, x can be anything since it will be altered by the call.

1 Like

This method is not static, meaning you need to call it on an instance of a vector object so it can operate on that data. It also returns a boolean value if it is perpendicular to the input vector.

*Note: you can also create a Vector by subtracting two Points

Point3d a = new Point3d(1,2,8);
Point3d b = new Point3d(6,2,1);

Vector3d vecA = a-b; // b-a will be reversed
Vector3d vecB = Vector3d.ZAxis;

bool perp = vecA.PerpendicularTo(VecB)
if(perp) Print("VecA is orthogonal to VecB");
else Print("VecA is not orthogonal to VecB");

//bool perp = vecA.PerpendicularTo(VecB, 0.01) takes a tolerance

So yes, vectors are not points, they have magnitudes and directions and you can do many important geometrical operations with them.

1 Like

I only see that on the IsPerpendicularTo method - is it for PerpendicularTo as well? Main takeaway is to learn applications of Static and Non-Static better, anyway.

I think this answers it for me anyway, that I hadn’t missed a neater way than declaring a placeholder vector (x) and mutating to be perp to (y), as opposed to ‘declaring(x), which is just perpendicular version of (y)’?

# Plane Definition
length_vector = rs.VectorCreate(extremities [0], length_midpoint) # midpoint to extreme
length_vector_perp = Rhino.Geometry.Vector3d(length_vector) # Placeholder Vector
length_vector_perp.PerpendicularTo(length_vector_perp) # perp dir from mid

vector_dir = Rhino.Geometry.Plane( length_midpoint , length_vector_perp , length_vector ) 
transformation_matrix = Rhino.Geometry.Transform.Scale(vector_dir, 1, scale_factor, 1) # 1 for holding
# Transform.Scale Method (Plane, Double, Double, Double) Custom X / Y / Z dir
transformed = rs.TransformObject(base_pattern_curve, transformation_matrix, copy=True)

So it’s defining a 1d scale, starting from Midpoint of a line which is drawn between the Y extremes of a closed curve. The scale_factor is driven by what the length between the Y extremes of the next object needs to be. (Y2 / Y1 = ~ 1.05, or whatever)

Yes, sorry, my typo there PerpendicularTo does not have an overload
I edited my answer to correct this, to not confuse other readers.

So overload means that it can accept different types of input/arguments? (In simple terms)

From Google - more than one method having the same name, if their argument lists are different

Yes, this is something in OOP independent of the programming language that implements OOP

Makes perfect sense. That’s a nice ‘big word alert’ to overcome, so thank you.