def cmd_rotate(self, keysym): """ Create current shape :keysym: key / - Rotate between shapes in place TBD - other direction... """ if keysym == 'slash': heading_chg = 45 cmd_last = self.last_marker_command() marker_last = self.last_marker() if marker_last is None: new_heading = self.get_heading() + heading_chg marker = DmHeading(self, heading=new_heading) cmd = DrawingCommand(f"cmd_{keysym}") cmd.add_markers(marker) else: self.undo_last_marker_command() # undo to last marker cmd = DrawingCommand(f"cmd_{keysym}") marker = marker_last.copy() marker = marker.use_locale(marker_last) new_heading = marker.get_heading() + heading_chg marker = marker.change(heading=new_heading) cmd.add_markers(marker) return cmd.do_cmd() SlTrace.report(f"Unrecognized rotate command: {keysym}")
def text_cmd(self, keysym): """ Do command in text mode Enter text unless special command END - go back to figure drawing mode Right, Left, Up, Down - do motions Return - go to next line """ SlTrace.lg(f"text_cmd({keysym})") if keysym.lower() == "space": # Support symbolic keysym = " " if keysym == "BackSpace": return self.command_manager.undo() if keysym.lower() == 'end': self.set_drawing_mode() return True if keysym == "Return" or keysym == "ENTER": self.cmd_newline() return True if keysym in ['Right', 'Left', 'Up', 'Down']: self.drawing_cmd(keysym) return cmd = DrawingCommand(f"cmd_{keysym}") marker = DmText(self, text=keysym) cmd.add_marker(marker) return cmd.do_cmd() SlTrace.report(f"Don't recognize text {keysym}" f" as a text_cmd") return False
def report(self, msg): """ Report message with popup identifying us as the area :msg: message to display """ msg_display = f"Player Control: {msg}" SlTrace.lg(msg_display) SlTrace.report(msg_display)
def save_file(self, file_name): out_file = file_name if file_name is None: out_file = "new_gpx_" + SlTrace.getTs() if not os.path.isabs(out_file): out_file = os.path.basename(out_file) out_file = os.path.join("..", "new_data", out_file) pm = re.match(r'^.*\.[^.]+$', out_file) if pm is None: out_file += ".gpx" out_file = os.path.abspath(out_file) SlTrace.lg(f"Output file: {out_file}") gpx_attr = {'version' : "1.1", 'creator' : "GDAL 3.0.4", 'xmlns:xsi' : "http://www.w3.org/2001/XMLSchema-instance", 'xmlns:ogr' : "http://osgeo.org/gdal", 'xmlns' : "http://www.topografix.com/GPX/1/1", 'xsi:schemaLocation' : "http://www.topografix.com/GPX/1/1", } gpx_top = Element('gpx', gpx_attr) generated_on = str(datetime.datetime.now()) comment = Comment(f"Created {generated_on} via surveyor.py by crs") gpx_top.append(comment) comment = Comment(f"Source code: GitHub raysmith619/PlantInvasion") gpx_top.append(comment) n_seg = 0 n_pt = 0 for track_segment in self.get_segments(): trk = SubElement(gpx_top, 'trk') ###gpx_top.append(trk) trkseg = SubElement(trk, 'trkseg') # We only have one trkseg per trk ###trk.append(trkseg) n_seg += 1 for seg_point in track_segment.get_points(): trkpt = SubElement(trkseg, 'trkpt', {'lat' : str(seg_point.lat), 'lon' : str(seg_point.long), }) ###trkseg.append(trkpt) n_pt += 1 SlTrace.lg(f"GPX File: {n_seg} segments {n_pt} points") pretty_str = prettify(gpx_top) if SlTrace.trace("gpx_output"): SlTrace.lg(pretty_str) if SlTrace.trace("gpx_rough_outupt"): rough_string = ElementTree.tostring(gpx_top, 'utf-8') SlTrace.lg(f"rough_string:{rough_string}") try: fout = open(out_file, "w") fout.write(pretty_str) fout.close() except IOError as e: err_msg = f"Error {repr(e)} in creating GPXFile {out_file}" SlTrace.lg(err_msg) SlTrace.report(err_msg)
def cmd_add_new_direction(self, keysym): """ Add copy of current marker/figure in new direction 7 8 9 4 5 6 1 2 4 0 """ dig2head = { '6': 0, '9': 45, '8': 90, '7': 135, '4': 180, '1': 225, '2': 270, '3': 315, '6': 0, } cur_heading = self.get_heading() if keysym == '0': new_heading = cur_heading - 45 elif keysym == '5': new_heading = cur_heading + 45 elif keysym not in dig2head: SlTrace.report(f"{keysym} is not a recogized new direction") return False else: new_heading = dig2head[keysym] cmd_last = self.last_marker_command() marker_last = self.last_marker() cmd = DrawingCommand(f"cmd_{keysym}") if marker_last is None: new_color = self.get_next("color") new_shape_type = self.get_next("shape") marker = self.make_shape(shape=new_shape_type) marker = marker.change(color=new_color, heading=new_heading) else: color_change = self.get_next_change("color") if color_change != "constant": new_color = self.get_next("color") else: new_color = None # No change - maybe special marker = marker_last.copy() x_cor, y_cor = marker_last.get_next_loc() marker = marker.change(x_cor=x_cor, y_cor=y_cor, color=new_color, heading=new_heading) cmd.add_markers(marker) return self.do_cmd(cmd)
def our_quit(flag=None): """ Test for traceButton :flag: flag arg """ global quit_set if flag is None: flag = "TBD" SlTrace.lg(f"our_quit({flag})") SlTrace.report("Quitting Program") root.destroy quit_set = True sys.exit()
def image_file_to_info(self, display_file): """ Convert file name(key) to image_info(key, image) :display_file: display file name/key :returns: image_info (key, image) None if can't get it """ image = self.image_file_to_image(display_file) if image is None: SlTrace.report(f"Can't load image:{display_file}") return None return (display_file, image)
def cmd_size_adjust(self, keysym): """ Adjust marker size a - reduce length q - increase length t - widen line r - narrow line """ len_mult = 1.2 min_width = 2 width_mult = 1.3 sym_to_size = {'a', 'q', 't', 'r'} if keysym not in sym_to_size: SlTrace.report( f"Not a recognized size descripiton keysym:{keysym}") return False side = self.get_side() width = self.get_width() new_side = new_width = None # Set, if changed if keysym == 'a': new_side = side / len_mult elif keysym == 'q': new_side = side * len_mult elif keysym == 'r': if width <= min_width: return False new_width = width / width_mult elif keysym == 't': new_width = width * width_mult else: raise SelectError(f"Unrecognized resize cmd: {keysym}") cmd_last = self.last_marker_command() marker_last = self.last_marker() if marker_last is None: marker = DmSize(self, side=new_side, line_width=new_width) cmd = DrawingCommand(f"cmd_{keysym}") cmd.add_markers(marker) else: #self.undo_last_marker_command() # undo to last marker ###cmd = cmd_last.reverse_copy() cmd = DrawingCommand(f"cmd_{keysym}") marker = marker_last marker = marker.use_locale(marker_last) marker = marker.change(side=new_side, line_width=new_width) cmd.add_prev_markers(marker_last) cmd.add_markers(marker) return cmd.do_cmd()
def cmd_visibility_adjust(self, keysym): """ Adjust visibility minus - penup plus = pendown """ sym_to_pen_desc = {'minus': "penup", 'plus': "pendown"} if keysym not in sym_to_pen_desc: SlTrace.report( f"Not a recognized pen descripiton keysym: {keysym}") return False marker = DmPen(self, keysym) cmd = DrawingCommand(f"cmd_{keysym}") cmd.add_marker(marker) return cmd.do_cmd()
def drawing_cmd(self, keysym): """ Do figure drawing command :keysym: key symbol recognizes \w+\([^)]*\) as a function call """ if keysym == 'e' or keysym == "End": self.set_text_mode(keysym) return keysym = self.key_to_sym(keysym) # Translate if necess dr_fun = self.get_key_fun(keysym) if dr_fun is None: SlTrace.report(f"Don't recognize drawing key cmd:" f" {keysym}") return dr_fun(keysym)
def cmd_image_file(self, group=None, file=None): """ create marker at current location, heading from group of name :group: group name (e.g. animals, family) :name: first file in group which contains the name string """ image_file = self.get_image_file(group=group, file=file, next=True) if image_file is None: SlTrace.report(f"No image file group {group}" f" groups: {self.image_group_names}") return False image_base = self.drawer.image_file_to_image(image_file) if image_base is None: raise SelectError(f"Can't get image from {image_file}") return self.cmd_do_image(file=image_file, image_base=image_base)
def make_image(self, group=None, file=None): """ Create genaric marker of given image :group: image group e.g. animals, family, ... :file: sub file name e.g. alex, first partial match default: next :returns: DmImage marker, None if none """ image_file = self.get_image_file(group=group, file=file, next=True) if image_file is None: SlTrace.report(f"No image file group {group}" f" groups: {self.image_group_names}") return False image_base = self.drawer.image_file_to_image(image_file) if image_base is None: raise SelectError(f"Can't get image from {image_file}") marker = DmImage(self, file=image_file, image_base=image_base) return marker
def cmd_color_adjust(self, keysym): """ Color adjustments w - rotating colors equal - choose color """ if keysym == 'w': self.set_next_change("color", "ascending") color = self.get_next("color") elif keysym == "equal": color_choice = colorchooser.askcolor() SlTrace.lg(f"color_choice: {color_choice}") if color_choice is None or color_choice[1] is None: return self.set_next_change("color", "constant") color = color_choice[1] self.add_next_change_value("color", value=color) else: SlTrace.report(f"Unrecognized color adjust: {keysym}") marker = DmColor(self, color=color) cmd_last = self.last_marker_command() marker_last = self.last_marker() if marker_last is None: marker = DmColor(self, color=color) cmd = DrawingCommand(f"cmd_{keysym}") cmd.add_markers(marker) else: #self.undo_last_marker_command() # undo to last marker ###cmd = cmd_last.reverse_copy() cmd = DrawingCommand(f"cmd_{keysym}") marker = marker_last marker = marker.use_locale(marker_last) marker = marker.change(color=color) cmd.add_prev_markers(marker_last) cmd.add_markers(marker) return cmd.do_cmd()
def marker_set(self, marker=None, changing=None, choose=None): """ Event marker setting :marker: marker to set :changing: auto changing markers :choose: True: prompt user for marker """ if choose: """ Prompt user for marker """ x0 = 300 y0 = 400 width = 200 height = 400 SlTrace.lg(f"x0={x0}, y0={y0}, width={width}, height={height}", "choose") select_image_files = self.get_image_files() select_image_hash = self.get_select_image_hash() app = SelectList(items=select_image_files, image_hash=select_image_hash, default_to_files=True, title="Marker Images", position=(x0, y0), size=(width, height)) selected_field = app.get_selected(return_text=True) SlTrace.lg(f"image_image: selected_field:{selected_field}", "choose") if selected_field is None: return self.image_chosen = self.image_file_to_info(selected_field) if self.image_chosen is None: SlTrace.report(f"Sorry, can't load image {selected_field}") return self.marker_chosen = selected_field SlTrace.lg(f"self.image_chosen={self.image_chosen}") self.set_marker(marker="image", changing=False) self.do_marker() else: self.set_marker(marker=marker, changing=changing)
def choose_color(self, widget=None): """ Facilitate chaning color (forground and background) with tkinter.colorchooser) :widget: widget to colorize default: use selected widget, if one """ if widget is None: widget = self.selected_widget if widget is None: SlTrace.report("No entry is selected") return if widget in self.player_field_by_widget: (player, field) = self.player_field_by_widget[widget] if not field.startswith("color"): self.report(f"field {field} is not colorizable") return else: self.report("No appropriate widget found") return SlTrace.lg(f"field:{field} player: {player}") _, color = askcolor() if color is None: SlTrace.report(f"No color selected") return ctl_var = player.ctls_vars[field] ctl_var.set(color) field_ctl = player.ctls[field] if field == "color": player_cfg = {"fg" : color} elif field == "color_bg": player_cfg = {"bg" : color} else: self.report(f"unhandled field: {field}") return field_ctl.config(player_cfg)
def cmd_images(self, keysym): """ Create image markers replacing previous marker, if one j - choose from current group k - rotate through animals l - rotate through family [ (bracketleft) - rotate through princesses ] (bracketright)- rotate other :keysym: image type """ char2group = { 'k': "animals", 'l': "family", 'bracketleft': "princesses", 'bracketright': "other_stuff", } if keysym in char2group: group = char2group[keysym] else: SlTrace.report(f"image command {keysym} is not available yet") return False return self.cmd_do_image(group=group)
def next_color(self, colr=None, changing=None): """ Get next color based on color_current, color_changing :colr: color default: use self.color_current :changing: is color changing default: use self.color_changing """ if colr is None: colr = self.color_current self.color_current = colr if changing is None: changing = self.color_changing self.color_changing = changing if self.color_current == 'w': if self.color_changing: self.color_index += 1 if self.color_index >= len(self.colors): self.color_index = 0 # wrap around new_color = self.colors[self.color_index] elif self.color_current == '2': if changing: self.color_index += 1 if self.color_index >= len(self.custom_colors): self.color_index = 0 new_color = self.custom_colors[self.color_index] else: new_color = self.color_current if type(new_color) != str: SlTrace.report(f"new_color:{new_color} not str") return SlTrace.lg( f"new_color:{new_color}" f" color_current:{self.color_current}" f" color_index:{self.color_index}" f" color_changing:{self.color_changing}", "color") return new_color
def main(): """ Main Program """ data_dir = "../data" trace = "" use_command = True # True use CommandManager, DrawCommand hello_str = None hello_file = "keyboard_draw_hello.txt" hello_file = "hello_family.txt" parser = argparse.ArgumentParser() parser.add_argument('--trace', dest='trace', default=trace) parser.add_argument('--data_dir', dest='data_dir', default=data_dir) parser.add_argument('--hs', '--hello_str', dest='hello_str', default=hello_str) parser.add_argument('--hf', '--hello_file', dest='hello_file', default=hello_file) parser.add_argument('-c', '--command', dest='use_command', action='store_true', default=use_command) args = parser.parse_args() # or die "Illegal options" SlTrace.lg("args: %s\n" % args) hello_file = args.hello_file hello_str = args.hello_str data_dir = args.data_dir trace = args.trace use_command = args.use_command app = tk.Tk() # initialize the tkinter app app.title("Keyboard Drawing") # title app.config(bg='powder blue') # background """ Using ScreenKbd app.resizable(0, 0) # disable resizeable property """ if hello_str is not None: pass else: try: with open(hello_file, 'r') as fin: hello_str = fin.read() except IOError as e: SlTrace.report(f"Problem with hello_file:{hello_file}" f"\n in {os.path.abspath(hello_file)}" f"\n error: {e}") sys.exit() kb_draw = KeyboardDraw(app, title="Keyboard Drawing", hello_drawing_str=hello_str, draw_x=100, draw_y=50, draw_width=1500, draw_height=1000, kbd_win_x=50, kbd_win_y=25, kbd_win_width=600, kbd_win_height=300) kb_draw.enable_image_update() # Enable key image update tk.mainloop()
def report(self, msg): """ Report, via popup window :msg: """ SlTrace.report(f"{self.control_prefix}: {msg}")
def __init__( self, master, image_dir=None, on_kbd=None, keys=None, key_attrs=None, btn_specs=None, im_fract_x=1.0, im_fract_y=.8, nrows=4, ncols=8, win_width=1000, win_height=600, chg_fract=.01, btn_padx=2, btn_pady=2, btn_bd=3, btn_font=('arial', 12, 'bold'), ): """ Setup Button Grid :master: master widget :image_dir: image directory default: ../images/keys :on_kbd: function to call with each key-click :keys: list of keys to display on buttons as text 'RowEnd' entries terminate rows default: use btn_specs :key_attrs: key attributes dictionary on key text key_text : image_file OR {dictionary:} "input" : char(s) to pass else text (key), "text" : button text displayed "image" : image file "column" : button column (starting with 1) "columnspan" : button column span default: just display text with no image :btn_specs: list of button specifications specification: { "type" : "ROWCOL" - use current row_col "REPEAT - repeat list for rest of buttons else - text to be added at top of button "image" : "SAMPLE" - use sample image "BLANK" - no image file else - path to button image, None - No image "column" : starting with 1 default: current "column_span" : default: 1 } default: [ {"type" : "ROWCOL", "image" : "SAMPLE"} {"type" : "REPEAT"} ] :im_fract_x: x button fraction taken by image default: 1.0 :im_fract_y: y button fraction taken by image default: .8 :nrows: Number of rows default: 4 :ncols: Number of columns default: 8 :win_x: window x start default: 20 :win_y: window y start default: 20 :win_width: grid window width default: 1000 :win_height: grid window height default: 600 """ self.ims = [] # TFD small = 2 self.small_image = Image.new("RGB", (small, small), (255, 255, 255)) small_btn_image = ImageTk.PhotoImage(self.small_image) self.blank_image = small_btn_image self.show_images = True # False disables image showing self.enable_image_update(False) # Set True to enable image size update self.btn_infos = [] # button info in order of creation self.master = master if image_dir is None: src_dir = os.path.dirname(os.path.abspath(__file__)) prj_dir = os.path.dirname(src_dir) image_dir = os.path.join(prj_dir, "images", "keys") if not os.path.exists(image_dir): image_dir = os.path.join(src_dir, "images", "keys") SlTrace.lg(f"Looking for images under src dir: {image_dir}") self.image_dir = image_dir self.on_kbd = on_kbd if keys is not None: """ Generate btn_specs from keys and key_files """ if btn_specs is not None: SlTrace.report(f"Can't have both keys and btn_specs") exit() nrow = 0 ncol = 0 max_col = ncol btn_specs = [] row_begin = True for key in keys: spec = { "type": "key", "input": key, # passed through "text": key } # displayed on button if key == 'RowEnd': nrow += 1 if ncol > max_col: max_col = ncol ncol = 0 spec["type"] = "RowEnd" elif key_attrs and key in key_attrs: if isinstance(key_attrs[key], dict): spec.update(key_attrs[key]) else: spec["image"] = key_attrs[key] ncol += 1 btn_specs.append(spec) SlTrace.lg(f"keys: {len(keys)} rows: {nrow} cols: {max_col}" f" generated specs {len(btn_specs)}") if btn_specs is None: btn_specs = ButtonGrid.btn_specs self.btn_specs = btn_specs self.im_fract_x = im_fract_x self.im_fract_y = im_fract_y self.btn_padx = btn_padx self.btn_pady = btn_pady self.btn_bd = btn_bd self.nrows = nrow self.ncols = max_col self.chg_fract = chg_fract self.btn_padx = btn_padx # Button attributes self.btn_pady = btn_pady self.btn_bd = btn_bd self.btn_font = btn_font self.win_x = 0 self.win_y = 0 self.win_width_orig = self.win_width = win_width self.win_height_orig = self.win_height = win_height # Setup for next sizing test btn_size_x, btn_size_y = self.get_btn_image_size() self.btn_image_size_x_prev = btn_size_x # Save for new size self.btn_image_size_y_prev = btn_size_y btn_size_x, btn_size_y = self.get_btn_image_size() self.btn_image_size_x_prev = btn_size_x self.btn_image_size_y_prev = btn_size_y self.master.rowconfigure(0, weight=1) self.master.columnconfigure(0, weight=1) #Create & Configure frame keybd_frame = Frame(self.master) keybd_frame.rowconfigure(0, weight=1) keybd_frame.columnconfigure(0, weight=1) keybd_frame.grid(sticky=N + S + E + W) self.keybd_frame = keybd_frame keybd_frame.bind('<Configure>', self.win_size_event) self.master.bind('<Key>', self.on_key_press) specs = self.btn_specs.copy() row_start = 0 row_current = row_start col_start = 0 # Bumped to 1 at first col_current = col_start row_begin = True col_inc = 1 # Default column increment # Changed columnspan for spec in specs: spec_type = spec["type"] if spec_type == 'RowEnd': row_begin = True if col_current > max_col: max_col = col_current continue if row_begin: row_current += 1 keybd_frame.rowconfigure(row_current, weight=1) row_begin = False col_current = col_start # Bumped by col_inc or spec["column"] if "column" in spec: col_current = spec["column"] else: col_current += col_inc keybd_frame.columnconfigure(col_current, weight=1) key_frame = Frame(keybd_frame) key_frame.rowconfigure(0, weight=1) key_frame.columnconfigure(0, weight=1) if "columnspan" in spec and spec["columnspan"] is not None: btn_columnspan = spec["columnspan"] col_inc = btn_columnspan - 1 else: btn_columnspan = None col_inc = 1 key_frame.grid(row=row_current, column=col_current, columnspan=btn_columnspan, sticky=N + S + E + W) btn_background = "white" btn_foreground = "black" btn_compound = BOTTOM btn_width = btn_size_x base_image = None if spec_type == "REPEAT": specs = self.btn_specs.copy() continue elif spec_type == "ROWCOL": btn_text = f"{row_current},{col_current}" else: btn_text = spec["text"] if "image" not in spec or spec["image"] is None: btn_width = 7 # Best guess text chars btn_compound = None btn_image = None spec_image_file = None else: btn_width = 7 * 12 # Best guess text pixels spec_image_file = spec["image"] if spec_image_file == "SAMPLE": spec_image_file = ButtonGrid.sample_file if not os.path.isabs(spec_image_file): spec_image_file = os.path.join(image_dir, spec_image_file) if not os.path.isabs(spec_image_file): SlTrace.lg(f"key path:{spec_image_file}", "trace_keys") spec_image_file = os.path.abspath(spec_image_file) SlTrace.lg(f"key path:{spec_image_file}", "trace_keys") if not os.path.exists(spec_image_file): SlTrace.lg(f"We Can't find image file for {btn_text}" f"\n looking in: {spec_image_file}") continue SlTrace.lg(f"spec_image_file: {spec_image_file}", "btn") base_image = Image.open(spec_image_file) scaled_image = base_image.resize( (int(btn_size_x), int(btn_size_y))) btn_image = ImageTk.PhotoImage(scaled_image) # avoid loss SlTrace.lg(f"btn: btn_text:{btn_text} btn_image: {btn_image}", "btn") inp = spec["input"] cmd = lambda x=inp: self.buttonClick(x) btn = Button(key_frame, text=btn_text, image=btn_image, compound=btn_compound, width=btn_width, bg=btn_background, fg=btn_foreground, activebackground='white', activeforeground='black', relief='raised', padx=self.btn_padx, pady=self.btn_pady, bd=self.btn_bd, font=self.btn_font, command=cmd) if btn_image is None: bti_image = btn_image else: bti_image = btn_image btn_info = ButtonInfo( btn=btn, text=btn_text, row=row_current, col=col_current, base_image=base_image, btn_image=bti_image, file_key=spec_image_file, ) self.ims.append(bti_image) # TFD btn.grid(sticky=N + S + E + W) self.btn_infos.append(btn_info) btn.rowconfigure(0, weight=1) btn.columnconfigure(0, weight=1)
def load_file(self, file_name): """ load .GPX file (actually a XML file) :file_name: file name :returns: self if successful, else None """ if file_name is None: file_name = filedialog.askopenfilename( initialdir= "../data/trail_system_files", title = "Open trail File", filetypes= (("trail files", "*.gpx"), ("all files", "*.*")) ) if file_name is not None: SlTrace.report(f"No file selected") return None if not os.path.isabs(file_name): file_name = os.path.join("..", "data", "trail_system_files", file_name) if not os.path.isabs(file_name): file_name = os.path.abspath(file_name) if re.match(r'.*\.[^.]+$', file_name) is None: file_name += ".gpx" # Add default extension if not os.path.exists(file_name): SlTrace.report(f"File {file_name} not found") return None self.file_name = file_name SlTrace.lg(f"Parsing file: {file_name}", "gpx_trace") """ TBD - build name space from root attributes """ SlTrace.lg(f"bns: base namespace name:{self.bns}", "gpx_trace") self.track_segments = [] # Initialize / re-initialize tree = ET.parse(file_name) root = tree.getroot() SlTrace.lg(f"root:{root} root.tag:{root.tag}", "gpx_trace") SlTrace.lg(f"root.attrib: {root.attrib}", "gpx_trace") ns = self.ns bns = self.bns # Shorter name space, # since namespace={} doesn't appear to work trks = root.findall(f"{bns}trk") for trk in trks: SlTrace.lg(f"trk: {trk}", "gpx_trace") trksegs = trk.findall(f"{bns}trkseg", ns) # DOESN'T WORK for trkseg in trksegs: SlTrace.lg(f" trkseg: {trkseg}", "gpx_trace") tseg = GPXTrackSegment() self.add_segments(tseg) trkpts = trkseg.findall(f"{bns}trkpt") if SlTrace.trace("gpx_trace"): npts = len(trkpts) SlTrace.lg(f"{npts} points", "gpx_trace") if npts > 0: trkpt = trkpts[0] SlTrace.lg(f" lat: {trkpt.attrib['lat']}" f" lon: {trkpt.attrib['lon']}", "gpx_trace") points = [] for trkpt in trkpts: SlTrace.lg(f" lat: {trkpt.attrib['lat']}" f" lon: {trkpt.attrib['lon']}", "gpx_trace_pts") pt = GPXPoint(lat=float(trkpt.attrib['lat']), long=float(trkpt.attrib['lon'])) points.append(pt) tseg.add_points(points) return self