0
$\begingroup$

Building on this question here

I have the range, in radians, of an angle formed by three points on a 2d plane and need to find the opposite range as shown here as range2: enter image description here

The function I am using (from the previous question) looks like this

    def anglexy(self, a, b):
        vec0 = Vector((1,0,0))
        vecQ = Vector(    (b[0]-a[0], 0, b[1]-a[1])    )

        rad =  vec0.angle(vecQ)
    
        return rad

It's called like this:

    a1 = self.anglexy(v3,v2)
    a2 = self.anglexy(v3,v1)

To be clear, when I say 'range' I mean that I can use any radian value between a1 and a2 as a rotation value with bpy.ops.transform.rotate(value=a, center_override=v3) and it will place vertices on the range1 or range2 curves.

$\endgroup$
7
  • 1
    $\begingroup$ Have a look at blender.stackexchange.com/a/203355/15543 $\endgroup$
    – batFINGER
    Dec 19, 2020 at 12:38
  • $\begingroup$ @batFINGER The edgeangle function used in that answer is far beyond my math ability -- likely because the question is much more complicate. The if branch with the negate() call makes it look like he's using the whole circle then omitting the results in the acute range? $\endgroup$ Dec 19, 2020 at 13:02
  • 1
    $\begingroup$ Think of it like walking around a table with left hand on surface. The table's up is face normal, our up (or the corner's up going thru v3 in question) is axis. A certain condition flipped axis, making us upside down, the test and negate fixed this. The main gist is need some reference to get the angle into 2d and hence get a signed value. $\endgroup$
    – batFINGER
    Dec 19, 2020 at 13:08
  • $\begingroup$ If the whole circle is 360 or -pi, pi in radians, shouldn't you be able to just subtract the first angle from 360 and then project that distance from v2 to v1 instead of v1 to v2? $\endgroup$ Dec 19, 2020 at 13:12
  • $\begingroup$ I've been tryin to do this and it works sometimes but there are so many corner cases. I don't really understand blender's angle system very well thought there might be an easier way built in. $\endgroup$ Dec 19, 2020 at 13:13

1 Answer 1

2
$\begingroup$

Revisit Previous question

Python: Calculate angle between vertices

The answer: Interior Face Angles

Think of it like walking around a table with left hand on surface. The table's up is face normal, our up (or the corner's up going thru v3 in question) is axis. A certain condition flipped axis, making us upside down, the test and negate fixed this. The main gist is need some reference to get the angle into 2d and hence get a signed value.

The verts are ordered the choice is which side of the line of verts is the table top (or face). We need some reference ie since the projection is onto Y plane would use Y or -Y axis as a proxy for face normal (in front view -Y is coming at us).

In the other question, if edges are made from the verts in x order, if the area below is a "face" with normal pointing at us (front view) then we are going clockwise, if above counter clockwise around the face.

Signed angle of 2D vectors.

Simple example, 2 points (p1, p2) and an origin point o If the 2d vectors represent the xy plane, the origin in middle, then this is y axis (12 o'clock) to (1, 1) (half past one). Travelling clockwise it's 45 degrees, counter clockwise 315

import bpy
from mathutils import Vector
from math import degrees, pi

context = bpy.context

o = Vector((0, 0))
p1 = Vector((0, 1))
p2 = Vector((1, 1))
#p1, p2 = p2, p1 # flipped
v1 = p1 - o
v2 = p2 - o

# if in z=0 plane this is axis of rotation
axis = v1.to_3d().cross(v2.to_3d())

a1 = v1.angle_signed(v2)

if a1 <= 0:
    a2 = 2 * pi + a1
else:
    a2 = a1 - 2 * pi
    
print(degrees(a1), degrees(a2))

# Results
#45.00000125223908 -314.9999987477609
#-45.00000125223908 314.9999987477609 flipped

So to re-iterate need to know what direction to go in. Assuming clockwise then return positive result above, p1 -> p2 is 45 degs, p2 -> p1 is 315.

but the range values do not work and I can't explain why. uniform(a1, a2) in a loop produces a complete circle

The angles are how far to rotate from p1 to get to p2 either the short way or the long way. Adding them together (range) is effectively adding questions two ranges together.

The only thing I can think of is that v1, v2, v3 positions, relative to one another, are variable and can occur in different orders.

Yes. It is clear in face edge angle answer link that the order is known. In this case it is not.

To get to p2 from p1 either rotate relative to p1 range (0, a1) or (0, a2)

3D Vectors

Can calculate the rotation difference between two vectors as a quaternion, ie how much to rotate vector to get to match alignment of other vector.

import bpy
from mathutils import Vector
from math import degrees, pi

context = bpy.context

o = Vector((1, 1, 1))

p1 = Vector((2, 3, 4))
p2 = Vector((5, 1, 5))

v1 = p1 - o
v2 = p2 - o

# to rotate v1 to v2

axis, angle = v1.rotation_difference(v2).to_axis_angle()

print(axis, degrees(angle))

if angle <= 0:
    angle2 = 2 * pi + angle
else:
    angle2 = angle - 2 * pi
    
print(degrees(angle2))

output

<Vector (0.5774, 0.5774, -0.5774)> 40.89339099490394
-319.10660900509606

Rotate about a pivot point

Recommend look at answer here https://blender.stackexchange.com/a/194802/15543 re making a matrix to rotate about a pivot point.

The example above gives us the angle and axis required to make the rotation matrix R

R = Matrix.Rotation(angle, 4, axis)

the direction of this rotation is determined by the sign of angle and the way the axis is pointing.

$\endgroup$
4
  • $\begingroup$ This all looks like it should be correct -- but the range values do not work and I can't explain why. uniform(a1, a2) in a loop produces a complete circle $\endgroup$ Dec 20, 2020 at 3:48
  • $\begingroup$ The only thing I can think of is that v1, v2, v3 positions, relative to one another, are variable and can occur in different orders. For this reason, perhaps the directions calculations are being thrown off? $\endgroup$ Dec 20, 2020 at 3:50
  • $\begingroup$ The issue I'm trying to go from the start of a1 to a2 -- not from 0 to a1 or zero to a2. I am trying to find all the points on the blue curve in the drawing. $\endgroup$ Dec 21, 2020 at 2:25
  • $\begingroup$ I was using a similar math.pi*2 to get there but my errors were probably in direction and the signed function should solve that. I will eventually need to do this in 3d possibly but I will deal with that another time $\endgroup$ Dec 21, 2020 at 2:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .