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
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_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
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]
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()
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()
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
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
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
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
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)
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
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)
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)
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( )
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)
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)
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)
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))
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)
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 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)
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
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)
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
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())
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)
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)
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())
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'])
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())
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)
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'])
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)
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)
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)
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)
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)
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
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())
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 + " ")
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()))
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)
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)
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
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()
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()
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()
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()