Beispiel #1
0
    def drawBBox(self, scnObj):
        ls = LineSegs()
        x, y, z = scnObj.pos
        rx, rz, ry = scnObj.radius
        ls.setThickness(5)
        ls.setColor(1, 0.4, 0.0, 0.3)

        ls.moveTo(x, y, z)
        ls.drawTo(x + rx, y + ry, z + rz)
        ls.drawTo(x + rx, y - ry, z + rz)
        ls.drawTo(x - rx, y - ry, z + rz)
        ls.drawTo(x - rx, y + ry, z + rz)
        ls.drawTo(x + rx, y + ry, z + rz)

        ls.moveTo(x, y, z)
        ls.drawTo(x + rx, y + ry, z - rz)
        ls.drawTo(x + rx, y - ry, z - rz)
        ls.drawTo(x - rx, y - ry, z - rz)
        ls.drawTo(x - rx, y + ry, z - rz)
        ls.drawTo(x + rx, y + ry, z - rz)

        linegeomn = ls.create(dynamic=False)
        np = self.render.attachNewNode(linegeomn)
        scnObj.setNodePath(
            np)  # Rotation should occure ere, TODO but maybe it shouldnt
Beispiel #2
0
    def plot_xy_vs_t(self):
        then = self.now
        if self.now == 0:
            then = time.time()
        self.now = time.time()
        #print self.now
        dt = (self.now - then) / 10
        joy_in = self.js.getEvents()
        if joy_in:
            #print type(joy_in)
            for event_name in joy_in:
                #print event_name
                event = joy_in[event_name]
                #print event
                #print type(event)
                #print inspect.getmembers(event, predicate=inspect.ismethod)
                event_mag = event.getMagnitude()
                if event_name == 'moveForward':
                    y_mag = event_mag
                    #print('forward', y_mag)
                    self.y_mag = (y_mag * self.gain) - self.offset
                    #print('forward', self.y_mag)
                elif event_name == 'moveBackward':
                    y_mag = -event_mag
                    #print('backward', y_mag)
                    self.y_mag = (y_mag * self.gain) - self.offset
                    #print('backward', self.y_mag)
                elif event_name == 'turnRight':
                    x_mag = event_mag
                    #print('right', x_mag)
                    self.x_mag = (x_mag * self.gain) + self.offset
                    #print('right', self.x_mag)
                elif event_name == 'turnLeft':
                    x_mag = -event_mag
                    #print('left', x_mag)
                    self.x_mag = (x_mag * self.gain) + self.offset
                    #print('left', self.x_mag)
        plot_x = LineSegs()
        plot_x.setThickness(2.0)
        plot_x.setColor(Vec4(1, 1, 0, 1))
        plot_x.moveTo(self.time, 0, self.old_x)

        plot_y = LineSegs()
        plot_y.setThickness(2.0)
        plot_y.setColor(Vec4(1, 0, 0, 1))
        plot_y.moveTo(self.time, 0, self.old_y)

        self.time += dt
        #print('dt', dt)
        #print('time', self.time)
        plot_x.drawTo(self.time, 0, self.x_mag)
        node = base.render2d.attach_new_node(plot_x.create(True))
        self.plot.append(node)
        plot_y.drawTo(self.time, 0, self.y_mag)
        node = base.render2d.attach_new_node(plot_y.create(True))
        self.plot.append(node)
        self.old_x = self.x_mag
        self.old_y = self.y_mag
        if self.time > 1:
            self.clear_plot()
Beispiel #3
0
def create_line_seg(panda3d):
    print("Draw LineSeg")
    line = LineSegs()
    print(LineSegs)
    line.setThickness(4)

    print(coredata["start"])

    x0, y0, z0 = coredata["start"]
    x1, y1, z1 = app.work_plane_mouse

    line.setColor(1.0, 0.0, 0.0, 1.0)
    line.moveTo(x0, y0, z0)
    line.drawTo(x1, y1, z1)

    coredata["line"] = line

    node = line.create(dynamic=True)

    node_path = NodePath(node)
    node_path.reparentTo(panda3d.render)

    coredata["line_node"] = node_path

    return line, node
Beispiel #4
0
 def move_map_avatar(self, move, stop):
     # print move
     # avatar is mapped assuming c_range of 0.5. What do I need to
     # change to use a different c_range? c_range of one is twice
     # the
     if move:
         avt = LineSegs()
         avt.setThickness(1)
         avt.setColor(1, 1, 1)
         # print 'last', self.last_avt
         avt.move_to(self.last_avt[0], -5, self.last_avt[1])
         # print 'move', move
         new_move = [i + (j * self.avt_factor) for i, j in zip(self.last_avt, move)]
         # new_move = [i + j for i, j in zip(self.last_avt, move)]
         # would it be better to have a local stop condition?
         if stop[0]:
             new_move[0] = self.last_avt[0]
             # print 'stop x', self.last_avt[0]
         if stop[1]:
             new_move[1] = self.last_avt[1]
             # print 'stop y', self.last_avt[1]
         # print 'new', new_move
         self.last_avt = [new_move[0], new_move[1]]
         avt.draw_to(new_move[0], -5, new_move[1])
         self.map_avt_node.append(self.render2d.attach_new_node(avt.create()))
         # print self.map_avt_node[-1]
         # can't let too many nodes pile up
         if len(self.map_avt_node) > 299:
             # removing the node does not remove the object from the list
             for i, j in enumerate(self.map_avt_node):
                 j.removeNode()
                 if i > 49:
                     break
             del self.map_avt_node[0:50]
Beispiel #5
0
    def load_bbone(self, structure, node):
        for chain in structure.get_chains():
            carr = np.random.rand(3, 1)
            ccolor = float(carr[0]), float(carr[1]), float(carr[2]), 1.0
            can_atoms = [
                atom for atom in chain.get_atoms()
                if atom.get_name() == 'CA' or atom.get_name() == 'N'
            ]
            can_coordinates = [atom.coord for atom in can_atoms]

            for atom in can_atoms:
                x, y, z = atom.coord
                id = atom.get_id()
                a = loader.loadModel("data/atom_sphere")
                a.setPos(x, y, z)
                a.reparentTo(pnode)
                a.setColor(ccolor)
                a.setScale(vrad(id) / 2.5)

            lines = LineSegs()
            lines.setColor(ccolor)
            lines.moveTo(can_coordinates[0][0], can_coordinates[0][1],
                         can_coordinates[0][2])
            for i in range(len(can_atoms))[1:]:
                lines.drawTo(can_coordinates[i][0], can_coordinates[i][1],
                             can_coordinates[i][2])
            lines.setThickness(6)
            lnode = lines.create()
            linenp = NodePath(lnode)
            linenp.reparentTo(pnode)

        node.flattenStrong()
Beispiel #6
0
    def createMoveVis(self):
        # Instance each selected map object to the vis root
        for obj in base.selectionMgr.selectedObjects:
            instRoot = NodePath("instRoot")
            inst = obj.np.instanceTo(instRoot)
            instRoot.wrtReparentTo(self.toolVisRoot)
            self.xformObjects.append((obj, instRoot, inst))

        # Show an infinite line along the axis we are moving the object
        # if we are using the 3D view
        if self.widget.activeAxis:
            axis = self.widget.activeAxis.axisIdx
            segs = LineSegs()
            col = Vec4(0, 0, 0, 1)
            col[axis] = 1.0
            segs.setColor(col)
            p = Point3(0)
            p[axis] = -1000000
            segs.moveTo(p)
            p[axis] = 1000000
            segs.drawTo(p)
            self.axis3DLines = self.toolRoot.attachNewNode(segs.create())
            self.axis3DLines.setLightOff(1)
            self.axis3DLines.setFogOff(1)

        self.widget.stash()
Beispiel #7
0
    def checkCollisions(self, task):
        sensorPoints = []
        self.sensorDistances = []
        for queue in self.sensorCollisionHandlers:
            if queue.getNumEntries() > 0:
                queue.sortEntries()
                entry = queue.getEntry(0)
                sensorPoint = entry.getSurfacePoint(entry.getFromNodePath())
                sensorPoints.append(sensorPoint)
                tmp = sensorPoint - Vec3(0.0, 0.0, self.sensorHeight)
                self.sensorDistances.append(tmp.length())

        # DEBUG
        tmp = self.car.find("sensorsSegs")
        if not tmp.isEmpty():
            tmp.removeNode()
        if self.debugMode:
            sensorSegs = LineSegs("sensorsSegs")
            sensorSegs.setColor(1.0, 0.45, 0.0)
            sensorSegs.setThickness(4)
            for point in sensorPoints:
                sensorSegs.moveTo(Point3(0.0, 0.0, self.sensorHeight))
                sensorSegs.drawTo(point)
            sensorNode = sensorSegs.create()
            self.car.attachNewNode(sensorNode)

        return task.cont
Beispiel #8
0
 def plot_xy(self):
     joy_in = self.js.getEvents()
     if joy_in:
         #print type(joy_in)
         for event_name in joy_in:
             #print event_name
             event = joy_in[event_name]
             #print event
             #print type(event)
             #print inspect.getmembers(event, predicate=inspect.ismethod)
             event_mag = event.getMagnitude()
             if event_name == 'moveForward':
                 self.y_mag = event_mag
                 print('forward', self.y_mag)
             elif event_name == 'moveBackward':
                 self.y_mag = -event_mag
                 print('backward', self.y_mag)
             elif event_name == 'turnRight':
                 self.x_mag = event_mag
                 print('right', self.x_mag)
             elif event_name == 'turnLeft':
                 self.x_mag = -event_mag
                 print('left', self.x_mag)
         plot_xy = LineSegs()
         plot_xy.setThickness(2.0)
         plot_xy.setColor(Vec4(1, 1, 0, 1))
         plot_xy.moveTo(self.old_x, 0, self.old_y)
         plot_xy.drawTo(self.x_mag, 0, self.y_mag)
         base.render2d.attach_new_node(plot_xy.create(True))
         self.old_x = self.x_mag
         self.old_y = self.y_mag
Beispiel #9
0
 def plot_xy(self):
     joy_in = self.js.getEvents()
     if joy_in:
         #print type(joy_in)
         for event_name in joy_in:
             #print event_name
             event = joy_in[event_name]
             #print event
             #print type(event)
             #print inspect.getmembers(event, predicate=inspect.ismethod)
             event_mag = event.getMagnitude()
             if event_name == 'moveForward':
                 self.y_mag = event_mag
                 print('forward', self.y_mag)
             elif event_name == 'moveBackward':
                 self.y_mag = -event_mag
                 print('backward', self.y_mag)
             elif event_name == 'turnRight':
                 self.x_mag = event_mag
                 print('right', self.x_mag)
             elif event_name == 'turnLeft':
                 self.x_mag = -event_mag
                 print('left', self.x_mag)
         plot_xy = LineSegs()
         plot_xy.setThickness(2.0)
         plot_xy.setColor(Vec4(1, 1, 0, 1))
         plot_xy.moveTo(self.old_x, 0, self.old_y)
         plot_xy.drawTo(self.x_mag, 0, self.y_mag)
         base.render2d.attach_new_node(plot_xy.create(True))
         self.old_x = self.x_mag
         self.old_y = self.y_mag
Beispiel #10
0
def gen_linesegs(linesegs, thickness=0.001, rgba=[0, 0, 0, 1]):
    """
    gen linsegs -- non-continuous segs are allowed
    :param linesegs: [[pnt0, pn1], [pnt0, pnt1], ...], pnti 1x3 nparray, defined in local 0 frame
    :param rgba:
    :param thickness:
    :param refpos, refrot: the local coordinate frame where the pnti in the linsegs are defined
    :return: a geomtric model
    author: weiwei
    date: 20161216, 20201116
    """
    M_TO_PIXEL = 3779.53
    # Create a set of line segments
    ls = LineSegs()
    ls.setThickness(thickness * M_TO_PIXEL)
    ls.setColor(rgba[0], rgba[1], rgba[2], rgba[3])
    for p0p1tuple in linesegs:
        ls.moveTo(p0p1tuple[0][0], p0p1tuple[0][1], p0p1tuple[0][2])
        ls.drawTo(p0p1tuple[1][0], p0p1tuple[1][1], p0p1tuple[1][2])
    # Create and return a node with the segments
    lsnp = NodePath(ls.create())
    lsnp.setTransparency(TransparencyAttrib.MDual)
    lsnp.setLightOff()
    ls_sgm = StaticGeometricModel(lsnp)
    return ls_sgm
Beispiel #11
0
    def draw_trails(self):
        # draw trails
        # self.trails = []
        for i, ball in enumerate(self.box.particles):
            trail = []
            # for j in range(self.box.trail):
            for j in range(MAX_TRAILS):
                line = LineSegs(f"trail[{i},{j}]")
                color = [c / 255 for c in ball.color]
                line.setColor(*color, 1)
                # line.setColor(0.3, 0.3, 0.3, 1)
                line.moveTo((0, 0, 0))
                line.drawTo((0, 1, 0))
                line.setThickness(1)

                node = line.create()
                nodepath = NodePath(node)
                # nodepath.reparentTo(self.render)
                nodepath.reparentTo(self.boxnode)
                # nodepath.reparentTo(ball.object)
                # nodepath.setColor(0,0.5,0,1)
                trail.append(nodepath)
            self.trails.append(trail)

        return self.box.particles
Beispiel #12
0
    def makeBulletRicochet(self, dgi):
        pos = CIGlobals.getVec3(dgi)
        dir = CIGlobals.getVec3(dgi)
        scale = dgi.getFloat64()

        start = (0, 0, 0)
        end = dir * scale

        from panda3d.core import LineSegs, Vec4
        from direct.interval.IntervalGlobal import Sequence, Func, Parallel
        lines = LineSegs()
        lines.setColor(Vec4(1, 1, 1, 1))
        lines.setThickness(1)
        lines.moveTo(start)
        lines.drawTo(end)
        np = render.attachNewNode(lines.create())
        np.setLightOff(1)
        np.setPos(pos)
        Sequence(
            Parallel(np.posInterval(0.1, pos + end, pos),
                     np.scaleInterval(0.1, (0.001, 0.001, 0.001), (1, 1, 1))),
            Func(np.removeNode)).start()

        import random
        soundDir = "sound/weapons/ric{0}.wav"
        soundIdx = random.randint(1, 5)
        CIGlobals.emitSound(soundDir.format(soundIdx), pos)
Beispiel #13
0
    def makeGizmoAxis(self, axis, text, textOffset=1.1):
        color = Vec4(0, 0, 0, 1)
        color[axis] = 1

        pos = Vec3(0, 1, 0)
        if axis == 1:
            pos[1] = -pos[1]

        if axis == 1:
            textOffset = -textOffset

        direction = Vec3(0)
        direction[axis] = 1

        segs = LineSegs()
        segs.setColor(color)
        segs.moveTo(Point3(0))
        segs.drawTo(pos)
        np = self.np.attachNewNode(segs.create())
        np.lookAt(direction)
        tn = TextNode('gizmoAxis%iText' % axis)
        tn.setTextColor(color)
        tn.setAlign(TextNode.ACenter)
        tn.setText(text)
        tnnp = np.attachNewNode(tn.generate())
        tnnp.setY(textOffset)
        tnnp.setBillboardPointEye()
        tnnp.setScale(0.5)

        return np
Beispiel #14
0
 def show_window(self, target_pos):
     # draw line around target representing how close the subject has to be looking to get reward
     # print('show window around square', square_pos)
     tolerance = self.plot_variables[
         self.text_dict['Tolerance']] / self.deg_per_pixel
     # print 'tolerance in pixels', tolerance
     # print 'square', square[0], square[2]
     eye_window = LineSegs()
     eye_window.setThickness(2.0)
     eye_window.setColor(1, 0, 0, 1)
     angle_radians = radians(360)
     for i in range(50):
         a = angle_radians * i / 49
         y = tolerance * sin(a)
         x = tolerance * cos(a)
         eye_window.drawTo((x + target_pos[0], 55, y + target_pos[1]))
     # draw a radius line
     # eye_window.moveTo(square[0], 55, square[2])
     # eye_window.drawTo(square[0], 55, square[2] + self.plot_variables[self.text_dict['Tolerance']])
     # print 'distance drawn', self.distance((square[0], square[2]), (square[0], square[2] + self.plot_variables[self.text_dict['Tolerance']]))
     # True optimizes the line segments, which sounds useful
     node = self.base.render.attachNewNode(eye_window.create(True))
     node.show(BitMask32.bit(0))
     node.hide(BitMask32.bit(1))
     self.eye_window.append(node)
Beispiel #15
0
 def add_line(self, start_p: Union[Vec3, Tuple], end_p: Union[Vec3, Tuple], color, thickness: float):
     line_seg = LineSegs("interface")
     line_seg.setColor(*color)
     line_seg.moveTo(start_p)
     line_seg.drawTo(end_p)
     line_seg.setThickness(thickness)
     NodePath(line_seg.create(False)).reparentTo(self.render)
Beispiel #16
0
    def plot_xy_vs_t(self):
        then = self.now
        if self.now == 0:
            then = time.time()
        self.now = time.time()
        #print self.now
        dt = (self.now - then) / 10
        joy_in = self.js.getEvents()
        if joy_in:
            #print type(joy_in)
            for event_name in joy_in:
                #print event_name
                event = joy_in[event_name]
                #print event
                #print type(event)
                #print inspect.getmembers(event, predicate=inspect.ismethod)
                event_mag = event.getMagnitude()
                if event_name == 'moveForward':
                    y_mag = event_mag
                    #print('forward', y_mag)
                    self.y_mag = (y_mag * self.gain) - self.offset
                    #print('forward', self.y_mag)
                elif event_name == 'moveBackward':
                    y_mag = -event_mag
                    #print('backward', y_mag)
                    self.y_mag = (y_mag * self.gain) - self.offset
                    #print('backward', self.y_mag)
                elif event_name == 'turnRight':
                    x_mag = event_mag
                    #print('right', x_mag)
                    self.x_mag = (x_mag * self.gain) + self.offset
                    #print('right', self.x_mag)
                elif event_name == 'turnLeft':
                    x_mag = -event_mag
                    #print('left', x_mag)
                    self.x_mag = (x_mag * self.gain) + self.offset
                    #print('left', self.x_mag)
        plot_x = LineSegs()
        plot_x.setThickness(2.0)
        plot_x.setColor(Vec4(1, 1, 0, 1))
        plot_x.moveTo(self.time, 0, self.old_x)

        plot_y = LineSegs()
        plot_y.setThickness(2.0)
        plot_y.setColor(Vec4(1, 0, 0, 1))
        plot_y.moveTo(self.time, 0, self.old_y)

        self.time += dt
        #print('dt', dt)
        #print('time', self.time)
        plot_x.drawTo(self.time, 0, self.x_mag)
        node = base.render2d.attach_new_node(plot_x.create(True))
        self.plot.append(node)
        plot_y.drawTo(self.time, 0, self.y_mag)
        node = base.render2d.attach_new_node(plot_y.create(True))
        self.plot.append(node)
        self.old_x = self.x_mag
        self.old_y = self.y_mag
        if self.time > 1:
            self.clear_plot()
 def create(self, s):
     segs = LineSegs( )
     segs.setThickness( 2.0 )
     segs.setColor( Vec4(1,0,0,1) )
     segs.moveTo( s.points[0] )
     for p in s.points[1:]:
         segs.drawTo( p )
     return segs.create( )
Beispiel #18
0
 def _drawVelocityLine(self):
     self.velocityLineNP.removeNode()
     ls = LineSegs()
     # ls.setThickness(1)
     ls.setColor(0.0, 0.0, 1.0, 1.0)
     ls.moveTo(self.getPos())
     ls.drawTo(self.getPos() + self.getVel())
     node = ls.create()
     self.velocityLineNP = self.base.render.attachNewNode(node)
Beispiel #19
0
 def _drawSetpointLine(self):
     self.setpointNP.removeNode()
     ls = LineSegs()
     # ls.setThickness(1)
     ls.setColor(1.0, 1.0, 1.0, 1.0)
     ls.moveTo(self.getPos())
     ls.drawTo(self.setpoint)
     node = ls.create()
     self.setpointNP = self.base.render.attachNewNode(node)
Beispiel #20
0
 def _drawForceLine(self):
     self.forceLineNP.removeNode()
     ls = LineSegs()
     # ls.setThickness(1)
     ls.setColor(0.0, 1.0, 0.0, 1.0)
     ls.moveTo(self.getPos())
     ls.drawTo(self.getPos() + self.rigidBody.getTotalForce() * 0.2)
     node = ls.create()
     self.forceLineNP = self.base.render.attachNewNode(node)
Beispiel #21
0
 def plot_zero_lines(self):
     plot_zero = LineSegs()
     plot_zero.setThickness(2.0)
     plot_zero.setColor(Vec4(1, 0, 1, 1))
     plot_zero.moveTo(-1, 0, self.x_mag)
     plot_zero.drawTo(1, 0, self.x_mag)
     plot_zero.moveTo(-1, 0, self.y_mag)
     plot_zero.drawTo(1, 0, self.y_mag)
     base.render2d.attach_new_node(plot_zero.create(True))
Beispiel #22
0
 def _drawActualDroneLine(self):
     self.actualDroneLineNP.removeNode()
     ls = LineSegs()
     # ls.setThickness(1)
     ls.setColor(0.0, 0.0, 0.0, 1.0)
     ls.moveTo(self.getPos())
     ls.drawTo(self.actualDronePosition)
     node = ls.create()
     self.actualDroneLineNP = self.base.render.attachNewNode(node)
Beispiel #23
0
 def draw_edge(self, e, e_color):
     line_drawer = LineSegs('line_drawer')
     line_drawer.setColor(e_color)
     line_drawer.setThickness(1.5)
     line_drawer.moveTo(e.v1.pos)
     line_drawer.drawTo(e.v2.pos)
     edge_node = line_drawer.create()
     rendered_edge = self.render_root.attachNewNode(edge_node)
     self.render_nodes['edge_' + str(e.ID)] = rendered_edge
Beispiel #24
0
 def plot_zero_lines(self):
     plot_zero = LineSegs()
     plot_zero.setThickness(2.0)
     plot_zero.setColor(Vec4(1, 0, 1, 1))
     plot_zero.moveTo(-1, 0, self.x_mag)
     plot_zero.drawTo(1, 0, self.x_mag)
     plot_zero.moveTo(-1, 0, self.y_mag)
     plot_zero.drawTo(1, 0, self.y_mag)
     base.render2d.attach_new_node(plot_zero.create(True))
Beispiel #25
0
 def draw_line(self,p,col):
     line = LineSegs()
     line.setColor(col[0],col[1],col[2], 1)
     line.setThickness(2)
     line.moveTo(p[0],p[1],0)
     line.drawTo(p[2],p[3],0)
     line_node = line.create()
     node_path = NodePath(line_node)
     node_path.reparentTo(render)
Beispiel #26
0
	def draw_edge(self,e,e_color):
		line_drawer = LineSegs('line_drawer')
		line_drawer.setColor(e_color)
		line_drawer.setThickness(1.5)
		line_drawer.moveTo(e.v1.pos)
		line_drawer.drawTo(e.v2.pos)
		edge_node = line_drawer.create()
		rendered_edge = self.render_root.attachNewNode(edge_node)
		self.render_nodes['edge_'+str(e.ID)] = rendered_edge
    def drawLineSeg(self, loader, parent, start, end):
        lines = LineSegs()
        lines.setThickness(5.0)
        lines.setColor(VBase4(1, 0.5, 0.5, 1.0))
        lines.moveTo(start)
        lines.drawTo(end)

        np = parent.attachNewNode(lines.create())
        np.setDepthWrite(True)
        np.setDepthTest(True)
    def fire_laser(self, panda3dworld, entity_id):
        now = globalClock.getRealTime()
        if now - self.last_time_laser_fired < self.laser_reload_time:
            if defines.ENTITIES[entity_id]["CATEGORY"] == "ship":
                panda3dworld.keys["fire"] = 0
            elif defines.ENTITIES[entity_id]["CATEGORY"] == "ship2":
                panda3dworld.keys["p2fire"] = 0
        else:
            self.last_time_laser_fired = now

            pos = defines.ENTITIES[entity_id]["NODE"].getPos()
            angle = 360 - defines.ENTITIES[entity_id]["NODE"].getR()
            # print angle
            start_pos_x = pos.x + 0.5 * cos(angle * pi / 180)
            start_pos_y = pos.z + 0.5 * sin(angle * pi / 180)
            pos_x = pos.x + 10 * cos(angle * pi / 180)
            pos_y = pos.z + 10 * sin(angle * pi / 180)

            callback = test_laser_collision(start_pos_x, start_pos_y, pos_x, pos_y)
            if callback.hit:
                pos_x = callback.point.x
                pos_y = callback.point.y
                for contact_id, entity in defines.ENTITIES.items():
                    if entity["BODY"].fixtures[0] == callback.fixture:
                        if (
                            entity["CATEGORY"] == "ship"
                            or entity["CATEGORY"] == "ship2"
                            or entity["CATEGORY"] == "asteroid"
                        ):
                            entity["SHIELD"] -= 10
                        elif entity["CATEGORY"] == "bullet":
                            defines.ENTITIES[contact_id]["NODE"].removeNode()
                            defines.ENTITIES[contact_id]["PHYSIC_NODE"].removeNode()
                            defines.world.DestroyBody(defines.ENTITIES[contact_id]["BODY"])
                            del defines.ENTITIES[contact_id]
            ls = LineSegs("lines")
            ls.setColor(1, 1, 1, 1)
            ls.drawTo(start_pos_x, 55, start_pos_y)
            ls.drawTo(pos_x, 55, pos_y)
            laser = ls.create(False)
            laserPath = render.attachNewNode(laser)
            laserPath.setBin("unsorted", 0)
            laserPath.setDepthTest(False)

            sound = base.loader.loadSfx("sounds/laser.ogg")
            sound.setVolume(0.2)
            sound.play()

            taskMgr.doMethodLater(0.05, remove_laser_task, "remove laser", extraArgs=[laserPath], appendTask=True)

            defines.ENTITIES[entity_id]["ENERGY"] -= 5
            if defines.ENTITIES[entity_id]["CATEGORY"] == "ship":
                panda3dworld.keys["fire"] = 0
            elif defines.ENTITIES[entity_id]["CATEGORY"] == "ship2":
                panda3dworld.keys["p2fire"] = 0
Beispiel #29
0
 def draw_path(self,path):
     if self.vis:
         self.vis.removeNode()
     l=LineSegs()
     l.setColor(1,0,0,1)
     l.setThickness(2)
     l.moveTo(path[0])
     for point in path:
         l.drawTo(point)
     self.vis=render.attachNewNode(l.create())
     self.vis.setZ(0.5)
def create_lines(joints, color, thickness=5.0):
    for node, parent in joints:
        if parent is not None:
            lines = LineSegs()
            lines.setThickness(thickness)
            lines.setColor(color)
            lines.moveTo(0, 0, 0)
            lines.drawTo(node.getPos(parent))

            np = parent.attachNewNode(lines.create())
            np.setDepthWrite(True)
            np.setDepthTest(True)
Beispiel #31
0
 def createGrid(self):
     segs = LineSegs()
     segs.setThickness(4.0)
     segs.setColor(Vec4(1, 1, 0, 0.3))
     for i in xrange(self.level.maxX):
         segs.moveTo(i + 1, 0, utils.GROUND_LEVEL)
         segs.drawTo(i + 1, self.level.maxY, utils.GROUND_LEVEL + 0.02)
     for j in xrange(self.level.maxY):
         segs.moveTo(0, j + 1, utils.GROUND_LEVEL)
         segs.drawTo(self.level.maxX, j + 1, utils.GROUND_LEVEL + 0.02)
     self.grid = NodePath(segs.create())
     self.grid.setTransparency(TransparencyAttrib.MAlpha)
    def fire_laser(self, panda3dworld, entity_id):
        now = globalClock.getRealTime()
        if now - self.last_time_laser_fired < self.laser_reload_time:
            if defines.ENTITIES[entity_id]['CATEGORY'] == 'ship':
                panda3dworld.keys["fire"] = 0
            elif defines.ENTITIES[entity_id]['CATEGORY'] == 'ship2':
                panda3dworld.keys["p2fire"] = 0
        else:
            self.last_time_laser_fired = now

            pos = defines.ENTITIES[entity_id]["NODE"].getPos()
            angle = 360 - defines.ENTITIES[entity_id]["NODE"].getR() 
            # print angle
            start_pos_x = pos.x + 0.5 * cos(angle* pi/180)
            start_pos_y = pos.z + 0.5 * sin(angle* pi/180)
            pos_x = pos.x + 10 * cos(angle* pi/180)
            pos_y = pos.z + 10 * sin(angle* pi/180)

            callback = test_laser_collision(start_pos_x, start_pos_y, pos_x, pos_y)
            if callback.hit:
                pos_x = callback.point.x
                pos_y = callback.point.y
                for contact_id, entity in defines.ENTITIES.items(): 
                    if entity['BODY'].fixtures[0] == callback.fixture:
                        if entity['CATEGORY'] == "ship" or entity['CATEGORY'] == "ship2" or entity['CATEGORY'] == "asteroid":
                            entity['SHIELD'] -= 10
                        elif entity['CATEGORY'] == "bullet":
                            defines.ENTITIES[contact_id]['NODE'].removeNode()
                            defines.ENTITIES[contact_id]['PHYSIC_NODE'].removeNode()
                            defines.world.DestroyBody(defines.ENTITIES[contact_id]['BODY'])
                            del defines.ENTITIES[contact_id]
            ls = LineSegs("lines")
            ls.setColor(1,1,1,1)
            ls.drawTo(start_pos_x, 55, start_pos_y)
            ls.drawTo(pos_x, 55, pos_y)
            laser = ls.create(False)
            laserPath = render.attachNewNode(laser)
            laserPath.setBin("unsorted", 0)
            laserPath.setDepthTest(False)


            sound = base.loader.loadSfx("sounds/laser.ogg")
            sound.setVolume(0.2)
            sound.play()
 
            taskMgr.doMethodLater(0.05, remove_laser_task, 'remove laser', extraArgs=[laserPath], appendTask=True)

            defines.ENTITIES[entity_id]['ENERGY'] -= 5
            if defines.ENTITIES[entity_id]['CATEGORY'] == 'ship':
                panda3dworld.keys["fire"] = 0
            elif defines.ENTITIES[entity_id]['CATEGORY'] == 'ship2':
                panda3dworld.keys["p2fire"] = 0
Beispiel #33
0
 def plot_match_square(self, corners):
     print 'plot match square'
     print corners
     match = LineSegs()
     match.setThickness(1.5)
     match.setColor(0, 0, 0)
     match.move_to(corners[0][0], -5, corners[1][0])
     match.draw_to(corners[0][1], -5, corners[1][0])
     match.draw_to(corners[0][1], -5, corners[1][1])
     match.draw_to(corners[0][0], -5, corners[1][1])
     match.draw_to(corners[0][0], -5, corners[1][0])
     # print self.render2d
     self.match_square = self.render2d.attach_new_node(match.create())
Beispiel #34
0
 def plot_match_square(self, corners):
     print 'plot match square'
     print corners
     match = LineSegs()
     match.setThickness(1.5)
     match.setColor(0, 0, 0)
     match.move_to(corners[0][0], -5, corners[1][0])
     match.draw_to(corners[0][1], -5, corners[1][0])
     match.draw_to(corners[0][1], -5, corners[1][1])
     match.draw_to(corners[0][0], -5, corners[1][1])
     match.draw_to(corners[0][0], -5, corners[1][0])
     # print self.render2d
     self.match_square = self.render2d.attach_new_node(match.create())
Beispiel #35
0
    def __init__(self):
        BareBonesEditor.__init__(self)
        camera.setPos( 0.0, 0.0, 50.0)
        camera.lookAt(0)

        # hole1 = HorseShoeCentered()
        # hole2 = SquareOffCenter()
        # holes = []
        # holes.append(hole1)
        # holes.append(hole2)
        #
        # map10 = SquareMap10x10()
        # mapWholes = []
        # mapWholes.append(map10)
        # mapWholes.append(holes)
        # for i in mapWholes:
        #     print "mapWholes", i
        #
        # mesh_trilator = makeTriMesh(mapWholes[0], mapWholes[1])  # , holes) ############
        mapThrs = TheirMap()
        # for i in mapThrs:
        #     print "mapThrs", i
        mesh_trilator = makeTriMesh(mapThrs[0], mapThrs[1])  # , holes) ###########

        aLst = AdjacencyList(mesh_trilator[1])
        # for i in aLst.aLst:
        #     print i
        indsNP = drawInds(aLst.adjLst)  # put text on each triangle
        indsNP.setPos(0, 0, .2)
        indsNP.setColor(0, 1, 1, 1)
        mapNP = render.attachNewNode(mesh_trilator[0])
        wireNP = render.attachNewNode('wire')
        wireNP.setPos(0, 0, .1)
        wireNP.setColor(1, 0, 0, 1)
        wireNP.setRenderMode(RenderModeAttrib.MWireframe, .5, 0)
        mapNP.instanceTo(wireNP)

        # aStar = TriangulationAStar(aLst.adjLst, Point3(-11, -11, 0), Point3(11, 11, 0))aLst.adjLst[11].getCenter()
        aStar = TriangulationAStarR(aLst.adjLst, Point3(-11, 11, 0), aLst.adjLst[17].getCenter(), radius=.55)
        path = aStar.AStar()
        print "\n\nEND PATH\n", path
        # https://www.panda3d.org/manual/index.php?title=Putting_your_new_geometry_in_the_scene_graph&diff=prev&oldid=6303
        linesegs = LineSegs("lines")
        linesegs.setColor(0, 0, 1, 1)
        linesegs.setThickness(5)
        for p in path:
            linesegs.drawTo(p)
        node = linesegs.create(False)
        nodePath = render.attachNewNode(node)
        nodePath.setZ(.15)
Beispiel #36
0
    def __init__(self, widget, axis):
        TransformWidgetAxis.__init__(self, widget, axis)
        self.head = base.loader.loadModel("models/editor/arrow_head.bam")
        self.head.reparentTo(self)
        self.head.setY(0.6)
        self.head.setScale(0.7)

        baseSegs = LineSegs()
        baseSegs.setColor(1, 1, 1, 1)
        baseSegs.setThickness(2.0)
        baseSegs.moveTo(0, 0, 0)
        baseSegs.drawTo(0, 0.6, 0)
        self.base = self.attachNewNode(baseSegs.create())
        self.base.setAntialias(AntialiasAttrib.MLine)
Beispiel #37
0
    def _createDebugLine(self, points, connectToEnd=False):
        segs = LineSegs()
        segs.setThickness(1.0)
        segs.setColor(Vec4(1, 1, 0, 1))

        segs.moveTo(points[0])

        for point in points[1:]:
            segs.drawTo(point)

        if connectToEnd:
            segs.drawTo(points[0])

        return NodePath(segs.create())
Beispiel #38
0
 def __make_border__(cls, parent, thickness, color, l, r, b, t):
     moveto_drawto = (
         ((l, 0, t), (l, 0, b)),
         ((r, 0, t), (r, 0, b)),
         ((l, 0, b), (r, 0, b)),
         ((l, 0, t), (r, 0, t)),
     )
     for moveto, drawto in moveto_drawto:
         Border = LineSegs()
         Border.setThickness(thickness)
         Border.setColor(*color)
         Border.moveTo(*moveto)
         Border.drawTo(*drawto)
         b = parent.attachNewNode(Border.create())
         b.setBin(*cls.DRAW_ORDER['border'])
Beispiel #39
0
 def draw_connections(self):
     try:
         self.visual.removeNode()
     except:
         pass
     l=LineSegs()
     l.setColor(1,0,0,1)
     l.setThickness(2)
     for start_node, ends in self.graph['neighbors'].items():
         start_pos=self.graph['pos'][start_node]
         for end in ends:
             end_pos=self.graph['pos'][end]
             l.moveTo(start_pos)
             l.drawTo(end_pos)
     self.visual=render.attachNewNode(l.create())
Beispiel #40
0
 def line_small_lakes(self):
     for l in range(len(small_lake_lines)):
         line = LineSegs()
         line.setColor(0,0,0, 1)
         line.setThickness(2)
         for n in range(len(small_lake_lines[l])):
             x = (small_lake_nodes[small_lake_lines[l][n]]["x"]-map_center[0])*amplification
             y = (small_lake_nodes[small_lake_lines[l][n]]["y"]-map_center[1])*amplification
             if n == 0:
                 line.moveTo(x,y,0)
             else:
                 line.drawTo(x,y,0)
         line_node = line.create()
         node_path = NodePath(line_node)
         node_path.reparentTo(render)
Beispiel #41
0
Datei: ui.py Projekt: tgbugs/desc
 def __make_border__(cls, parent, thickness, color, l, r , b, t):
     moveto_drawto = (
        ((l,0,t), (l,0,b)),
        ((r,0,t), (r,0,b)),
        ((l,0,b), (r,0,b)),
        ((l,0,t), (r,0,t)),
     )
     for moveto, drawto in moveto_drawto:
         Border = LineSegs()
         Border.setThickness(thickness)
         Border.setColor(*color)
         Border.moveTo(*moveto)
         Border.drawTo(*drawto)
         b = parent.attachNewNode(Border.create())
         b.setBin(*cls.DRAW_ORDER['border'])
Beispiel #42
0
 def update2DLines(self):
     self.disable2DLines()
     segs = LineSegs()
     segs.setColor((0, 1, 1, 1))
     segs.moveTo(self.point1)
     segs.drawTo(self.point2)
     segs.moveTo(self.point2)
     segs.drawTo(self.point3)
     segs.moveTo(self.point3)
     segs.drawTo(self.point1)
     self.lines2D = self.doc.render.attachNewNode(segs.create())
     self.lines2D.setBin("fixed", LEGlobals.BoxSort)
     self.lines2D.setDepthWrite(False)
     self.lines2D.setDepthTest(False)
     self.lines2D.hide(~VIEWPORT_2D_MASK)
Beispiel #43
0
 def draw_axis(self):
     for i in range(3):
         line = LineSegs()
         line.setColor(0.7, 0.7, 0.7, 1)
         start = [0, 0, 0]
         start[i] = -500
         line.moveTo(*start)
         end = [0, 0, 0]
         end[i] = 500
         line.drawTo(*end)
         line.setThickness(1)
         node = line.create()
         nodepath = NodePath(node)
         #nodepath.setAntiAlias(8, 1)
         #numpy.setColor((1, 1, 1, 1))
         nodepath.reparentTo(self.boxnode)
Beispiel #44
0
 def line_border(self):
     line = LineSegs()
     line.setColor(0,0,0, 1)
     line.setThickness(5)
     x1 = (175.152-map_center[0])*amplification
     x2 = (177.358-map_center[0])*amplification
     y1 = (-38.808-map_center[1])*amplification
     y2 = (-37.462-map_center[1])*amplification
     line.moveTo(x1,y1,0)
     line.drawTo(x1,y2,0)
     line.drawTo(x2,y2,0)
     line.drawTo(x2,y1,0)
     line.drawTo(x1,y1,0)
     line_node = line.create()
     node_path = NodePath(line_node)
     node_path.reparentTo(render)
Beispiel #45
0
def drawLines():
    global nodes
    for x in nodes:
        x.removeNode()
    nodes = []
    for x in range(len(electrons)):
        ls = LineSegs()
        ls.setThickness(5)
        ls.setColor(1.0, 0.0, 0.0, 1.0)
        ls.moveTo(0.0, 0.0, 0.0)
        if electrons[x].bonded == False:
            ls.drawTo(electrons[x].model.getPos(render))
        else:
            ls.drawTo(electrons[x].bigmodel.getPos(render))
        nodes.append(NodePath(ls.create()))
        nodes[x].reparentTo(render)
Beispiel #46
0
    def _createDebugLine(self, points, connectToEnd=False):
        """ Helper for visualizing the light bounds.
        Draws a line trough all points. When connectToEnd is true,
        the last point will get connected to the first point. """
        segs = LineSegs()
        segs.setThickness(1.0)
        segs.setColor(Vec4(1, 1, 0, 1))

        segs.moveTo(points[0])

        for point in points[1:]:
            segs.drawTo(point)

        if connectToEnd:
            segs.drawTo(points[0])

        return NodePath(segs.create())
    def selection_ring_create(self, segments = 16,size = 1.0):
        ls = LineSegs()
        ls.setThickness(2)
        ls.setColor(0.8,0.8,0.8)

        radians = deg2Rad(360)

        for i in range(segments+1):
            a = radians * i / segments
            y = math.sin(a)*size
            x = math.cos(a)*size

            ls.drawTo(x, y, 0.2)

        node = ls.create()

        return NodePath(node)
Beispiel #48
0
	def draw_floor_plane(self,size,granularity):
		line_drawer = LineSegs('grid_line_drawer')
		line_drawer.setColor(0.0,0.0,0.0,1.0)
		line_drawer.setThickness(1.0)
		for i in range(-size,size+1,granularity):
			line_drawer.moveTo(Vec3(float(i),float(-size),0.0))
			line_drawer.drawTo(Vec3(float(i),float(size),0.0))

		for i in range(-size,size+1,granularity):
			line_drawer.moveTo(Vec3(float(-size),float(i),0.0))
			line_drawer.drawTo(Vec3(float(size),float(i),0.0))

		edge_node = line_drawer.create()
		rendered_edges = render.attachNewNode(edge_node)
		rendered_edges.setTransparency(TransparencyAttrib.MAlpha)
		rendered_edges.setAlphaScale(0.5)

		return 0
Beispiel #49
0
 def make_circle(self, radius, center, color=None):
     circle = LineSegs()
     circle.setThickness(2.0)
     if not color:
         circle.setColor(1, 1, 0, 1)
     else:
         circle.setColor(color)
     angle_radians = radians(360)
     # print alpha_pos
     for i in range(50):
         a = angle_radians * i / 49
         y = radius * sin(a)
         x = radius * cos(a)
         circle.drawTo((x + center[0], self.drawing_layer, y + center[2]))
     if not color:
         self.alpha_circle_node.append(self.base.render.attachNewNode(circle.create()))
     else:
         self.base.render.attachNewNode(circle.create())
Beispiel #50
0
    def walkJointHierarchy(self, actor, part, parentNode = None, indent = ""):
        if isinstance(part, CharacterJoint):
            np = actor.exposeJoint(None, 'modelRoot', part.getName())

            if parentNode and parentNode.getName() != "root":
                lines = LineSegs()
                lines.setThickness(3.0)
                lines.setColor(random.random(), random.random(), random.random())
                lines.moveTo(0, 0, 0)
                lines.drawTo(np.getPos(parentNode))
                lnp = parentNode.attachNewNode(lines.create())
                lnp.setBin("fixed", 40)
                lnp.setDepthWrite(False)
                lnp.setDepthTest(False)

            parentNode = np

        for child in part.getChildren():
            self.walkJointHierarchy(actor, child, parentNode, indent + "  ")
Beispiel #51
0
 def update_avt_p(self, t_time):
     avt = LineSegs()
     avt.setThickness(5)
     avt.setColor(self.avatar_color[0], self.avatar_color[1], self.avatar_color[2])
     group_avatar = []
     while self.avatar_pt[-1] < t_time:
         group_avatar.append(self.avatar_pos.pop())
         # print points
         self.avatar_pt.pop()
         if not self.avatar_pt:
             break
     # print('positions', group_avatar)
     if group_avatar:
         avt.moveTo(self.last_avt[0], self.drawing_layer, self.last_avt[1])
         self.last_avt = [i * self.scale_factor for i in group_avatar[0]]
         for i in group_avatar:
             # print(i[0], i[1], i[2])
             pos = [j * self.scale_factor for j in i]
             avt.drawTo(pos[0], self.drawing_layer, pos[1])
         self.avatar_node.append(self.base.render.attachNewNode(avt.create()))
Beispiel #52
0
 def show_window(self):
     # draw line around target representing how close the subject has to be looking to get reward
     # print('show window around square', square_pos)
     photo_window = LineSegs()
     photo_window.setThickness(2.0)
     photo_window.setColor(1, 0, 0, 1)
     photo_window.moveTo(self.tolerance[0], 55, self.tolerance[1])
     # print photo_window.getCurrentPosition()
     # photo_window.drawTo(self.tolerance[0], 55, -self.tolerance[1] - 100)
     photo_window.drawTo(self.tolerance[0], 55, -self.tolerance[1])
     # print photo_window.getCurrentPosition()
     # photo_window.drawTo(-self.tolerance[0], 55, -self.tolerance[1] - 100)
     photo_window.drawTo(-self.tolerance[0], 55, -self.tolerance[1])
     # print photo_window.getCurrentPosition()
     photo_window.drawTo(-self.tolerance[0], 55, self.tolerance[1])
     # print photo_window.getCurrentPosition()
     photo_window.drawTo(self.tolerance[0], 55, self.tolerance[1])
     # print photo_window.getCurrentPosition()
     node = self.base.render.attachNewNode(photo_window.create(True))
     node.show(BitMask32.bit(0))
     node.hide(BitMask32.bit(1))
     self.photo_window.append(node)
Beispiel #53
0
    def __init__(self):
        ShowBase.__init__(self)
        #BareBonesEditor.__init__(self)
        PanditorDisableMouseFunc()
        camera.setPos( 0.0, 0.0, 50.0)
        camera.lookAt(0.0)
        PanditorEnableMouseFunc()

        # mapThrs = TheirMap()
        mapThrs = CrossWithHole()
        print mapThrs[1]
        mesh_trilator = makeTriMesh(mapThrs[0], mapThrs[1])  # , holes) ###########

        aLst = AdjacencyList(mesh_trilator[1])

        indsNP = drawInds(aLst.adjLst)  # put text on each triangle
        indsNP.setPos(0.0, 0.0, .2)
        indsNP.setColor(0.0, 1.0, 1.0, 1.0)
        mapNP = render.attachNewNode(mesh_trilator[0])
        wireNP = render.attachNewNode('wire')
        wireNP.setPos(0.0, 0.0, .1)
        wireNP.setColor(1.0, 0.0, 0.0, 1)
        wireNP.setRenderMode(RenderModeAttrib.MWireframe, .5, 0)
        mapNP.instanceTo(wireNP)

        aStar = TriangulationAStarR(aLst.adjLst, Point3(0.0, -5.0, 0.0), Point3(0.0, 5.5, 0.0), radius=0.0)
        # aStar = TriangulationAStarR(aLst.adjLst, Point3(aLst.adjLst[17].getCenter() + Point3(5, 0, 0)), Point3(0, 11, 0), radius=.55)
        # aStar = TriangulationAStarR(aLst.adjLst, Point3(-5, 4, 0), Point3(aLst.adjLst[17].getCenter() + Point3(5, 0, 0)), radius=.55)
        path = aStar.AStar()
        print "\n\nEND PATH\n", path
        # https://www.panda3d.org/manual/index.php?title=Putting_your_new_geometry_in_the_scene_graph&diff=prev&oldid=6303
        linesegs = LineSegs("lines")
        linesegs.setColor(0, 0, 1, 1)
        linesegs.setThickness(5)
        for p in path:
            linesegs.drawTo(p)
        node = linesegs.create(False)
        nodePath = render.attachNewNode(node)
        nodePath.setZ(.15)
Beispiel #54
0
 def frame_loop(self, task):
     dt = task.time - task.last
     task.last = task.time
     plot_x = LineSegs()
     plot_x.setThickness(2.0)
     plot_x.setColor(Vec4(1, 1, 0, 1))
     plot_x.moveTo(self.time, 55, self.old_x)
     plot_y = LineSegs()
     plot_y.setThickness(2.0)
     plot_y.moveTo(self.time, 55, self.old_y)
     self.time += dt
     plot_x.drawTo(self.time, 55, self.x_mag)
     plot_y.drawTo(self.time, 55, self.y_mag)
     self.old_x = self.x_mag
     self.old_y = self.y_mag
     node = render.attachNewNode(plot_x.create())
     self.plot.append(node)
     node = render.attachNewNode(plot_y.create())
     self.plot.append(node)
     if self.time > 20:
         self.clear_plot()
     return task.cont
Beispiel #55
0
    def __init__(self, parent, color, hpr, dim):
        PandaNode.__init__(self, dim+'handle')
        self.path = NodePath(self)
        self.parent = parent
        self.dim = dim

        arrow = GeomNode('gnode')
        arrow.addGeomsFrom(self.geomNode)
        arrownp = self.path.attachNewNode(arrow)
        arrownp.hide(BitMask32(1))
        
        clickNode = ClickableNode('clicknode')
        clickNode.setDepthLevel(0.5)
        clickNode.addMouseListener(self)
        clicknp = self.path.attachNewNode(clickNode)
        
        clickgeom = clicknp.attachNewNode(GeomNode('clicknode'))
        clickgeom.hide(BitMask32(7))
        clickgeom.node().addGeomsFrom(self.clickableGeomNode)

        linesegs = LineSegs()
        linesegs.setColor(color)
        linesegs.setThickness(2)
        linesegs.moveTo(Vec3(0, 0, -30))
        linesegs.drawTo(Vec3(0, 0, -0.5))
        linesegs.moveTo(Vec3(0, 0, 0.5))
        linesegs.drawTo(Vec3(0, 0, 30))
        lines = self.path.attachNewNode(linesegs.create())
        lines.show(BitMask32(1))
        lines.hide(BitMask32(2|4|8|16))
        lines.setBin('opaque', 30, 100)
        lines.setAntialias(AntialiasAttrib.MNone)

        self.path.setColor(color)
        self.path.setHpr(hpr)
        
        self.mDownPos = Vec2()
Beispiel #56
0
class GolfScoreBoard:
    notify = directNotify.newCategory('GolfScoreBoard')

    def __init__(self, golfCourse):
        self.golfCourse = golfCourse
        self.numPlayas = len(golfCourse.avIdList)
        self.avIdList = golfCourse.avIdList
        self.playaTags = []
        self.scoreTags = []
        self.totalTags = []
        self.scoreLabels = []
        self.holeLabels = []
        self.parLabels = []
        self.numExited = 0
        self.setup()

    def setup(self):
        self.scoreboard = DirectFrame(parent=aspect2d, relief=None, geom=DGG.getDefaultDialogGeom(), geom_color=ToontownGlobals.GlobalDialogColor, geom_scale=(1.9, 1, 1.05), pos=(0, 0, 0.375))
        self.lines = LineSegs()
        self.lines.setColor(0, 0, 0, 1)
        self.lines.setThickness(2)
        guiModel = loader.loadModel('phase_6/models/golf/golf_gui')
        highlight = loader.loadModel('phase_6/models/golf/headPanel')
        self.maximizeB = DirectButton(parent=base.a2dBottomRight, pos=(-0.15, 0, 0.15), relief=None, state=DGG.NORMAL, image=(guiModel.find('**/score_card_icon'), guiModel.find('**/score_card_icon_rollover'), guiModel.find('**/score_card_icon_rollover')), image_scale=(0.2, 1, 0.2), command=self.showBoard)
        self.vertOffset = 0.13
        self.playaTop = 0.12
        horzOffset = 0.12
        holeTop = 0.3
        self.vCenter = 0.025
        totScore = 0
        totPar = 0
        self.lineVStart = -0.465
        self.lineHStart = 0.17
        self.lineHorOffset = 0.13
        self.lineVertOffset = 0.125
        self.lineVCenter = 0.025
        buttons = loader.loadModel('phase_3/models/gui/dialog_box_buttons_gui')
        self.minimizeB = DirectButton(parent=self.scoreboard, pos=(0, 0, self.lineHStart - 0.59), relief=None, state=DGG.NORMAL, image=(buttons.find('**/CloseBtn_UP'), buttons.find('**/CloseBtn_DN'), buttons.find('**/CloseBtn_Rllvr')), image_scale=(1, 1, 1), command=self.hideBoard, extraArgs=[None])
        self.exitCourseB = DirectButton(parent=self.scoreboard, pos=(0, 0, self.lineHStart - 0.59), relief=None, state=DGG.NORMAL, image=(buttons.find('**/CloseBtn_UP'), buttons.find('**/CloseBtn_DN'), buttons.find('**/CloseBtn_Rllvr')), image_scale=(1, 1, 1), text=TTLocalizer.GolfExitCourse, text_scale=0.04, text_pos=TTLocalizer.GSBexitCourseBPos, command=self.exitCourse)
        self.exitCourseB.hide()
        self.highlightCur = DirectLabel(parent=self.scoreboard, relief=None, pos=(-0.003, 0, 0.038), image=highlight, image_scale=(1.82, 1, 0.135))
        self.titleBar = DirectLabel(parent=self.scoreboard, relief=None, pos=(-0.003, 0, 0.166), color=(0.7, 0.7, 0.7, 0.3), image=highlight, image_scale=(1.82, 1, 0.195))
        self.titleBar.show()
        self.highlightCur.show()
        buttons.removeNode()
        guiModel.removeNode()
        title = GolfGlobals.getCourseName(self.golfCourse.courseId) + ' - ' + GolfGlobals.getHoleName(self.golfCourse.holeIds[self.golfCourse.curHoleIndex])
        self.titleLabel = DirectLabel(parent=self.scoreboard, relief=None, pos=(0, 0, holeTop + 0.1), text_align=TextNode.ACenter, text=title, text_scale=TTLocalizer.GSBtitleLabel, text_font=ToontownGlobals.getSignFont(), text_fg=(0, 0.5, 0.125, 1))
        self.playaLabel = DirectLabel(parent=self.scoreboard, relief=None, pos=(self.lineVStart - 0.23, 0, holeTop), text_align=TextNode.ACenter, text=TTLocalizer.GolfHole, text_font=ToontownGlobals.getMinnieFont(), text_scale=0.05)
        for holeLIndex in xrange(self.golfCourse.numHoles):
            holeLabel = DirectLabel(parent=self.scoreboard, relief=None, pos=(self.lineVStart + 0.055 + horzOffset * holeLIndex, 0, holeTop), text_align=TextNode.ACenter, text='%s' % (holeLIndex + 1), text_scale=0.05)
            self.holeLabels.append(holeLabel)

        self.totalLabel = DirectLabel(parent=self.scoreboard, relief=None, pos=(self.lineVStart + 0.1 + horzOffset * 9.5, 0, holeTop), text_align=TextNode.ACenter, text=TTLocalizer.GolfTotal, text_font=ToontownGlobals.getMinnieFont(), text_scale=0.05)
        self.parTitleLabel = DirectLabel(parent=self.scoreboard, relief=None, pos=(self.lineVStart - 0.23, 0, holeTop - 0.1), text_align=TextNode.ACenter, text=TTLocalizer.GolfPar, text_font=ToontownGlobals.getMinnieFont(), text_scale=0.05)
        for parHoleIndex in xrange(self.golfCourse.numHoles):
            parLabel = DirectLabel(parent=self.scoreboard, relief=None, pos=(self.lineVStart + 0.055 + horzOffset * parHoleIndex, 0, holeTop - 0.1), text_align=TextNode.ACenter, text='%s' % GolfGlobals.HoleInfo[self.golfCourse.holeIds[parHoleIndex]]['par'], text_scale=0.05, text_wordwrap=10)
            totPar = totPar + GolfGlobals.HoleInfo[self.golfCourse.holeIds[parHoleIndex]]['par']
            self.parLabels.append(parLabel)

        parLabel = DirectLabel(parent=self.scoreboard, relief=None, pos=(self.lineVStart + 0.1 + horzOffset * 9.5, 0, holeTop - 0.1), text_align=TextNode.ACenter, text='%s' % totPar, text_scale=0.05, text_wordwrap=10)
        self.parLabels.append(parLabel)
        vert = 0.0
        self.numPlayas = len(self.golfCourse.avIdList)
        for playaIndex in xrange(self.numPlayas):
            name = TTLocalizer.GolfUnknownPlayer
            av = base.cr.doId2do.get(self.golfCourse.avIdList[playaIndex])
            if av:
                name = av.getName()
            playaLabel = DirectLabel(parent=self.scoreboard, relief=None, text_align=TextNode.ACenter, text=name, text_scale=0.05, text_wordwrap=9)
            self.playaTags.append(playaLabel)
            textN = playaLabel.component(playaLabel.components()[0])
            if type(textN) == OnscreenText:
                try:
                    if textN.textNode.getWordwrappedWtext() != name:
                        vert = self.playaTop - self.vertOffset * playaIndex
                    else:
                        vert = self.playaTop - self.vertOffset * playaIndex - self.vCenter
                except:
                    vert = self.playaTop - self.vertOffset * playaIndex

            self.playaTags[playaIndex].setPos(self.lineVStart - 0.23, 0, vert)
            self.notify.debug('self.text height = %f' % self.playaTags[playaIndex].getHeight())
            holeIndex = 0
            for holeIndex in xrange(self.golfCourse.numHoles):
                holeLabel = DirectLabel(parent=self.scoreboard, relief=None, pos=(self.lineVStart + 0.055 + horzOffset * holeIndex, 0, self.playaTop - self.vertOffset * playaIndex - self.vCenter), text_align=TextNode.ACenter, text='-', text_scale=0.05, text_wordwrap=10)
                self.scoreTags.append(holeLabel)

            holeLabel = DirectLabel(parent=self.scoreboard, relief=None, pos=(self.lineVStart + 0.1 + horzOffset * 9.5, 0, self.playaTop - self.vertOffset * playaIndex - self.vCenter), text_align=TextNode.ACenter, text='-', text_scale=0.05, text_wordwrap=10)
            self.totalTags.append(holeLabel)

        self.lines.moveTo(self.lineVStart - 0.45, 0, self.lineHStart + 0.19)
        self.lines.drawTo(self.lineVStart + 11 * self.lineVertOffset, 0, self.lineHStart + 0.19)
        self.lines.moveTo(self.lineVStart - 0.45, 0, self.lineHStart + 0.09)
        self.lines.drawTo(self.lineVStart + 11 * self.lineVertOffset, 0, self.lineHStart + 0.09)
        self.lines.moveTo(self.lineVStart - 0.45, 0, self.lineHStart)
        self.lines.drawTo(self.lineVStart + 11 * self.lineVertOffset, 0, self.lineHStart)
        self.lines.moveTo(self.lineVStart - 0.45, 0, self.lineHStart + 0.19)
        self.lines.drawTo(self.lineVStart - 0.45, 0, self.lineHStart - 4 * 0.13)
        self.lines.moveTo(self.lineVStart, 0, self.lineHStart + 0.19)
        self.lines.drawTo(self.lineVStart, 0, self.lineHStart - 4 * 0.13)
        for x in xrange(4):
            self.lines.moveTo(self.lineVStart - 0.45, 0, self.lineHStart - (x + 1) * self.lineHorOffset)
            self.lines.drawTo(self.lineVStart + 11 * self.lineVertOffset + 0.005, 0, self.lineHStart - (x + 1) * self.lineHorOffset)

        for y in xrange(10):
            self.lines.moveTo(self.lineVStart + y * self.lineVertOffset, 0, self.lineHStart + 0.19)
            self.lines.drawTo(self.lineVStart + y * self.lineVertOffset, 0, self.lineHStart - 4 * 0.13)

        self.lines.moveTo(self.lineVStart + 11 * self.lineVertOffset, 0, self.lineHStart + 0.19)
        self.lines.drawTo(self.lineVStart + 11 * self.lineVertOffset, 0, self.lineHStart - 4 * 0.13)
        self.scoreboard.attachNewNode(self.lines.create())
        self.hide()
        return

    def getScoreLabel(self, avIdorIndex, holeNum):
        index = None
        if avIdorIndex < 100:
            index = avIdorIndex
        else:
            for playaIndex in xrange(self.numPlayas):
                if self.golfCourse.avIdList[playaIndex] == avIdorIndex:
                    index = playaIndex

        return self.scoreTags[index * self.golfCourse.numHoles + holeNum]

    def update(self):
        self.showBoard()
        taskMgr.doMethodLater(AUTO_HIDE_TIMEOUT, self.hideBoard, 'hide score board')

    def hideBoard(self, task):
        self.hide()

    def hide(self):
        self.scoreboard.hide()
        self.maximizeB.show()

    def showBoardFinal(self, task = None):
        self.exitCourseB.show()
        self.minimizeB.hide()
        self.showBoard()

    def showBoard(self, task = None):
        scoreDict = self.golfCourse.scores
        x = 0
        currentGolfer = self.golfCourse.getCurGolfer()
        for playaIndex in xrange(self.numPlayas):
            if self.golfCourse.isGameDone():
                self.playaTags[playaIndex].setColor(0, 0, 0, 1)
            elif currentGolfer == self.golfCourse.avIdList[playaIndex]:
                self.highlightCur.setColor(*GolfGlobals.PlayerColors[playaIndex])
                self.highlightCur.setAlphaScale(0.4)
                self.highlightCur.setPos(-0.003, 0, 0.038 - playaIndex * (self.lineVertOffset + 0.005))
                self.highlightCur.show()
            else:
                self.playaTags[playaIndex].setColor(0, 0, 0, 1)

        for avId in self.avIdList:
            holeIndex = 0
            totScore = 0
            playerExited = False
            for y in xrange(len(self.golfCourse.exitedAvIdList)):
                if self.golfCourse.exitedAvIdList[y] == avId:
                    self.playaTags[x].setColor(0.7, 0.7, 0.7, 1)
                    holeIndex = 0
                    for holeIndex in xrange(self.golfCourse.numHoles):
                        self.getScoreLabel(self.avIdList[x], holeIndex).setColor(0.7, 0.7, 0.7, 1)

                    self.totalTags[x].setColor(0.7, 0.7, 0.7, 1)
                    playerExited = True

            if playerExited == False:
                for holeIndex in xrange(self.golfCourse.numHoles):
                    if holeIndex <= self.golfCourse.curHoleIndex:
                        self.getScoreLabel(avId, holeIndex)['text'] = '%s' % scoreDict[avId][holeIndex]
                        totScore = totScore + scoreDict[avId][holeIndex]
                        if self.golfCourse.isGameDone() == False:
                            if holeIndex == self.golfCourse.curHoleIndex:
                                self.getScoreLabel(avId, holeIndex).setColor(1, 0, 0, 1)
                                self.holeLabels[holeIndex].setColor(1, 0, 0, 1)
                                self.parLabels[holeIndex].setColor(1, 0, 0, 1)
                                title = GolfGlobals.getCourseName(self.golfCourse.courseId) + ' - ' + GolfGlobals.getHoleName(self.golfCourse.holeIds[self.golfCourse.curHoleIndex])
                                self.titleLabel['text'] = title
                            else:
                                self.getScoreLabel(avId, holeIndex).setColor(0, 0, 0, 1)
                                self.holeLabels[holeIndex].setColor(0, 0, 0, 1)
                                self.parLabels[holeIndex].setColor(0, 0, 0, 1)

                self.totalTags[x]['text'] = '%s' % totScore
            if self.golfCourse.isGameDone():
                self.getScoreLabel(avId, self.golfCourse.numHoles - 1).setColor(0, 0, 0, 1)
                self.totalTags[x].setColor(1, 0, 0, 1)
            x = x + 1

        y = 0
        if self.golfCourse.isGameDone():
            self.parLabels[self.golfCourse.numHoles - 1].setColor(0, 0, 0, 1)
            self.holeLabels[self.golfCourse.numHoles - 1].setColor(0, 0, 0, 1)
            self.parLabels[self.golfCourse.numHoles].setColor(1, 0, 0, 1)
            self.totalLabel.setColor(1, 0, 0, 1)
        self.scoreboard.show()
        self.maximizeB.hide()

    def exitCourse(self):
        course = self.golfCourse
        self.delete()
        course.exitEarly()

    def delete(self):
        if self.maximizeB:
            self.maximizeB.destroy()
        self.maximizeB = None
        if self.scoreboard:
            self.scoreboard.destroy()
        self.scoreboard = None
        self.golfCourse = None
        taskMgr.remove('hide score board')
        return
    def getWidthAcrossEdges(self, searchTri, edge1, edge2):
        """Calculates the path width through this triangle. Edge1 and edge2 are the edges being crossed."""
        # this calculates the distance from the point shared by edge1 and edge2 to the nearest obstacle
        # 1st it sets the width of the triangle to the shortest edge being crossed
        # then it searches across the third edge to see if there is an obstacle closer than its own vertices
        # yes that can happen!!!
        for p in edge1:
            if p in edge2:
                pt = p  # get the point that both edges share. This is the point we are measuring the distance to.

        if edge2 == searchTri.getEdge12() and searchTri.n12 is None\
            or edge2 == searchTri.getEdge23() and searchTri.n23 is None\
            or edge2 == searchTri.getEdge13() and searchTri.n13 is None:
            # if edge2 is on a constrained side swap it for edge1
            # doint this makes it so we only have to check edge1. It cuts our code for the next step in half.
            tmp = edge2
            edge2 = edge1
            edge1 = tmp

        # TODO make this work with edge 1, 2, & 3 and local vars nayb 1, 2, & 3 so it's not sooo much code
        if edge1 == searchTri.getEdge12() and searchTri.n12 is None:
            if edge2 == searchTri.getEdge23() and searchTri.n23 is None:
                # Both search edges are constrained, so the width of the triangle is the width of the third edge.
                return getDistance(searchTri.getPoint1(), searchTri.getPoint3())

            elif edge2 == searchTri.getEdge13() and searchTri.n13 is None:
                # ditto
                return getDistance(searchTri.getPoint2(), searchTri.getPoint3())
            else:
                # the other edge is not constrained, so the initial width
                # should be the shortest of either the length of this unconstrained edge
                # or the distance from its non-shared point to the constrained side
                if edge2 == searchTri.getEdge23():
                    minWidth = getDistance(searchTri.getPoint2(), searchTri.getPoint3())
                    # we also need to find the end point for the next step
                    if pt != edge2[0]:
                        otherPt = edge2[0]
                    else:
                        otherPt = edge2[1]
                else:  # the other (non-constrained) edge is 13
                    minWidth = getDistance(searchTri.getPoint1(), searchTri.getPoint3())
                    # we also need to find the end point for the next step
                    if pt != edge2[0]:
                        otherPt = edge2[0]
                    else:
                        otherPt = edge2[1]
                # so now get the distance from the end to the other (constrained) edge
                debugEdgeConstrained = edge1  ############################# DEBUG
                distAcrossTri = getDistance(getNearestPointOnLine(otherPt, edge1),
                                            otherPt)
                if distAcrossTri < minWidth:
                    minWidth = distAcrossTri
                # ########################### this next bit seems off
                else:
                    minWidth = getDistance(searchTri.getPoint1(), searchTri.getPoint3())
        elif edge1 == searchTri.getEdge13() and searchTri.n13 is None:

            if edge2 == searchTri.getEdge23() and searchTri.n23 is None:
                # both are constrained, so the width of the triangle is the length of the unconstrained edge
                return getDistance(searchTri.getPoint1(), searchTri.getPoint2())

            elif edge2 == searchTri.getEdge12() and searchTri.n12 is None:
                return getDistance(searchTri.getPoint2(), searchTri.getPoint3())
            else:
                # the other edge is not constrained, so the initial width
                # should be either the length of this unconstrained edge
                # or the distance from its non-shared point to the constrained side, whichever is shortest
                if edge2 == searchTri.getEdge23():
                    minWidth = getDistance(searchTri.getPoint2(), searchTri.getPoint3())
                    # we also need to find the end point for the next step
                    if pt != edge2[0]:
                        otherPt = edge2[0]
                    else:
                        otherPt = edge2[1]
                else:  # the other (non-constrained) edge is 12
                    minWidth = getDistance(searchTri.getPoint1(), searchTri.getPoint2())
                    # we also need to find the end point for the next step
                    if pt != edge2[0]:
                        otherPt = edge2[0]
                    else:
                        otherPt = edge2[1]
                # so now get the distance from the end to the other (constrained) edge
                debugEdgeConstrained = edge1  ############################# DEBUG
                distAcrossTri = getDistance(getNearestPointOnLine(otherPt, edge1),
                                            otherPt)
                if distAcrossTri < minWidth:
                    minWidth = distAcrossTri
                # ########################### this next bit seems off
                else:
                    minWidth = getDistance(searchTri.getPoint1(), searchTri.getPoint3())

        elif edge1 == searchTri.getEdge23() and searchTri.n23 is None:

            if edge2 == searchTri.getEdge13() and searchTri.n13 is None:
                # both are constrained, so the width of the triangle is the length of the unconstrained edge
                return getDistance(searchTri.getPoint1(), searchTri.getPoint2())

            elif edge2 == searchTri.getEdge12() and searchTri.n12 is None:
                return getDistance(searchTri.getPoint1(), searchTri.getPoint2())
            else:
                # the other edge is not constrained, so the initial width
                # should be either the length of this unconstrained edge
                # or the distance from its non-shared point to the constrained side, whichever is shortest
                if edge2 == searchTri.getEdge12():
                    minWidth = getDistance(searchTri.getPoint1(), searchTri.getPoint2())
                    # we also need to find the end point for the next step
                    if pt != edge2[0]:
                        otherPt = edge2[0]
                    else:
                        otherPt = edge2[1]
                else:  # the other (non-constrained) edge is 13
                    minWidth = getDistance(searchTri.getPoint1(), searchTri.getPoint3())
                    # we also need to find the end point for the next step
                    if pt != edge2[0]:
                        otherPt = edge2[0]
                    else:
                        otherPt = edge2[1]
                # so now get the distance from the end to the other (constrained) edge
                debugEdgeConstrained = edge1  ############################# DEBUG
                distAcrossTri = getDistance(getNearestPointOnLine(otherPt, edge1),
                                            otherPt)
                if distAcrossTri < minWidth:
                    minWidth = distAcrossTri
                # ########################### this next bit seems off
                else:
                    minWidth = getDistance(searchTri.getPoint1(), searchTri.getPoint3())
        else:  # edge1 and edge2 are not constrained
            # Get the width of the shortest of the these two edges
            minWidth = min((edge1[0] - edge1[1]).length(), (edge2[0] - edge2[1]).length())

        # if minWidth < 1:
        #     print "minWidth < 1 pt = ", pt, " || otherPt = ", otherPt, "  || debugConstrained = ", debugEdgeConstrained

        # save these so we don't consider them as nearest points later, else every triangle's width will be 0
        edgePts = [edge1[0], edge1[1]]
        edgePts.extend([edge2[0], edge2[1]])

        # FINALLY search across the third edge for a constrained edge
        # that's closer (to the shared point) than this triangle's vertices
        # print self.adjLst
        # ###################################################
        counter = 0
        # ###################################################
        for t in range(0, len(self.adjLst)):
            # if the edge is constrained, check to see if it narrows the width of this path
            tri = self.adjLst[t]
            # print tri
            if tri.selfInd != searchTri.selfInd:
                if tri.n12 is None:
                    # if the constrained edge, is on the opposite side
                    # from the point shared between the shared edges i.e. for point C check across edge c
                    nearest = getNearestPointOnLine(pt, [tri.tri[0], tri.tri[1]], True)
                    # print tri.selfInd, " 12 is none nearest", nearest
                    if isPointInWedge(nearest, edge1, edge2) and nearest not in edgePts:
                        # and it's in the wedge, check the distance against the current minimum width
                        newW = getDistance(pt, nearest)
                        # print "in wedge newW", newW
                        if newW < minWidth:
                            # ####################################################
                            from panda3d.core import LineSegs
                            # print "pt = ", pt, " || nearest = ", nearest
                            counter += 1
                            linesegs2 = LineSegs("lines" + str(counter))
                            linesegs2.setColor(0, 1, 1, 1)
                            linesegs2.setThickness(5)
                            linesegs2.drawTo(pt)
                            linesegs2.drawTo(nearest)
                            node2 = linesegs2.create(False)
                            nodePath = render.attachNewNode(node2)
                            nodePath.setZ(.25)
                            # ####################################################
                            minWidth = newW
                # do likewise for the other edges
                if tri.n23 is None:
                    nearest = getNearestPointOnLine(pt, [tri.tri[1], tri.tri[2]], True)
                    # print tri.selfInd, " 23  is none nearest", nearest
                    if isPointInWedge(nearest, edge1, edge2) and nearest not in edgePts:
                        newW = getDistance(pt, nearest)
                        # print "in wedge newW", newW
                        if newW < minWidth:
                            # ####################################################
                            from panda3d.core import LineSegs
                            # print "pt = ", pt, " || nearest = ", nearest
                            counter += 1
                            linesegs2 = LineSegs("lines" + str(counter))
                            linesegs2.setColor(0, 1, 1, 1)
                            linesegs2.setThickness(5)
                            linesegs2.drawTo(pt)
                            linesegs2.drawTo(nearest)
                            node2 = linesegs2.create(False)
                            nodePath = render.attachNewNode(node2)
                            nodePath.setZ(.25)
                            # ####################################################
                            minWidth = newW

                if tri.n13 is None:
                    nearest = getNearestPointOnLine(pt, [tri.tri[0], tri.tri[2]], True)
                    # print tri.selfInd, " 13 is none nearest", nearest
                    if isPointInWedge(nearest, edge1, edge2) and nearest not in edgePts:
                        newW = getDistance(pt, nearest)
                        # print "in wedge newW", newW
                        if newW < minWidth:
                            # ####################################################
                            from panda3d.core import LineSegs
                            # print "pt = ", pt, " || nearest = ", nearest
                            counter += 1
                            linesegs2 = LineSegs("lines" + str(counter))
                            linesegs2.setColor(0, 1, 1, 1)
                            linesegs2.setThickness(5)
                            linesegs2.drawTo(pt)
                            linesegs2.drawTo(nearest)
                            node2 = linesegs2.create(False)
                            nodePath = render.attachNewNode(node2)
                            nodePath.setZ(.25)
                            # ####################################################
                            minWidth = newW




        return minWidth
def renderCharts(facegraph, verts, vert_indices, lineset=None):
    
    from meshtool.filters.panda_filters.pandacore import getVertexData, attachLights, ensureCameraAt
    from meshtool.filters.panda_filters.pandacontrols import KeyboardMovement, MouseDrag, MouseScaleZoom, ButtonUtils
    from panda3d.core import GeomTriangles, Geom, GeomNode, GeomVertexFormat, GeomVertexData, GeomVertexWriter, LineSegs
    from direct.showbase.ShowBase import ShowBase
       
    vformat = GeomVertexFormat.getV3c4()
    vdata=GeomVertexData('tris', vformat, Geom.UHDynamic)

    vertex=GeomVertexWriter(vdata, 'vertex')
    color=GeomVertexWriter(vdata, 'color')
    
    colors = gen_color3(len(facegraph))
    numtris = 0
    for chart, data in facegraph.nodes_iter(data=True):
        curcolor = next(colors)
        for tri in data['tris']:
            triv = verts[vert_indices[tri]]
            vertex.addData3f(triv[0][0], triv[0][1], triv[0][2])
            vertex.addData3f(triv[1][0], triv[1][1], triv[1][2])
            vertex.addData3f(triv[2][0], triv[2][1], triv[2][2])
            color.addData4f(curcolor[0],curcolor[1], curcolor[2], 1)
            color.addData4f(curcolor[0],curcolor[1], curcolor[2], 1)
            color.addData4f(curcolor[0],curcolor[1], curcolor[2], 1)
            numtris += 1

    tris=GeomTriangles(Geom.UHDynamic)
    tris.addConsecutiveVertices(0, 3*numtris)
    tris.closePrimitive()
        
    linenodes = []
    if lineset:
        for lines in lineset:
            ls = LineSegs()
            ls.setThickness(4)
            curcolor = next(colors)
            ls.setColor(curcolor[0]/256.0, curcolor[1]/256.0, curcolor[2]/256.0, 1)
    
            tuples = False
            for blah in lines:
                if isinstance(blah, tuple):
                    tuples = True
                break
            if tuples:
                for i, j in lines:
                    frompt = verts[i]
                    topt = verts[j]
                    ls.moveTo(frompt[0], frompt[1], frompt[2])
                    ls.drawTo(topt[0], topt[1], topt[2])
            else:
                for i in range(len(lines)-1):
                    frompt = verts[lines[i]]
                    topt = verts[lines[i+1]]
                    ls.moveTo(frompt[0], frompt[1], frompt[2])
                    ls.drawTo(topt[0], topt[1], topt[2])
            
            linenodes.append(ls.create())
        

    pgeom = Geom(vdata)
    pgeom.addPrimitive(tris)

    node = GeomNode("primitive")
    node.addGeom(pgeom)

    p3dApp = ShowBase()
    #attachLights(render)
    geomPath = render.attachNewNode(node)

    for linenode in linenodes:
        geomPath.attachNewNode(linenode)
    
    #geomPath.setRenderModeWireframe()
    
    ensureCameraAt(geomPath, base.cam)
    
    boundingSphere = geomPath.getBounds()
    base.cam.setPos(boundingSphere.getCenter() + boundingSphere.getRadius())

    base.cam.lookAt(boundingSphere.getCenter())
    
    KeyboardMovement()
    ButtonUtils(geomPath)
    MouseDrag(geomPath)
    MouseScaleZoom(geomPath)
    #render.setShaderAuto()
    p3dApp.run()
Beispiel #59
0
    def __init__(self):
        ShowBase.__init__(self)
        winProps = WindowProperties()
        winProps.setTitle("Triangle and SimpleCircle Unittest")
        # base.win.requestProperties(winProps) (same as below e.g. self == base)
        self.win.requestProperties(winProps)


        # 1) create GeomVertexData
        frmt = GeomVertexFormat.getV3n3cp()
        vdata = GeomVertexData('triangle_developer', frmt, Geom.UHDynamic)

        # 2) create Writers/Rewriters (must all be created before any readers and readers are one-pass-temporary)
        vertex = GeomVertexRewriter(vdata, 'vertex')
        normal = GeomVertexRewriter(vdata, 'normal')
        color = GeomVertexRewriter(vdata, 'color')

        zUp = Vec3(0, 0, 1)
        wt = Vec4(1.0, 1.0, 1.0, 1.0)
        gr = Vec4(0.5, 0.5, 0.5, 1.0)

        # 3) write each column on the vertex data object (for speed, have a different writer for each column)
        def addPoint(x, y, z):
            vertex.addData3f(x, y, z)
            normal.addData3f(zUp)
            color.addData4f(wt)

        addPoint(0.0, 0.0, 0.0)
        addPoint(5.0, 0.0, 0.0)
        addPoint(0.0, 5.0, 0.0)
        addPoint(15.0, 15.0, 0.0)

        # 4) create a primitive and add the vertices via index (not truely associated with the actual vertex table, yet)
        tris = GeomTriangles(Geom.UHDynamic)
        t1 = Triangle(0, 1, 2, vdata, tris, vertex)
        t2 = Triangle(2, 1, 3, vdata, tris, vertex)
        c1 = t1.getCircumcircle()
        t1AsEnum = t1.asPointsEnum()
        r0 = (t1AsEnum.point0 - c1.center).length()
        r1 = (t1AsEnum.point1 - c1.center).length()
        r2 = (t1AsEnum.point2 - c1.center).length()
        assert abs(r0 - r2) < utilities.EPSILON and abs(r0 - r1) < utilities.EPSILON
        t2AsEnum = t2.asPointsEnum()
        c2 = t2.getCircumcircle()
        r0 = (t2AsEnum.point0 - c2.center).length()
        r1 = (t2AsEnum.point1 - c2.center).length()
        r2 = (t2AsEnum.point2 - c2.center).length()
        assert abs(r0 - r2) < utilities.EPSILON and abs(r0 - r1) < utilities.EPSILON

        assert t1.getAngleDeg0() == 90.0
        assert t1.getAngleDeg1() == t1.getAngleDeg2()

        oldInd0 = t1.pointIndex0
        oldInd1 = t1.pointIndex1
        oldInd2 = t1.pointIndex2
        t1.pointIndex0 = t1.pointIndex1
        t1.pointIndex1 = oldInd0
        assert t1.pointIndex0 == oldInd1
        assert t1.pointIndex1 == oldInd0
        assert t1.pointIndex0 != t1.pointIndex1
        t1.reverse()
        assert t1.pointIndex1 == oldInd2

        # 5.1) (adding to scene) create a Geom and add primitives of like base-type i.e. triangles and triangle strips
        geom = Geom(vdata)
        geom.addPrimitive(tris)
        # 5.2) create a GeomNode to hold the Geom(s) and add the Geom(s)
        gn = GeomNode('gnode')
        gn.addGeom(geom)
        # 5.3) attache the node to the scene
        gnNodePath = render.attachNewNode(gn)

        # setup a wire frame
        wireNP = render.attachNewNode('wire')
        wireNP.setPos(0.0, 0.0, .1)
        wireNP.setColor(0.1, 0.1, 0.1, 1)
        wireNP.setRenderMode(RenderModeAttrib.MWireframe, .5, 0)
        gnNodePath.instanceTo(wireNP)

        # test and draw intersections and circles
        pt1 = Point3(0.0, 5.0, 0.0)
        pt2 = Point3(1.0, 5.0, 0.0)
        intersection = t2.getIntersectionsWithCircumcircle(pt1, pt2)
        circle = t2.getCircumcircle()
        cuts = 128
        border = circle.getBorder(cuts, closed=True)
        assert len(border) == cuts or (len(border) == cuts + 1 and border[0] == border[len(border) - 1])
        n = len(border)
        xMid = yMid = 0
        for p in border:
            xMid += p.x
            yMid += p.y
        mid = Point3(xMid / n, yMid / n, border[0].z)
        assert mid.almostEqual(circle.center, 0.06)
        assert t2.isCcw()
        assert t1.containsPoint(c1.center) != t1.containsPoint(c1.center, includeEdges=False)

        circleSegs = LineSegs("circleLines")
        circleSegs.setColor(1.0, 0.0, 0.0, 1.0)
        for p in border:
            circleSegs.drawTo(*p)
        circleNode = circleSegs.create(False)
        circleNP = render.attachNewNode(circleNode)
        circleNP.setZ(-5)

        originSpot = LineSegs("intersection")
        originSpot.setColor(1.0, 0.0, 0.0, 1.0)
        originSpot.setThickness(10)
        for p in intersection:
            originSpot.drawTo(p)
        spotNode = originSpot.create(False)
        spotNP = render.attachNewNode(spotNode)
        circleNP.setZ(-0.75)

        # fix the camera rot/pos
        PHF.PanditorDisableMouseFunc()
        camera.setPos(0.0, 0.0, 50.0)
        camera.lookAt(c2.center)
        PHF.PanditorEnableMouseFunc()
Beispiel #60
0
class WartsApp(ShowBase):
    """
    The application running all the graphics.
    """

    def __init__(self, graphicsInterface):
        ShowBase.__init__(self)

        # This is available as a global, but pylint gives an undefined-variable
        # warning if we use it that way. Looking at
        #     https://www.panda3d.org/manual/index.php/ShowBase
        # I would have thought we could reference it as either
        # self.globalClock, direct.showbase.ShowBase.globalClock, or possibly
        # direct.showbase.globalClock, but none of those seems to work. To
        # avoid the pylint warnings, create self.globalClock manually.
        self.globalClock = ClockObject.getGlobalClock()

        self.graphicsInterface = graphicsInterface

        # Mapping from gids to entities.
        self.entities = {}

        # Set up event handling.
        self.mouseState = {}
        self.keys = {}
        self.setupEventHandlers()

        # Set up camera control.
        self.cameraHolder = self.render.attachNewNode('CameraHolder')
        self.cameraHolder.setPos(0, 0, 100)
        self.prevCameraHpr = (0, -80, 0)
        self.usingCustomCamera = True
        self.setCameraCustom()

        self.prevMousePos = None
        self.selectionBox = None
        self.selectionBoxNode = None
        self.selectionBoxOrigin = None
        # TODO[#3]: Magic numbers bad.
        self.resourceDisplay = OnscreenText(pos=(-0.98,.9),
                                            align=TextNode.ALeft,
                                            mayChange=True)

        # Define the ground plane by a normal (+z) and a point (the origin).
        self.groundPlane = core.Plane(core.Vec3(0, 0, 1), core.Point3(0, 0, 0))

        self.graphicsInterface.graphicsReady(self)

    def cleanup(self):
        pass

    def interfaceMessage(self, data):
        # Messages from GraphicsInterface to Graphics are always internal
        # client messages, so no need to catch InvalidMessageError.
        message = deserializeMessage(data)
        if isinstance(message, messages.Tick):
            pass
        elif isinstance(message, cmessages.AddEntity):
            self.addEntity(message.gid, message.pos, message.modelPath,
                           message.isExample, message.isUnit, message.goalSize)
        elif isinstance(message, cmessages.RemoveEntity):
            self.removeEntity(message.gid)
        elif isinstance(message, cmessages.MoveEntity):
            self.moveEntity(message.gid, message.pos)
        elif isinstance(message, cmessages.MarkEntitySelected):
            self.markSelected(message.gid, message.isSelected)
        elif isinstance(message, cmessages.DisplayResources):
            self.displayResources(message.resourceAmt)
        else:
            badIMessageCommand(message, log)

    def addEntity(self, gid, pos, modelPath, isExample, isUnit, goalSize):
        """
        pos is given in graphics coordinates.

        goalSize, if specified, is a pair (width, height) -- the model will be
        scaled in the xy plane so that it's as large as possible while still
        fitting within that width and height. Don't pass 0 as the width or the
        height, because that's just not nice.
        """

        if gid in self.entities:
            raise RuntimeError("Already have entity with gid {gid}."
                               .format(gid=gid))

        log.debug("Adding graphical entity %s at %s", gid, pos)
        x, y = pos

        if isExample:
            # The example panda from the Panda3D "Hello world" tutorial.
            # TODO[#9]: Figure out a more general way of specifying animations.
            model = Actor(modelPath,
                          {"walk": "models/panda-walk4"})
        else:
            model = self.loader.loadModel(getModelPath(modelPath))

        # Put the model in the scene, but don't position it yet.
        rootNode = self.render.attachNewNode("")
        model.reparentTo(rootNode)

        # Rescale the model about its origin. The x and y coordinates of the
        # model's origin should be chosen as wherever it looks like the model's
        # center of mass is, so that rotation about the origin (in the xy
        # plane) feels natural.

        goalWidthX, goalWidthY = goalSize

        bound1, bound2 = model.getTightBounds()
        modelWidthX = abs(bound2[0] - bound1[0])
        modelWidthY = abs(bound2[1] - bound1[1])

        # Scale it to the largest it can be while still fitting within the goal
        # rect. If the aspect ratio of the goal rect is different from that of
        # the model, then it'll only fill that rect in one dimension.
        # altScaleFactor is used for sanity checks below.
        scaleFactor, altScaleFactor = minmax(goalWidthX / modelWidthX,
                                             goalWidthY / modelWidthY)

        # Sanity check the scale factor.
        if scaleFactor <= 0.0:
            if scaleFactor == 0.0:
                log.warn("Graphical entity %s will be scaled negatively!", gid)
            else:
                log.warn("Graphical entity %s will be scaled to zero size.",
                         gid)
        else:
            # TODO[#9]: Currently the example panda triggers this warning.
            # TODO[#3]: Magic numbers bad.
            if altScaleFactor / scaleFactor > 1.001:
                log.warn("Graphical entity %s has different aspect ratio than "
                         "its model: model of size %.3g x %.3g being scaled "
                         "into %.3g x %.3g.",
                         gid, modelWidthX, modelWidthY, goalWidthX, goalWidthY)

        model.setScale(scaleFactor)

        # Place the model at z=0. The model's origin should be placed so that
        # this looks natural -- for most units this means it should be right at
        # the bottom of the model, but if we add any units that are intended to
        # float above the ground, then this can be accomplished by just
        # positioning the model above its origin.
        rootNode.setPos(x, y, 0.0)

        entity = Entity(gid, model, rootNode, isExample)
        self.entities[gid] = entity

        if isUnit:
            # TODO[#52]: Sigh. This is a terrible hack. I guess we could pipe
            # through yet another bool for "is this my unit", but I don't want
            # to have a growing collection of bools that need to be passed into
            # the graphics for each unit. For now, "is this an example model?"
            # and "is this my unit" are equivalent, so I guess we'll just
            # piggyback off of isExample....
            if isExample:
                entity.setIndicator(self.loader.loadModel(
                    getModelPath("unit-indicator-mine.egg")
                ))
            else:
                entity.setIndicator(self.loader.loadModel(
                    getModelPath("unit-indicator-notmine.egg")
                ))

    def removeEntity(self, gid):
        log.debug("Removing graphical entity %s", gid)
        entity = self.entities.pop(gid)
        entity.cleanup()

    def moveEntity(self, gid, newPos):
        log.debug("Moving graphical entity %s to %s", gid, newPos)
        entity = self.entities[gid]

        x, y = newPos
        oldX, oldY, oldZ = entity.rootNode.getPos()
        z = oldZ

        # Ensure the entity is facing the right direction.
        heading = math.atan2(y - oldY, x - oldX)
        heading *= 180.0 / math.pi
        # Magic angle adjustment needed to stop the panda always facing
        # sideways.
        # TODO[#9]: Establish a convention about which way _our_ models face;
        # figure out whether we need something like this. (Hopefully not?)
        heading += 90.0
        entity.rootNode.setHpr(heading, 0, 0)

        moveInterval = entity.rootNode.posInterval(config.TICK_LENGTH,
                                                   (x, y, z))
        moveInterval.start()

        if entity.isActor and "walk" in entity.model.getAnimNames():
            currFrame = entity.model.getCurrentFrame("walk")
            if currFrame is None:
                currFrame = 0
            # Supposedly, it's possible to pass a startFrame and a duration to
            # actorInterval, instead of calculating the endFrame ourself. But
            # for some reason, that doesn't seem to work; if I do that, then
            # the animation just keeps jumping around the early frames and
            # never gets past frame 5 or so. I'm not sure why. For now at
            # least, just calculate the endFrame ourselves to work around this.
            log.debug("Animating entity %s from frame %s/%s",
                      gid, currFrame, entity.model.getNumFrames("walk"))
            frameRate = entity.model.getAnimControl("walk").getFrameRate()
            endFrame = currFrame + int(math.ceil(frameRate *
                                                 config.TICK_LENGTH))
            animInterval = entity.model.actorInterval(
                "walk", loop=1, startFrame=currFrame, endFrame=endFrame
            )
            animInterval.start()

    def markSelected(self, gid, isSelected):
        log.debug("Marking graphical entity %s as %sselected",
                  gid, "" if isSelected else "not ")
        entity = self.entities[gid]

        if isSelected:
            entity.setIndicator(self.loader.loadModel(
                getModelPath("unit-indicator-selected.egg")
            ))
        else:
            # You can't currently select others' units, so if a unit is being
            # deselected it must be mine.
            entity.setIndicator(self.loader.loadModel(
                getModelPath("unit-indicator-mine.egg")
            ))

    def displayResources(self, resourceAmt):
        self.resourceDisplay.setText("Resource: {}".format(resourceAmt))

    def createSelectionBox(self, corner1, corner2):
        """
        Create a selection "box" given the coordinates of two opposite corners.
        The corners are given in world coordinates (well, 3d graphics
        coordinates).
        """

        assert self.selectionBox is None

        p1, p2, p3, p4 = self.convert3dBoxToScreen(corner1, corner2)
        x1, y1 = p1
        x2, y2 = p2
        x3, y3 = p3
        x4, y4 = p4

        # TODO[#3]: Magic numbers bad.
        self.selectionBox = LineSegs("SelectionBox")
        self.selectionBox.setThickness(3.0)
        self.selectionBox.setColor(0.0, 1.0, 0.25, 1.0)
        self.selectionBox.move_to(x1, 0, y1)
        self.selectionBox.draw_to(x2, 0, y2)
        self.selectionBox.draw_to(x3, 0, y3)
        self.selectionBox.draw_to(x4, 0, y4)
        self.selectionBox.draw_to(x1, 0, y1)

        self.selectionBoxNode = self.render2d.attachNewNode(
            self.selectionBox.create())

    def moveSelectionBox(self, corner1, corner2):
        assert self.selectionBox is not None

        p1, p2, p3, p4 = self.convert3dBoxToScreen(corner1, corner2)
        x1, y1 = p1
        x2, y2 = p2
        x3, y3 = p3
        x4, y4 = p4

        self.selectionBox.setVertex(0, x1, 0, y1)
        self.selectionBox.setVertex(1, x2, 0, y2)
        self.selectionBox.setVertex(2, x3, 0, y3)
        self.selectionBox.setVertex(3, x4, 0, y4)
        self.selectionBox.setVertex(4, x1, 0, y1)

    def removeSelectionBox(self):
        self.selectionBoxNode.removeNode()
        self.selectionBox     = None
        self.selectionBoxNode = None

    def convert3dBoxToScreen(self, corner1, corner3):
        """
        Return screen coordinates of the 4 corners of a box, given in 3d
        coordinates. The box is specified using 2 opposite corners.
        """

        wx1, wy1, wz1 = corner1
        wx3, wy3, wz3 = corner3

        wx2, wy2 = (wx1, wy3)
        wx4, wy4 = (wx3, wy1)

        # Note: corner1 and corner2 could have nonzero z because floating-point
        # calculations, but they should at least be close. We'll just average
        # their z and not worry about it.
        wz2 = wz4 = 0.5 * (wz1 + wz3)

        p1 = self.coord3dToScreen((wx1, wy1, wz1))
        p2 = self.coord3dToScreen((wx2, wy2, wz2))
        p3 = self.coord3dToScreen((wx3, wy3, wz3))
        p4 = self.coord3dToScreen((wx4, wy4, wz4))

        return (p1, p2, p3, p4)

    def setCameraCustom(self):
        """
        Change to using our custom task to control the camera.
        """

        # Disable the default mouse-based camera control task, so we don't have
        # to fight with it for control of the camera.
        self.disableMouse()

        # Face the camera in the appropriate angle.
        self.camera.setHpr(self.prevCameraHpr)

        # Put it in the same location as the cameraHolder, and make it stay
        # put relative to the cameraHolder (so we can move the camera around by
        # changing the cameraHolder's position).
        self.camera.reparentTo(self.cameraHolder)
        self.camera.setPos(0, 0, 0)

        # Substitute our own camera control task.
        self.taskMgr.add(self.updateCameraTask, "UpdateCameraTask")

        self.usingCustomCamera = True

        # Need a task to handle mouse-dragging because there doesn't seem to be
        # a built-in mouseMove event.
        self.taskMgr.add(self.mouseMoveTask, "MouseMoveTask")

    def setCameraDefault(self):
        """
        Change to using the default mouse-based camera controls.
        """

        self.taskMgr.remove("UpdateCameraTask")

        # Save current location for when this control style is restored.
        self.prevCameraHpr = self.camera.getHpr()

        # Use the existing camera location, rather than jumping back to the one
        # from last time the default camera controller was active.
        # Copied from https://www.panda3d.org/manual/index.php/Mouse_Support
        mat = Mat4(self.camera.getMat())
        mat.invertInPlace()
        self.mouseInterfaceNode.setMat(mat)
        self.enableMouse()

        self.usingCustomCamera = False

    def toggleCameraStyle(self):
        """
        Switch to whichever style of camera control isn't currently active.
        """

        if self.usingCustomCamera:
            self.setCameraDefault()
        else:
            self.setCameraCustom()

    # We don't use task, but we can't remove it because the function signature
    # is from Panda3D.
    def updateCameraTask(self, task):  # pylint: disable=unused-argument
        """
        Move the camera sensibly.
        """

        dt = self.globalClock.getDt()
        translateSpeed = 30 * dt
        rotateSpeed    = 50 * dt

        # Separately track whether the camera should translate in each of the 4
        # directions. These 4 are initialized based on the various inputs that
        # might tell us to scroll, and different inputs saying the same thing
        # don't stack. That way if we get inputs saying both "left" and
        # "right", they can cancel and the camera just won't move along that
        # axis -- even if, say, there are two inputs saying "left" and only one
        # saying "right'.
        moveLeft  = self.keys["arrow_left"]
        moveRight = self.keys["arrow_right"]
        moveUp    = self.keys["arrow_up"]
        moveDown  = self.keys["arrow_down"]

        # Check if the mouse is over the window.
        if self.mouseWatcherNode.hasMouse():
            # Get the position.
            # Each coordinate is normalized to the interval [-1, 1].
            mousePos = self.mouseWatcherNode.getMouse()
            xPos, yPos = mousePos.getX(), mousePos.getY()
            # Only move if the mouse is close to the edge, and actually within
            # the window.
            if  (1.0 - EDGE_SCROLL_WIDTH) < xPos <=  1.0:
                moveRight = 1
            if -(1.0 - EDGE_SCROLL_WIDTH) > xPos >= -1.0:
                moveLeft  = 1
            if  (1.0 - EDGE_SCROLL_WIDTH) < yPos <=  1.0:
                moveUp    = 1
            if -(1.0 - EDGE_SCROLL_WIDTH) > yPos >= -1.0:
                moveDown  = 1

        forward  = translateSpeed * (moveUp    - moveDown)
        sideways = translateSpeed * (moveRight - moveLeft)
        self.cameraHolder.setPos(self.cameraHolder, sideways, forward, 0)

        if sideways != 0 or forward != 0:
            self.updateSelectionBox()

        rotate = rotateSpeed * (self.keys["a"] - self.keys["d"])
        self.cameraHolder.setHpr(self.cameraHolder, rotate, 0, 0)

        return Task.cont

    def zoomCamera(self, inward):
        """
        Zoom in or out.
        """

        dt = self.globalClock.getDt()
        zoomSpeed = 100 * dt

        zoom = -zoomSpeed if inward else zoomSpeed
        self.cameraHolder.setPos(self.cameraHolder, 0, 0, zoom)

    def centerView(self):
        """
        Center the view sensibly.
        """

        message = cmessages.RequestCenter()
        self.graphicsInterface.graphicsMessage(message.serialize())

    # We don't use task, but we can't remove it because the function signature
    # is from Panda3D.
    def mouseMoveTask(self, task):  # pylint: disable=unused-argument
        """
        Handle mouse movement.
        """

        mousePos = self.getMousePos()

        # NOTE: We don't handle clicking and dragging at the same time.
        if mousePos is not None and mousePos != self.prevMousePos:
            for (buttonId, state) in self.mouseState.iteritems():
                state.lastPos = mousePos
                if state.hasMoved:
                    self.handleMouseDragMove(buttonId, state.modifiers,
                                             state.startPos, mousePos)
                else:
                    startX, startY = state.startPos
                    mouseX, mouseY = mousePos
                    distance = math.hypot(mouseX - startX, mouseY - startY)
                    # TODO[#3]: Magic numbers bad.
                    # Check if the mouse has moved outside the dead zone.
                    if distance > 0.0314:
                        self.handleMouseDragStart(buttonId, state.modifiers,
                                                  state.startPos, mousePos)
                        state.hasMoved = True

        if mousePos != self.prevMousePos:
            self.prevMousePos = mousePos

        return Task.cont

    def pandaEventMouseDown(self, buttonId, modifiers):
        if buttonId in self.mouseState:
            # Call pandaEventMouseUp just to clear any state related to the
            # button being down, so we can handle this buttonDown event as if
            # it were a fresh press of the button.
            log.warn("Mouse button %s is already down.", buttonId)
            self.pandaEventMouseUp(buttonId)

        assert buttonId not in self.mouseState

        state = MouseButtonState(modifiers[:], self.getMousePos())
        self.mouseState[buttonId] = state

    def pandaEventMouseUp(self, buttonId):
        if buttonId not in self.mouseState:
            # Drop the event, since there's nothing to do.
            log.warn("Mouse button %s is already up.", buttonId)
            return

        state = self.mouseState[buttonId]

        if state.hasMoved:
            endPos = self.getMousePos()
            if endPos is None:
                endPos = state.lastPos
            self.handleMouseDragEnd(buttonId, state.modifiers,
                                    state.startPos, endPos)
        else:
            self.handleMouseClick(buttonId, state.modifiers, state.startPos)

        del self.mouseState[buttonId]

    def handleMouseClick(self, button, modifiers, pos):
        # Make sure the mouse is inside the screen
        # TODO: Move this check to pandaEventMouseUp?
        if self.mouseWatcherNode.hasMouse() and self.usingCustomCamera:
            x, y, _z = self.coordScreenTo3d(pos)

            if modifiers == []:
                # TODO: This component should take care of decoding the
                # click as far as "left" or "right"; we shouldn't send a
                # numerical button id to the graphicsInterface.
                message = cmessages.Click(button, (x, y))
            elif button == 1 and modifiers == ["shift"]:
                message = cmessages.ShiftLClick((x, y))
            elif button == 1 and modifiers == ["control"]:
                message = cmessages.ControlLClick((x, y))
            elif button == 3 and modifiers == ["shift"]:
                message = cmessages.ShiftRClick((x, y))
            elif button == 3 and modifiers == ["control"]:
                message = cmessages.ControlRClick((x, y))
            else:
                thisShouldNeverHappen(
                    "Unhandled modifiers for click: {}".format(modifiers))

            self.graphicsInterface.graphicsMessage(message.serialize())

    def handleMouseDragStart(self, buttonId, modifiers, startPos, endPos):
        log.debug("Start dragging from %s to %s", startPos, endPos)

        if buttonId == 1 and modifiers == []:
            assert self.selectionBoxOrigin is None
            self.selectionBoxOrigin = self.coordScreenTo3d(startPos)
            endPos = self.coordScreenTo3d(endPos)
            self.createSelectionBox(self.selectionBoxOrigin, endPos)

    def handleMouseDragMove(self, buttonId, modifiers, startPos, endPos):
        log.debug("Continue dragging from %s to %s", startPos, endPos)

        if buttonId == 1 and modifiers == []:
            assert self.selectionBoxOrigin is not None
            endPos = self.coordScreenTo3d(endPos)
            self.moveSelectionBox(self.selectionBoxOrigin, endPos)

    def handleMouseDragEnd(self, buttonId, modifiers, startPos, endPos):
        log.debug("End dragging from %s to %s", startPos, endPos)

        if buttonId == 1 and modifiers == []:
            # Actually select the units.
            endPos = self.coordScreenTo3d(endPos)
            # TODO[#55]: Use 3d graphics coords in messages so we don't have to
            # remove the z coordinates everywhere.
            message = cmessages.DragBox(self.selectionBoxOrigin[:2],
                                        endPos[:2])
            self.graphicsInterface.graphicsMessage(message.serialize())
            # Clear the selection box; we're done dragging.
            self.selectionBoxOrigin = None
            self.removeSelectionBox()

    def updateSelectionBox(self):
        if self.selectionBoxOrigin is not None:
            mousePos = self.getMousePos()
            if mousePos is not None:
                endPos = self.coordScreenTo3d(mousePos)
                self.moveSelectionBox(self.selectionBoxOrigin, endPos)

    def getMousePos(self):
        # Check if the mouse is over the window.
        if self.mouseWatcherNode.hasMouse():
            # Get the position.
            # Each coordinate is normalized to the interval [-1, 1].
            mousePoint = self.mouseWatcherNode.getMouse()
            # Create a copy of mousePoint rather than returning a reference to
            # it, because mousePoint will be modified in place by Panda.
            return (mousePoint.getX(), mousePoint.getY())
        else:
            return None

    def handleWindowClose(self):
        log.info("Window close requested -- shutting down client.")
        message = cmessages.RequestQuit()
        self.graphicsInterface.graphicsMessage(message.serialize())

    def setupEventHandlers(self):
        def pushKey(key, value):
            self.keys[key] = value

        for key in ["arrow_up", "arrow_left", "arrow_right", "arrow_down",
                    "w", "a", "d", "s"]:
            self.keys[key] = False
            self.accept(key, pushKey, [key, True])
            self.accept("shift-%s" % key, pushKey, [key, True])
            self.accept("%s-up" % key, pushKey, [key, False])

        # Camera toggle.
        self.accept("f3",       self.toggleCameraStyle, [])
        self.accept("shift-f3", self.toggleCameraStyle, [])

        # Center view.
        self.accept("space", self.centerView, [])

        # Handle mouse wheel.
        self.accept("wheel_up", self.zoomCamera, [True])
        self.accept("wheel_down", self.zoomCamera, [False])

        # Handle clicking.
        self.accept("mouse1",    self.pandaEventMouseDown, [1, []])
        self.accept("mouse1-up", self.pandaEventMouseUp,   [1])
        # TODO: Make sure this is always the right mouse button.
        self.accept("mouse3",    self.pandaEventMouseDown, [3, []])
        self.accept("mouse3-up", self.pandaEventMouseUp,   [3])

        # Handle clicking with modifier keys.
        self.accept("shift-mouse1",   self.pandaEventMouseDown,
                    [1, ["shift"]])
        self.accept("control-mouse1", self.pandaEventMouseDown,
                    [1, ["control"]])
        self.accept("shift-mouse3",   self.pandaEventMouseDown,
                    [3, ["shift"]])
        self.accept("control-mouse3", self.pandaEventMouseDown,
                    [3, ["control"]])

        # Handle window close request (clicking the X, Alt-F4, etc.)
        self.win.set_close_request_event("window-close")
        self.accept("window-close", self.handleWindowClose)

    def coord3dToScreen(self, coord3d):
        # Empirically, Lens.project takes coordinates in the *camera*'s
        # coordinate system, not its parent or the render. This was not very
        # clear from the documentation, and you'd be surprised how long it took
        # us to figure this out. Anyway, we need to convert the point to be
        # relative to self.camera here; otherwise we'll get bizarre,
        # nonsensical, and hard-to-debug results.
        coord3d = self.camera.getRelativePoint(self.render, coord3d)
        screenCoord = Point2()
        if not self.camLens.project(coord3d, screenCoord):
            log.debug("Attempting 3d-to-screen conversion on point outside of "
                      "camera's viewing frustum.")

        # Convert to a tuple to ensure no one else is keeping a reference
        # around.
        x, y = screenCoord
        return (x, y)

    def coordScreenTo3d(self, screenCoord):
        x, y = screenCoord
        screenPoint = Point2(x, y)

        # Do this calculation using simple geometry, rather than the absurd
        # collision-traversal nonsense we used to use. Thanks to
        #     https://www.panda3d.org/forums/viewtopic.php?t=5409
        # for pointing us at the right methods to make this work.

        # Get two points along the ray extending from the camera, in the
        # direction of the mouse click.
        nearPoint = Point3()
        farPoint = Point3()
        self.camLens.extrude(screenPoint, nearPoint, farPoint)

        # These points are relative to the camera, so need to be converted to
        # be relative to the render. Thanks to the example code (see link
        # above) for saving us probably some hours of debugging figuring that
        # one out again :)
        nearPoint = self.render.getRelativePoint(self.camera, nearPoint)
        farPoint  = self.render.getRelativePoint(self.camera, farPoint)

        intersection = Point3()
        if self.groundPlane.intersectsLine(intersection, nearPoint, farPoint):
            # Convert to a tuple to ensure no one else is keeping a reference
            # around.
            x, y, z = intersection
            return (x, y, z)

        # The ray didn't intersect the ground. This is almost certainly going
        # to happen at some point; all you have to do is find a way to aim the
        # camera (or manipulate the screen coordinate) so that the ray points
        # horizontally. But we don't have code to handle it, so for now just
        # abort.
        thisIsNotHandled()