Mathematical constraint

Ok, I have a 3D cursor that shows up where the cursor ray collides with a mesh. It works real swell, but now I want to constrain the max distance that the 3D cursor can travel from the camera.

So basically,

If 3D cursor distance > bound:
Relocate to distance equal to bound
Else:
Set location to collision point as usual

Here is the code and I’m pretty sure that theoretically, it should work. I don’t know any simple 3D formulas, so I calculate the hypotenuse of the triangle in the XY plane plus it’s angle, then calculate the angle for the “HZ” (H=hypotenuse of tri. in XY plane) triangle using the Hypotenuse of the XY triangle. I then use that information and calculate the new coordinates of the 3D cursor within the bound.

Right now, the cursor pretty much disappears from the view when it passes the bound…

Here is my script:

    def mousePlacer(self,task):
        
        bound=15        #Max dist of 3D cursor from camera

        mpos=base.mouseWatcherNode.getMouse()
        pickerRay.setFromLens(base.camNode,
                              mpos.getX(),
                              mpos.getY())
        myTraverser.traverse(render)
        
        if myHandler.getNumEntries() > 0:
            collisionPoint = myHandler.getEntry(0).getSurfacePoint(render)
            
            # Make x,y,z coordinates relative to cam pos
            camPos = camera.getPos()
            x=collisionPoint[0]-camPos[0]
            y=collisionPoint[1]-camPos[1]
            z=collisionPoint[2]-camPos[2]

            h=math.sqrt(x**2+y**2) #Find hypotenuse in XY plane
            aXY=math.atan(y/x) #Find angle in XY plane
            aHZ=math.atan(z/h) #Find angle on HZ plane
            distCursor=math.sqrt(x**2+y**2+z**2)

            #Calculate new coordinates within 'bound' from cam
            if distCursor>bound:
                z=bound*math.sin(aHZ)
                h=bound*math.cos(aHZ)
                y=h*math.sin(aXY)
                x=h*math.cos(aXY)

                self.axis.setPos(x,y,z)
            else:
                self.axis.setPos(collisionPoint[0],
                                 collisionPoint[1],
                                 collisionPoint[2])

        return task.cont

I know this is my 3rd post in the last few days, but I honestly won’t post unless I have slayed over the issue for hours. :blush:

        if myHandler.getNumEntries() > 0:

So if you don’t mouseover an object there is no cursor?

Sammual

Quick question.

Instead of all the math why don’t you just have a transparent sphere around the camera with a radius of 15?

Example

Start Task mousePlacer
Create Sphere
Get collisionPoint
Set Cursor to collisionPoint
Remove Sphere
Return

Sammual

I haven’t changed the line "getNumEntries() > 0: " because I don’t know what to do yet if there isn’t a collision. I am glad that you pointed that out though- I forgot to make a note of it.

That’s really clever- make an invisible sphere around the camera. It actually sounds tons easier than my method. I don’t know why, but I completely forgot about using the collision solids. I originally turned down the idea because I thought I would need to use a mesh. I should probably tack a big K.I.S.S. poster on my wall… :laughing: (Keep It Simple Stupid)

Thanks, Sammual!

Also on the KISS principle (but keeping more consistent with your original design), you don’t need to mess with sines and cosines in order to shorten a vector to be no longer than a certain length. To constrain a vector to a length without changing its direction, try vector.normalize(); vector *= length. Normalizing a vector makes it length 1 (without changing its direction), and scaling it by length makes it length times longer (without changing its direction).

Also, since you want to do this work relative to the camera, why not ask for the point relative to the camera in the first place (instead of having to subtract it out later)?

# Get intersection point relative to the camera
colPoint = myHandler.getEntry(0).getSurfacePoint(camera)

# Make it a vector so we can calculate length()
colVec = Vec3(colPoint)

length = colVec.length()

# Check the distance from the camera
if length > bound:
    # Shorten the vector
    colVec.normalize()
    colVec *= bound

self.axis.setPos(camera, colVec)

David

I have studied your example a bit and placed it in my code and it works very well. I remember studying vectors a couple years ago, but forgot most of the information, but seeing how easy they make 3D operations has definitely sparked my interest.

Thanks, David!