Ejemplo n.º 1
0
    def absorbit(self, ref, axis, amt):
        """
        Orbit the camera around an axis passing through a reference
        point ref.
        """
        # Position the reference point in the proper plane with the camera
        # position.
        ref = ref[:axis] + (self.pos[axis],) + ref[axis + 1:]
        # Counter-rotate the camera.
        self.absrotate(axis=axis, amt=-1 * amt)

        delta = diff3D(ref, self.pos)
        r = dist3D(c=delta)

        # Cacheable: All these handled by setattr hook

        if axis == X_AXIS:
            theta = atan2(delta[Y_AXIS], delta[Z_AXIS])
            theta = theta + (self.rotateSpeed * amt * pi / 180)
            self.pos = add3D(ref, (0, r * sin(theta), r * cos(theta)))
        elif axis == Y_AXIS:
            theta = atan2(delta[Z_AXIS], delta[X_AXIS])
            theta = theta + (self.rotateSpeed * amt * pi / 180)
            self.pos = add3D(ref, (r * cos(theta), 0, r * sin(theta)))
        elif axis == Z_AXIS:
            theta = atan2(delta[X_AXIS], delta[Y_AXIS])
            theta = theta + (-1 * self.rotateSpeed * amt * pi / 180)
            self.pos = add3D(ref, (r * sin(theta), r * cos(theta), 0))
Ejemplo n.º 2
0
    def realPosition(self, camera):
        """
        Figure out the world-space coordinates of this cursor
        relative to the camera given.
        """

        from utilities import mult3D, add3D
        from camera import X_AXIS, Y_AXIS, Z_AXIS

        x = mult3D(camera.yz, self.pos[X_AXIS])
        y = mult3D(camera.up, self.pos[Y_AXIS])
        z = mult3D(camera.vpn, self.pos[Z_AXIS])
        offset = add3D(x, y)
        offset = add3D(offset, z)
        return add3D(offset, camera.pos)
Ejemplo n.º 3
0
    def vertexWarp(self, vertex, refresh=None):
        """
        Warp to vertex, using the Animator.
        """
        from utilities import add3D, diff3D, mult3D

        offset = add3D(mult3D(self.camera.vpn, -10.0), (0.0, vertex.radius * 3.0, 0.0))

        if self.showGrid:
            npos = utilities.mult3D(vertex.pos, self.spacing)
        else:
            npos = vertex.pos

        targetpos = add3D(npos, offset)

        self.parent.animator.perspCameraMove(self.camera, newPos=targetpos, newLook=npos, duration=1.0)
Ejemplo n.º 4
0
    def orbit(self, ref, axis, amt):
        """
        Orbit the camera around an axis passing through a reerence point ref -
        this one orbits relative to the camera axes
        Currently, this function has the undesirable side-effect of possibly
        breaking the "camera.yz is parallel to the world Y=0 plane" constraint,
        and should not be used unless you know what you're doing.
        """
        # Counter-rotate the camera.
        self.rotate(axis=axis, amt=amt)

        # Find the vector from the reference point to the camera
        vec = diff3D(ref, self.pos)
        # Rotate this vector around the axis
        if axis == X_AXIS:
            vec = rotate3D(vec, self.yz, amt)
        elif axis == Y_AXIS:
            vec = rotate3D(vec, self.up, amt)
        elif axis == Z_AXIS:
            vec = rotate3D(vec, self.vpn, -1 * amt)

        # Cacheable: Handled by setattr hook

        # Convert the vector into worldspace coordinates
        self.pos = add3D(ref, vec)
Ejemplo n.º 5
0
 def useTracker(self):
     """
     camera.useTracker() -> void
     Offsets the camera (should be called after use()) based
     on the current position of the tracker.
     """
     if self.trackPosOffset:
         # Calculate the offset relative to the camera - rather than relative to the world.
         x = mult3D(self.yz, self.trackPosOffset[X_AXIS])
         y = mult3D(self.up, self.trackPosOffset[Y_AXIS])
         z = mult3D(self.vpn, self.trackPosOffset[Z_AXIS])
         offset = add3D(x, y)
         offset = add3D(offset, z)
         GL.glTranslatef(*offset)
     if self.trackRotMatrix:
         GL.glMultMatrix(*self.trackRotMatrix)
Ejemplo n.º 6
0
    def inputPos(self, pos):
        """
        Translate an input device position into cursor coordinates.
        """
        from utilities import add3D, diff3D, mult3D

        self.pos = add3D(pos, DEFAULT_POS)
Ejemplo n.º 7
0
    def midpoint(self):
        """
        Edge.midpoint() -> (float,float,float)
        Returns the midpoint of this edge as a position tuple.
        """
        from utilities import add3D, div3D

        sum = add3D(self.source.pos, self.target.pos)
        return div3D(sum, 2.0)
Ejemplo n.º 8
0
 def newValue(name, iter):
     """
     This function gets called right now, and can return lambdas that
     evaluate in event time.
     """
     if name in self._moveLock:
         return self._moveLock[name]
     elif isinstance(kwargs[name], (tuple, list)):
         return lambda: add3D(getattr(self._object, name), self._moveStepVals[name])
     else:
         return lambda: getattr(self._object, name) + self._moveStepVals[name]
Ejemplo n.º 9
0
    def arrangeStepwise(self, graph, vertices, newPos, duration, wait=0.0, tween=True):
        """
        Arrange the vertices of the graph into a new layout
        specified by an indexed list of new positions newPos.
        The vertices will be positioned one at a time.
        """
        assert (len(newPos) == len(vertices))
        delay = float(duration) / len(vertices)

        from math import floor

        if tween:
            if delay > (1.0 / self.parent.fps):
                # No sense tweening faster than the frame rate can keep up
                stepsPerVert = int(floor(delay / (1.0 / self.parent.fps)))
                totalMove = [diff3D(a, b) for a, b in zip([x.pos for x in vertices], newPos)]
                partialMove = [div3D(x, stepsPerVert) for x in totalMove]
            else:
                tween = False

        accum = wait

        for i in range(len(vertices)):
            if tween:
                accum += delay / stepsPerVert
                for step in range(stepsPerVert - 1):
                    self.post(accum,
                              objects=(
                              vertices[i],
                              ),
                              props=(
                              (
                              'pos',
                              add3D(vertices[i].pos, mult3D(partialMove[i], (step + 1))),
                              ),
                              ),
                              changeGraph=graph,
                    )
                    accum += delay / stepsPerVert
            else:
                accum += delay
            self.post(accum,
                      objects=(
                      vertices[i],
                      ),
                      props=(
                      ('pos', newPos[i]),
                      ),
                      changeGraph=graph,
            )

        self.signal()
Ejemplo n.º 10
0
    def draw(self):
        import graphgl
        # Calculate snap

        point = self.ctx.cursor.realPosition(self.ctx.camera)
        if self.relative:
            from utilities import add3D

            point = add3D(point, self.offset)
        newpos = tuple([x - ((x + self.snap / 2) % self.snap - (self.snap / 2)) for x in point])
        self.vertex.pos = newpos
        self.ctx.graphgl.drawVertex(self.vertex, alpha=0.5)
        if self.updateHUD:
            self.ctx.HUDstatus = "Positioning Vertex %s: (%0.2f, %0.2f, %0.2f)" % (
            self.vertex.id, self.vertex.pos[0], self.vertex.pos[1], self.vertex.pos[2])
Ejemplo n.º 11
0
    def perspCameraLookatMove(self, camera, newPos, fixLook, duration, wait=0.0):
        """
        Moves the camera smoothly to a new position and orientation.
        If newLook is None, does not change the orientation of the camera.
        If newPos is None, does not change the position of the camera.
        """
        from camera import Camera, OrthoCamera, X_AXIS, Y_AXIS, Z_AXIS

        assert (not isinstance(camera, OrthoCamera))

        fixLook = self.normalizePos(fixLook)
        steps = int(duration * self.parent.fps)

        deltaPos = diff3D(camera.pos, newPos)
        stepPos = div3D(deltaPos, steps)

        accum = wait
        delay = 1.0 / self.parent.fps

        # Set up the animation
        for i in range(steps - 1):
            accum += delay

            self.post(accum,
                      objects=(camera,),
                      props=(
                      ( 'pos', add3D(camera.pos, mult3D(stepPos, i + 1)) ),
                      ( 'lookAt', fixLook),
                      ),
                      call=(
                      ('absrotate', (Y_AXIS, stepYaw), {}),
                      ('rotate', (X_AXIS, stepPitch), {}),
                      ),
            )

        # Finish up in the correct place
        accum += delay
        self.post(accum,
                  objects=(camera,),
                  props=(
                  ('pos', newPos),
                  ('lookAt', fixLook),
                  ),
        )

        self.signal()
Ejemplo n.º 12
0
    def arrangeMorph(self, graph, vertices, newPos, duration, wait=0.0):
        """
        Arrange the vertices of the graph into a new layout
        specified by an indexed list of new positions newPos.
        The vertices will be positioned simultaneously (smooth morph)
        """
        assert (len(newPos) == len(vertices))

        accum = wait

        steps = int(duration * self.parent.fps)
        delay = 1.0 / self.parent.fps

        d = [div3D(diff3D(a.pos, b), steps) for a, b in zip(vertices, newPos)]

        for i in range(steps - 1):
            accum += delay
            self.post(accum,
                      objects=vertices,
                      multiprops=(
                      (
                      'pos',
                      [add3D(a.pos, mult3D(b, i + 1)) for a, b in zip(vertices, d)]
                      ),
                      ),
                      changeGraph=graph,
            )

        accum += delay
        self.post(accum,
                  objects=vertices,
                  multiprops=(
                  ('pos', newPos),
                  ),
                  changeGraph=graph,
        )
        self.signal()
Ejemplo n.º 13
0
def arrangeSpring(context, axes=(X_AXIS, Z_AXIS, Y_AXIS), sync=None, edgeTension=0.85, edgeLength=3.0,
                  useAttrEdgeK=False, invAttrEdgeK=False, useAttrEdgeLen=False, invAttrEdgeLen=False):
    """
    Arrange the vertices of the graph according to a force-directed
    spring model.
    """
    EPSILON = 0.1
    JITTER = EPSILON / 8
    TIMEINC = 0.7

    from utilities import jitterForce, repulseForce, springForce, diff3D, add3D
    from graph import DummyVertex

    balanced = False

    #
    # Set vertex mass
    #
    # XXX# Dummy vertices are 1/4 the mass of regular vertices.
    vxMass = dict([(v.id, (pi / 3.0, 2.0 * pi / 3.0)[isinstance(v, DummyVertex)]) for v in context.graph.vertices])

    #XXX# Scale by volume
    #vxMass = [4.0 * pi * v.radius * v.radius * v.radius / 3.0 for v in context.graph.vertices]

    #
    # Set vertex charge
    #
    vxCharge = dict([(v.id, 1.0) for v in context.graph.vertices])

    #
    # Set edge spring tensions
    #

    # The edgeTension parameter is specified in the range [0.0, 1.0].
    # Adjust it to be within reasonable bounds.
    if edgeTension > 1.0 or edgeTension < 0.0:
        raise GraphError, "Edge tension must be in the range [0.0, 1.0]"
    # 0.13 is practical (minimizing oscillations)
    # 0.11 is good (visibility separation)
    edgeTension = edgeTension * 0.15

    if useAttrEdgeK:
        edgeK = context.graph.normalizeFromEdges( \
            max=edgeTension, min=0.001, inv=invAttrEdgeK, \
            valFunc=lambda e: float(e.attribute), \
            failError="Some edge attributes could not be converted to float values for tension.")
    else:  # not useAttrEdgeK
        edgeK = dict([((e.source.id, e.target.id), edgeTension) for e in context.graph.edges])

    #
    # Set edge ideal length
    #
    # The edgeLength parameter must be >0.0

    if edgeLength <= 0.0:
        raise GraphError, "Edge length must be >0.0"
    if useAttrEdgeLen:
        edgeLen = context.graph.normalizeFromEdges( \
            max=edgeLength, min=0.0, inv=invAttrEdgeLen, \
            valFunc=lambda e: float(e.attribute), \
            failError="Some edge attributes could not be converted to float values for length.")
    else:
        edgeLen = dict([((e.source.id, e.target.id), edgeLength) for e in context.graph.edges])

    #
    # Set pass number
    #
    I = 0

    # Set changed flag now - if we set it after, then it's possible
    # that we could bail out without change flag getting set.
    context.graph.change()

    #
    # Do at least 2 passes to ensure that coincident vertices
    # get jittered apart.
    #
    while not balanced or I < 2:
        I = I + 1
        # Initialize the force on each vertex to 0.
        vxForceSum = dict([(x.id, (0.0, 0.0, 0.0)) for x in context.graph.vertices])
        balanced = True

        for v_num in range(len(context.graph.vertices)):
            v = context.graph.vertices[v_num]

            # Edges
            for u in v.nearestVertices():
                if u == v:
                    continue
                edges = context.graph.findEdgeBetween(u, v)
                for e in edges:
                    F = springForce(diff3D(v.pos, u.pos),
                                    Kuv=edgeK[(e.source.id, e.target.id)],
                                    Luv=edgeLen[(e.source.id, e.target.id)],
                                    j=JITTER)
                    vxForceSum[v.id] = add3D(vxForceSum[v.id], F)

            # Vertices
            for u in context.graph.vertices:
                if u == v:
                    continue
                F = repulseForce(diff3D(u.pos, v.pos),
                                 q1=vxCharge[u.id],
                                 q2=vxCharge[v.id],
                                 Cuv=300,
                                 j=JITTER)
                vxForceSum[v.id] = add3D(vxForceSum[v.id], F)

            # Jitter
            F = jitterForce(JITTER)
            vxForceSum[v.id] = add3D(vxForceSum[v.id], F)

            # Tether
            F = springForce(diff3D(v.pos, (0.0, 0.0, 0.0)), Kuv=0.005, Luv=1.0, j=JITTER)
            vxForceSum[v.id] = add3D(vxForceSum[v.id], F)

            if abs(vxForceSum[v.id][0]) > EPSILON and X_AXIS in axes or \
                                    abs(vxForceSum[v.id][1]) > EPSILON and Y_AXIS in axes or \
                                    abs(vxForceSum[v.id][2]) > EPSILON and Z_AXIS in axes:
                balanced = False

        # Now we have the force on each vertex.
        # Act on them.

        for v in context.graph.vertices:
            vel = ((X_AXIS in axes) * vxForceSum[v.id][0] * TIMEINC / vxMass[v.id],
                   (Y_AXIS in axes) * vxForceSum[v.id][1] * TIMEINC / vxMass[v.id],
                   (Z_AXIS in axes) * vxForceSum[v.id][2] * TIMEINC / vxMass[v.id])
            v.pos = add3D(v.pos, vel)

        if sync:
            # Because we're saving calls by referring to the vertices directly,
            # we have to set the change flag here, before we sync.
            context.graph.change()
            sync()
    context.graph.change()
    return I
Ejemplo n.º 14
0
    def perspCameraMove(self, camera, newPos=None, newLook=None, duration=1.0, wait=0.0):
        """
        Moves the camera smoothly to a new position and orientation.
        If newLook is None, does not change the orientation of the camera.
        If newPos is None, does not change the position of the camera.
        """
        from camera import Camera, OrthoCamera, X_AXIS, Y_AXIS, Z_AXIS

        assert (not isinstance(camera, OrthoCamera))

        newCam = Camera()
        if newPos != None:
            newCam.pos = self.normalizePos(newPos)
        else:
            newCam.pos = camera.pos
        if newLook != None:
            newCam.lookAt = self.normalizePos(newLook)
        else:
            newCam.lookAt = camera.lookAt

        steps = int(duration * self.parent.fps)

        (oldTheta, oldPhi) = camera.polar()
        (newTheta, newPhi) = newCam.polar()

        deltaYaw = newTheta - oldTheta
        deltaPitch = newPhi - oldPhi
        deltaPos = diff3D(camera.pos, newCam.pos)

        # Check to make sure we're coming around the short side
        if deltaYaw > 180.0:
            deltaYaw = deltaYaw - 360.0
        elif deltaYaw < -180.0:
            deltaYaw = deltaYaw + 360.0
        print "DeltaYaw", deltaYaw

        stepYaw = deltaYaw / steps
        stepPitch = deltaPitch / steps
        stepPos = div3D(deltaPos, steps)

        accum = wait
        delay = 1.0 / self.parent.fps

        # Set up the animation
        for i in range(steps - 1):
            accum += delay

            self.post(accum,
                      objects=(
                      camera,
                      ),
                      props=(
                      (
                      'pos',
                      add3D(camera.pos, mult3D(stepPos, i + 1)),
                      ),
                      ),
                      call=(
                      ('absrotate', (Y_AXIS, stepYaw), {}),
                      ('rotate', (X_AXIS, stepPitch), {}),
                      ),
            )

        # Finish up in the correct place
        accum += delay
        self.post(accum,
                  objects=(camera,),
                  props=(
                  ('pos', newCam.pos),
                  ('lookAt', newCam.lookAt),
                  ),
        )

        self.signal()