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 drawLineSegments(self, scnObjs): #Point will be origin of line segments ls = LineSegs() ls.setThickness(5) ind = 0 for scnobj in scnObjs: point = scnobj.pos a0 = scnobj.a0 a1 = scnobj.a1 a2 = scnobj.a2 #Draw th new threes ls.setColor(1, 0, 0, 0.7) ls.moveTo(float(point[0]), float(point[1]), float(point[2])) ls.drawTo(float(point[0] + a0[0]), point[1] + float(a0[1]), point[2] + float(a0[2])) ls.setColor(0, 1, 0, 0.7) ls.moveTo(float(point[0]), float(point[1]), float(point[2])) ls.drawTo(float(point[0] + a1[0]), point[1] + float(a1[1]), point[2] + float(a1[2])) ls.setColor(0, 0, 1, 0.7) ls.moveTo(float(point[0]), float(point[1]), float(point[2])) ls.drawTo(float(point[0] + a2[0]), point[1] + float(a2[1]), point[2] + float(a2[2])) #ls.setColor(1,0,0,0.7) ind += 1 linegeomn = ls.create(dynamic=False) # Creates a geomnode nodePath = self.render.attachNewNode(linegeomn) self.linesegs.append(nodePath)
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 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 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 createCurve(self): self.curve = [] self.progress = 0 self.showCurve = True lineThickness = 2 ls = LineSegs("LogSpiral") ls.setThickness(lineThickness) iteration_count = 10001 step_delta = 0.001 curve_length = step_delta * iteration_count for index in np.arange(1 + (curve_length * self.truncate_percentage), curve_length, step_delta): # Calculate curve point position spiral_x = self.radius_scale * self.a * pow( math.e, self.k * index) * math.cos(index) spiral_y = self.radius_scale * self.a * pow( math.e, self.k * index) * math.sin(index) spiral_z = self.height_scale * self.height_scale * math.log( index, math.e) + self.lower_bound if (self.showCurve): ls.drawTo(spiral_x, spiral_y, spiral_z) self.curve.append(Vec3(spiral_x, spiral_y, spiral_z)) self.curve.reverse() if (self.curve_segment != None): self.curve_segment.removeNode() node = ls.create(dynamic=False) body = BulletRigidBodyNode("lsRB") bodyNP = self.worldNP.attachNewNode(body) self.curve_segment = bodyNP.attachNewNode(node) if (not self.show_curve): self.curve_segment.hide()
def createAxesCross(name, size, has_labels): def createAxisLine(label, color, draw_to): coords.setColor(color) coords.moveTo(0, 0, 0) coords.drawTo(draw_to) # Put the axis' name in the tip if label != "": text = TextNode(label) text.setText(label) text.setTextColor(color) axis_np = coords_np.attachNewNode(text) else: axis_np = coords_np.attachNewNode("") axis_np.setPos(draw_to) return axis_np coords_np = NodePath(name) coords = LineSegs() coords.setThickness(2) axis_x_np = createAxisLine("X" if has_labels else "", Color3D.RED, (size, 0, 0)) axis_y_np = createAxisLine("Y" if has_labels else "", Color3D.GREEN, (0, size, 0)) axis_z_np = createAxisLine("Z" if has_labels else "", Color3D.BLUE, (0, 0, size)) np = coords.create(True) coords_np.attachNewNode(np) return coords_np, axis_x_np, axis_y_np, axis_z_np
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 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 __init__(self): """ """ TQGraphicsNodePath.__init__(self) ls = LineSegs() ls.setThickness(1) # X axis ls.setColor(1.0, 0.0, 0.0, 1.0) ls.moveTo(0.0, 0.0, 0.0) ls.drawTo(1.0, 0.0, 0.0) # Y axis ls.setColor(0.0, 1.0, 0.0, 1.0) ls.moveTo(0.0, 0.0, 0.0) ls.drawTo(0.0, 1.0, 0.0) # Z axis ls.setColor(0.0, 0.0, 1.0, 1.0) ls.moveTo(0.0, 0.0, 0.0) ls.drawTo(0.0, 0.0, 1.0) geomnode = ls.create() self.set_p3d_nodepath(NodePath(geomnode)) self.setLightOff(1)
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 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 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 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 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 update_LFP(self, dt, last_lfp, lfp_trace, offset, gen_lfp): # lfp data is taken at 1000Hz, and dt is the number of seconds since # the last frame was flipped, so plot number of points = dt * 1000 lfp = LineSegs() lfp.setThickness(1.0) #print('points to plot', int(dt * 1000)) #self.lfp_test += int(dt * 1000) #print('points so far', self.lfp_test) for i in range(int(dt * 1000)): try: last_lfp.append((next(gen_lfp) * self.lfp_gain) + offset) #last_lfp_x += 0.05 # only plotting 200 data points at a time while len(last_lfp) > 3500: last_lfp.pop(0) except StopIteration: #print('done with lfp') break if lfp_trace: lfp_trace[0].removeNode() lfp_trace.pop(0) lfp.moveTo(self.start_x_trace, 55, last_lfp[0]) x = self.start_x_trace for i in last_lfp: x += .1 lfp.drawTo(x, 55, i) node = self.base.pixel2d.attachNewNode(lfp.create()) lfp_trace.append(node)
def plot_eye_trace(self, first_eye): # print 'plot trace' # if plotting too many eye positions, things slow down and # python goes into lala land. Never need more than 500, and # last 300 is definitely plenty, so every time it hits 500, # get rid of first 200. if len(self.eye_nodes) > 500: # print('get rid of eye nodes', len(self.eye_nodes)) # Since this just removes the node, but doesn't delete # the object in the list, can do this in a for loop, for index in range(200): self.eye_nodes[index].removeNode() # now get rid of the empty nodes in eye_nodes # print('new length', len(self.eye_nodes)) self.eye_nodes = self.eye_nodes[200:] # print('new length', len(self.eye_nodes)) eye = LineSegs() # eye.setThickness(2.0) eye.setThickness(2.0) # print 'last', last_eye # print 'now', self.current_eye_data eye.moveTo(first_eye[0], 55, first_eye[1]) for data_point in self.current_eye_data: eye.drawTo(data_point[0], 55, data_point[1]) # print('plotted eye', eye_data_to_plot) node = self.base.render.attachNewNode(eye.create(True)) node.show(BitMask32.bit(0)) node.hide(BitMask32.bit(1)) self.eye_nodes.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 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 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 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 drawHilbertCurve(pts): # 2n + c for p in range(len(pts) - 1): # n seg = LineSegs() # c seg.setThickness(3) # c seg.draw_to(pts[p][0], 0, pts[p][2]) # c seg.draw_to(pts[p + 1][0], 0, pts[p + 1][2]) # c node = seg.create() # c nodes.append(node) # c for node in nodes: # n base.aspect2d.attach_new_node(node) # c
def plot_border(self): border = LineSegs() border.setThickness(2.0) corner = self.win_size/100 * 5/6 #print('corner', corner) border.move_to(corner, 25, corner) border.draw_to(corner, 25, -corner) border.draw_to(-corner, 25, -corner) border.draw_to(-corner, 25, corner) border.draw_to(corner, 25, corner) self.base.render.attach_new_node(border.create(True))
def draw_cross(self, deg_per_pixel): cross = LineSegs() cross.setThickness(2.0) # cross hair is 1/2 degree visual angle, # so go 1/4 on each side dist_from_center = 0.25 / deg_per_pixel cross.moveTo(0 + dist_from_center, 55, 0) cross.drawTo(0 - dist_from_center, 55, 0) cross.moveTo(0, 55, 0 - dist_from_center) cross.drawTo(0, 55, 0 + dist_from_center) self.x_node = self.base.render.attachNewNode(cross.create(True)) self.x_node.hide()
def __init__(self, widget, axis): TransformWidgetAxis.__init__(self, widget, axis) segs = LineSegs() segs.setThickness(2) vertices = LEUtils.circle(0, 0, 1, 64) for i in range(len(vertices)): x1, y1 = vertices[i] x2, y2 = vertices[(i + 1) % len(vertices)] segs.moveTo(x1, 0, y1) segs.drawTo(x2, 0, y2) self.axisCircle = self.attachNewNode(segs.create()) self.axisCircle.setAntialias(AntialiasAttrib.MLine)
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 drawWheelBase(self): wheelSegs = LineSegs("wheelBase") wheelSegs.setThickness(5) wheelSegs.moveTo(self.wheelFront + Vec3(0.0, 5.0, 1.44)) wheelSegs.drawTo(self.wheelFront + Vec3(0.0, -5.0, 1.44)) wheelSegs.moveTo(self.wheelBack + Vec3(0.0, 5.0, 1.44)) wheelSegs.drawTo(self.wheelBack + Vec3(0.0, -5.0, 1.44)) wheelNode = wheelSegs.create() wheelNodePath = self.car.attachNewNode(wheelNode) return wheelNodePath
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 _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 __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 __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 __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 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 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 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 _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 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 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 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 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): 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 __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()
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()
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()