From: Bruce S. <bas...@nc...> - 2010-09-11 22:34:02
|
There are two answers to your question. One answer is that there is indeed a hidden user scaling factor based on the user's mouse operations. I confess I don't understand all of the design issues, but the last time I talked with David Scherer, the creator of Visual, he suggested creating a "reset" function (or some such name) whose arguments would be all of the view elements: camera position, center, forward, and field of view (of course, any element not reset would retain its current value). Presumably you could specify range instead of camera position and field of view. The point would be to make sure in one statement (running in the computational thread) that all the view status was set at once, so that you wouldn't get garbled renderings. This isn't an issue with non-real-time applications such as Pov-Ray. The other answer is to handle the user zoom and spin yourself. I've appended a program that does that. Pressing f or g does what you want and expect. I'll put a version of this in the contributed section of vpython.org. Bruce Sherwood -------------------------------------- import visual vs = visual.scene vs.userzoom = False vs.userspin = False vs.range = 2 visual.box(color=visual.color.red) visual.arrow(pos=(0,.5,0), axis=(0,1,0), color=visual.color.green) visual.arrow(pos=(.5,0,0), axis=(1,0,0), color=visual.color.cyan) zoom = False spin = False rangemin = .5 rangemax = 20 while True: visual.rate(50) if vs.kb.keys: k = vs.kb.getkey() if k == 'f': vs.range = 5 elif k == 'g': vs.range = 3 elif vs.mouse.events: m = vs.mouse.getevent() if m.drag == 'middle': zoom = True lasty = m.pos.y elif m.drop == 'middle': zoom = False elif m.drag == 'right': spin = True lastray = vs.mouse.ray elif m.drop == 'right': spin = False elif zoom: newy = vs.mouse.pos.y if newy != lasty: distance = (vs.center-vs.mouse.camera).mag scaling = 10**((lasty-newy)/distance) newrange = scaling*vs.range.y if rangemin < newrange < rangemax: vs.range = newrange lasty = scaling*newy elif spin: newray = vs.mouse.ray dray = newray-lastray right = vs.forward.cross(vs.up).norm() # unit vector to the right up = right.cross(vs.forward).norm() # unit vector upward anglex = -4*visual.arcsin(dray.dot(right)) newforward = visual.vector(vs.forward) newforward = visual.rotate(newforward, angle=anglex, axis=vs.up) newray = visual.rotate(newray, angle=anglex, axis=vs.up) angley = 4*visual.arcsin(dray.dot(up)) maxangle = vs.up.diff_angle(newforward) if not (angley >= maxangle or angley <= maxangle-visual.pi): newforward = visual.rotate(newforward, angle=angley, axis=right) newray = visual.rotate(newray, angle=angley, axis=right) vs.forward = newforward lastray = newray On Fri, Sep 10, 2010 at 2:19 PM, Aaron Mavrinac <mav...@gm...> wrote: > Hi, > > I have an application which requires me to view a scene from a > particular point in space (pointed along a particular axis). Suppose I > want the camera at point (a, b, c), pointed at (d, e, f). This may > occur at any point in the program -- i.e., I want the ability to > rotate and zoom the scene freely before jumping into this view. > > First, I set display.center = (d, e, f). Then, I set display.forward > to something like (d, e, f) - (a, b, c). This gives me the correct > axis, but the actual position of the camera along that axis (i.e. the > "zoom" level, or range/scale) is incorrect, and appears somehow linked > to whatever my range/scale was before I switched to that view. > > >From what I understand, the magnitude of display.forward ought to put > the camera at the appropriate distance from display.center. > > I also tried explicitly setting display.range, based on a complex set > of calculations involving the relative position of the center and the > field of view, and while I am somewhat encouraged that this gives me > the same result as the simpler solution above, it's still not the > correct result. > > I suspect, if I am not misunderstanding something, that there may be > some issue with how Visual is storing the current position when the > user rotates and zooms with the mouse. Take the following short > program: > > import visual > visual.box() > while True: > visual.rate(50) > if visual.scene.kb.keys: > k = visual.scene.kb.getkey() > if k == 'f': > visual.scene.range = 5 > elif k == 'g': > visual.scene.range = 3 > > Running this gives the following results: > > F - the box zooms out to size A > G - the box zooms in a bit, to size B > F - the box zooms out, back to size A > <mouse zoom> - the box zooms out to size C > F - the box remains at size C > G - the box zooms in a bit, to size D (!= B) > F - the box zooms out, back to size C > > I would have expected from the documentation that, assuming the only > mouse interaction is zooming, hitting F again should return the box to > size A -- in other words, that the range/scale is absolute. > > If this is buggy behavior, is there a fix or workaround? If this is > the expected behavior, how can I achieve what I am trying to do above? > > -- > Aaron Mavrinac > www.mavrinac.com |