def example3(): Stochastics.seed(1) # Reading network from text data file network = NetworkReader.readFromFile( 'tracklib/data/network/network_ecrin_extrait.csv', 'TEST2') # Cartographic Conversion network.toGeoCoords(2154) # Get distance between pairs of nodes tracks = TrackCollection() for i in range(10): node1 = network.getRandomNode() node2 = network.getRandomNode() track = network.shortest_path(node1, node2) if not track is None: tracks.addTrack(track) print(node1, node2, track.size(), track.length()) # Export KmlWriter.writeToKml(network, path='network.kml', c1=[1, 1, 1, 1]) # white network KmlWriter.writeToKml(tracks, path='tracks.kml', c1=[1, 0, 0, 1]) # red paths
def getAllEdgeGeoms(self) -> TrackCollection: """Return a TrackCollection of all edges :return: All edges of :class:`Network` """ tracks = TrackCollection() for id in self.__idx_edges: tracks.addTrack(self.EDGES[id].geom) return tracks
def select(self, tracks): """TODO""" if self.type == TYPE_SELECT: output = TrackCollection() for track in tracks: if self.contains(track): output.addTrack(track) return output if self.type == TYPE_CUT_AND_SELECT: return tracks
def writeToGpx(tracks, path, af=False): """ Transforms track into Gpx string # path: file to write gpx (gpx returned in standard output if empty) af: AF exported in gpx file """ f = open(path, "w") # Time output management fmt_save = GPSTime.getPrintFormat() GPSTime.setPrintFormat("4Y-2M-2DT2h:2m:2s") if isinstance(tracks, Track): collection = TrackCollection() collection.addTrack(tracks) tracks = collection f.write('<?xml version="1.0" encoding="UTF-8"?>\n') f.write("<gpx>\n") f.write( "<author>File generated by Tracklib: https://github.com/umrlastig/tracklib</author>\n" ) for i in range(len(tracks)): track = tracks.getTrack(i) f.write(" <trk>\n") f.write(" <trkseg>\n") for i in range(len(track)): x = "{:3.8f}".format(track[i].position.getX()) y = "{:3.8f}".format(track[i].position.getY()) z = "{:3.8f}".format(track[i].position.getZ()) f.write(' <trkpt lat="' + y + '" lon="' + x + '">\n') f.write(" <ele>" + z + "</ele>\n") f.write(" <time>" + str(track[i].timestamp) + track[i].timestamp.printZone() + "</time>\n") if af: f.write(" <extensions>\n") for af_name in track.getListAnalyticalFeatures(): f.write(" <" + af_name + ">") f.write(str(track.getObsAnalyticalFeature(af_name, i))) f.write("</" + af_name + ">\n") f.write(" </extensions>\n") f.write(" </trkpt>\n") f.write(" </trkseg>\n") f.write(" </trk>\n") f.write("</gpx>\n") f.close() GPSTime.setPrintFormat(fmt_save)
def test_create_index(self): GPSTime.setReadFormat("4Y-2M-2D 2h:2m:2s") track = Track() p1 = Obs(ENUCoords(550, 320), GPSTime.readTimestamp('2020-01-01 10:00:00')) track.addObs(p1) p2 = Obs(ENUCoords(610, 325), GPSTime.readTimestamp('2020-01-01 10:08:00')) track.addObs(p2) p3 = Obs(ENUCoords(610, 330), GPSTime.readTimestamp('2020-01-01 10:17:00')) track.addObs(p3) p4 = Obs(ENUCoords(650, 330), GPSTime.readTimestamp('2020-01-01 10:21:00')) track.addObs(p4) p5 = Obs(ENUCoords(675, 340), GPSTime.readTimestamp('2020-01-01 10:25:00')) track.addObs(p5) #track.plot() #track.plotAsMarkers() TRACES = [] TRACES.append(track) collection = TrackCollection(TRACES) res = (25, 4) index = SpatialIndex(collection, res, 0.05, True) index.plot() # ===================================================================== self.assertEqual(index.request(0, 0), [0]) self.assertEqual(index.request(1, 0), [0]) self.assertEqual(index.request(0, 1), []) self.assertEqual(index.request(1, 1), [0]) self.assertEqual(index.request(2, 0), []) self.assertEqual(index.request(2, 1), [0])
def centralTrack(tracks: Union[TrackCollection, Iterable[Track]], mode: Literal["NN", "DTW", "FDTW"] = "NN", verbose: bool = True) -> Track: """Computes central track of a track collection :param tracks: TrackCollection or list of tracks :param mode: "NN", "DTW" or "FDTW" for track pair matching (see the documentation of :func:`differenceProfile` function for more infos on modes) :return: The central track """ tracks = tracks.copy() if isinstance(tracks, list): tracks = TrackCollection(tracks) base = tracks.toENUCoordsIfNeeded() central = tracks[0].copy() for i in range(1, len(tracks)): diff = differenceProfile(tracks[0], tracks[i], mode=mode, verbose=verbose) for j in range(len(central)): dx = tracks[i][diff["pair", j]].position.getX() dy = tracks[i][diff["pair", j]].position.getY() dz = tracks[i][diff["pair", j]].position.getZ() central[j].position.translate(dx, dy, dz) for j in range(len(central)): central[j].position.scale(1.0 / len(tracks)) if not base is None: central.toGeoCoords(base) return central
def mapOnNetwork( tracks, network, gps_noise=50, transition_cost=10, search_radius=50, debug=False ): """TODO""" if isinstance(tracks, Track): tracks = TrackCollection([tracks]) for track in tracks: __mapOnNetwork(track, network, gps_noise, transition_cost, search_radius, debug)
def readFromGpx(path, srid="GEO"): """ Reads (multiple) tracks in .gpx file """ tracks = TrackCollection() format_old = GPSTime.getReadFormat() GPSTime.setReadFormat("4Y-2M-2D 2h:2m:2s") doc = minidom.parse(path) trks = doc.getElementsByTagName("trk") for trk in trks: trace = t.Track() trkpts = trk.getElementsByTagName("trkpt") for trkpt in trkpts: lon = float(trkpt.attributes["lon"].value) lat = float(trkpt.attributes["lat"].value) hgt = utils.NAN eles = trkpt.getElementsByTagName("ele") if eles.length > 0: hgt = float(eles[0].firstChild.data) time = "" times = trkpt.getElementsByTagName("time") if times.length > 0: time = GPSTime(times[0].firstChild.data) else: time = GPSTime() point = Obs(utils.makeCoords(lon, lat, hgt, srid), time) trace.addObs(point) tracks.addTrack(trace) # pourquoi ? # --> pour remettre le format comme il etait avant la lectre :) GPSTime.setReadFormat(format_old) collection = TrackCollection(tracks) return collection
def split(track, source) -> TrackCollection: """Splits track according to : - af name (considered as a marker) if `source` is a string - list of index if `source` is a list :return: No track if no segmentation, otherwise a TrackCollection object """ NEW_TRACES = TrackCollection() # -------------------------------------------- # Split from analytical feature name # -------------------------------------------- if isinstance(source, str): count = 0 # Initialisation du compteur des étapes begin = 0 # indice du premier point de l'étape for i in range(track.size()): if track.getObsAnalyticalFeature(source, i) == 1: # Nouvelle trajectoire # L'identifiant de la trace subdivisée est obtenue par concaténation # de l'identifiant de la trace initiale et du compteur new_id = str(track.uid) + "." + str(count) # La liste de points correspondant à l'intervalle de subdivision est créée new_traj = track.extract(begin, i) new_traj.setUid(new_id) NEW_TRACES.addTrack(new_traj) count += 1 begin = i + 1 # Si tous les points sont dans la même classe, la liste d'étapes reste vide # sinon, on clôt la derniere étape et on l'ajoute à la liste if begin != 0: new_id = str(track.uid) + "." + str(count) new_traj = track.extract(begin, track.size() - 1) new_traj.setUid(new_id) NEW_TRACES.addTrack(new_traj) # -------------------------------------------- # Split from list of indices # -------------------------------------------- if isinstance(source, list): for i in range(len(source) - 1): NEW_TRACES.addTrack(track.extract(source[i], source[i + 1])) return NEW_TRACES
def noise(self, track, N=1, mode='linear', force=False): """TODO""" if N == 1: return noise(track, self.amplitudes, self.kernels, self.distribution, mode=mode, force=force) else: collection = TrackCollection() for i in range(N): collection.addTrack( noise(track, self.amplitudes, self.kernels, self.distribution, mode=mode, force=force)) return collection
def splitAR(track, pt1, pt2=None, radius=10, nb_min_pts=10, verbose=True): if pt2 is None: pt2 = pt1 tracks = TrackCollection() subtrack = Track() k = -1 while k < len(track) - 1: k = k + 1 if (min(track[k].position.distance2DTo(pt1), track[k].position.distance2DTo(pt2)) < radius): if len(subtrack) > nb_min_pts: tracks.addTrack(subtrack) if verbose: print( "Add sub-track: ", subtrack[0].timestamp, subtrack[-1].timestamp, "[" + str(len(tracks)) + "]", ) subtrack = Track() subtrack.addObs(track[k].copy()) if len(subtrack) > nb_min_pts: tracks.addTrack(subtrack) if verbose: print( "Add sub-track: ", subtrack[0].timestamp, subtrack[-1].timestamp, "[" + str(len(tracks)) + "]", ) return tracks
def splitReturnTripFast(track, side_effect=0.1, sampling=1): """Split track when there is a return trip to keep only the first part. Second version with Fast Fourier Transform""" track = track.copy() track.toENUCoords(track.getFirstObs().position) track_test = track.copy() track_test.resample((track_test.length() / track_test.size()) / sampling, ALGO_LINEAR, MODE_SPATIAL) H = np.fft.fft(track_test.getY()) G = np.fft.fft(track_test.getY()[::-1]) temp = np.flip(np.abs(np.fft.ifft(H * np.conj(G)))) id = np.argmax(temp[int(side_effect * len(temp)):int((1 - side_effect) * len(temp))]) pt = track_test[id].position dmin = 1e300 argmin = 0 for i in range(track.size()): d = track[i].position.distance2DTo(pt) if d < dmin: dmin = d argmin = i first_part = track.extract(0, argmin - 1) second_part = track.extract(argmin, track.size() - 1) TRACKS = TrackCollection() TRACKS.addTrack(first_part) TRACKS.addTrack(second_part) return TRACKS
def splitReturnTripExhaustive(track): """Split track when there is a return trip to keep only the first part""" min_val = 1e300 argmin = 0 AVG = Operator.Operator.AVERAGER for return_point in progressbar.progressbar(range(1, track.size() - 1)): T1 = track.extract(0, return_point) T2 = track.extract(return_point, track.size() - 1) avg = (T1 - T2).operate(AVG, "diff") + (T2 - T1).operate(AVG, "diff") if avg < min_val: min_val = avg argmin = return_point first_part = track.extract(0, argmin - 1) second_part = track.extract(argmin, track.size() - 1) TRACKS = TrackCollection() TRACKS.addTrack(first_part) TRACKS.addTrack(second_part) return TRACKS
def test_create_index_collection2(self): GPSTime.setReadFormat("4Y-2M-2D 2h:2m:2s") track = Track() p1 = Obs(ENUCoords(0, 0), GPSTime.readTimestamp('2020-01-01 10:00:00')) track.addObs(p1) p2 = Obs(ENUCoords(3.1, 3), GPSTime.readTimestamp('2020-01-01 10:08:00')) track.addObs(p2) p3 = Obs(ENUCoords(3.1, 4.5), GPSTime.readTimestamp('2020-01-01 10:17:00')) track.addObs(p3) p4 = Obs(ENUCoords(4.5, 4.5), GPSTime.readTimestamp('2020-01-01 10:21:00')) track.addObs(p4) p5 = Obs(ENUCoords(6, 5.5), GPSTime.readTimestamp('2020-01-01 10:21:00')) track.addObs(p5) p6 = Obs(ENUCoords(7, 4.5), GPSTime.readTimestamp('2020-01-01 10:21:00')) track.addObs(p6) p7 = Obs(ENUCoords(11, 5.5), GPSTime.readTimestamp('2020-01-01 10:21:00')) track.addObs(p7) p8 = Obs(ENUCoords(13, 10), GPSTime.readTimestamp('2020-01-01 10:25:00')) track.addObs(p8) #track.plot() #track.plotAsMarkers() TRACES = [] TRACES.append(track) collection = TrackCollection(TRACES) index = SpatialIndex(collection, (2, 2)) index.plot() # ===================================================================== # ===================================================================== self.assertEqual(index.request(0, 0), [0]) self.assertEqual(index.request(1, 0), [0]) self.assertEqual(index.request(0, 1), []) self.assertEqual(index.request(1, 1), [0]) self.assertEqual(index.request(2, 0), []) self.assertEqual(index.request(2, 1), []) self.assertEqual(index.request(1, 2), [0]) self.assertEqual(index.request(2, 2), [0]) self.assertEqual(index.request(3, 2), [0]) self.assertEqual(index.request(3, 3), []) self.assertEqual(index.request(4, 2), [0]) self.assertEqual(index.request(4, 3), []) self.assertEqual(index.request(4, 4), []) self.assertEqual(index.request(5, 2), [0]) self.assertEqual(index.request(5, 3), [0]) self.assertEqual(index.request(5, 4), [])
def example5(): # ------------------------------------------------------- # Trajectoire de reference IMU # ------------------------------------------------------- path = "data/imu_opk_Vincennes1909121306.txt" ref = FileReader.readFromFile(path, "IMU_STEREOPOLIS") ref = ref < 435 ref.incrementTime(0, 18) ref.translate(0, 0, 43.79) track = ref.copy() track2 = ref.copy() track2 = track2 // track track.toGeoCoords(2154) track.toECEFCoords() # Read the data file of the satellites satellites = "data/satellites_no_errors.txt" # Model 1: # -------- # The state matrix Xk = (Xr, Yr, Zr) # Define the evolution model matrix # Stationery model A = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) # Define the covariance matrix of the states Q = np.array([[1e2, 0, 0], [0, 1e2, 0], [0, 0, 1e2]]) # Define the measurement matrix def H(x, k, track): # Declare the number of satellites used NUMBER_OF_SATELLITES = 32 NUMBER_OF_STATES = 1 Hk = np.zeros((NUMBER_OF_SATELLITES, 1)) for ind in range(0, NUMBER_OF_SATELLITES): recue = 0 + (track.getObsAnalyticalFeature("Xs" + str(ind + 1), k) != 0) # Obtenir les positions des satellites rajouter à la trace Xsat = track.getObsAnalyticalFeature("Xs" + str(ind + 1), k) Ysat = track.getObsAnalyticalFeature("Ys" + str(ind + 1), k) Zsat = track.getObsAnalyticalFeature("Zs" + str(ind + 1), k) # Distance radiale Hk[ind][0] = recue * ((x[0, 0] - Xsat)**2 + (x[1, 0] - Ysat)**2 + (x[2, 0] - Zsat)**2)**0.5 return Hk # Define the covariance matrix of the observation Rk = np.eye(32, 32) # Create 32 analytical variables for cnt in range(0, 32): track.createAnalyticalFeature("Xs" + str(cnt + 1), [0] * len(track)) track.createAnalyticalFeature("Ys" + str(cnt + 1), [0] * len(track)) track.createAnalyticalFeature("Zs" + str(cnt + 1), [0] * len(track)) track.createAnalyticalFeature("pd" + str(cnt + 1), [0] * len(track)) # Put the satellites coordinates as new analytics into the track ind = -1 counter = 0 with open(satellites) as fp: line = fp.readline() while (line): if line[0:5] == "12/09": ind += 1 counter = counter + 1 fp.readline() while True: line = fp.readline() if line[0] == "-": break # Handle the headers of each slot tok = line.split() # Set the values of the satellites at each time stamp track.setObsAnalyticalFeature("Xs" + str(tok[0]), ind, float(tok[1])) track.setObsAnalyticalFeature("Ys" + str(tok[0]), ind, float(tok[2])) track.setObsAnalyticalFeature("Zs" + str(tok[0]), ind, float(tok[3])) track.setObsAnalyticalFeature("pd" + str(tok[0]), ind, float(tok[4])) line = fp.readline() start = ECEFCoords(4201797.8382, 178416.3546, 4779221.8874) X0 = np.array([[start.getX()], [start.getY()], [start.getZ()]]) P0 = 1e1 * np.eye(3, 3) UKF = Kalman(spreading=1) UKF.setTransition(A, Q) UKF.setObservation(H, Rk) UKF.setInitState(X0, P0) UKF.summary() H(X0, 0, track) obs = [] for i in range(32): obs.append("pd" + str(i + 1)) UKF.estimate(track, obs, mode=Dynamics.MODE_STATES_AS_3D_POSITIONS) track.toGeoCoords() KmlWriter.writeToKml(TrackCollection([ref, track]), "test_no_multipath.kml") # ref.plot('g-') track.plot('r.') plt.show() time_stamps = track.getTimestamps() """ # Get the error of the predictions for t in range(len(time_stamps)): for sat in range (32): pos_sat = ECEFCoords(track["Xs"+str(sat+1),t], track["Ys"+str(sat+1),t], track["Zs"+str(sat+1),t]) # Create analytic error and compute it track.createAnalyticalFeature("error_"+str(sat+1), [0]*len(track)) # An error of -999 represents an NLOS Satellite if track["pd"+str(sat+1), t] != 0: error = track["pd"+str(sat+1), t] - track[t].position.distanceTo(pos_sat) else: error = 0 track.setObsAnalyticalFeature("error_"+str(sat+1), t, error) from PIL import Image for cnt in range(32): plt.plot(track["error_"+str(cnt+1)]) plt.xlabel('Position') plt.ylabel('Error (m)') plt.title("Error of Pseudo-distance on satellite " + str(cnt+1)) plt.savefig("Result\Error_IMU_Satellite_" + str(cnt+1)) plt.clf() """ KmlWriter.writeToKml(track, "test1.kml", type="POINT") track.toProjCoords(2154) # ---------------------------------------------- # Calcul RMSE dans chaque direction # ---------------------------------------------- track.createAnalyticalFeature("x2", track2.getX()) track.createAnalyticalFeature("y2", track2.getY()) track.createAnalyticalFeature("z2", track2.getZ()) std_x = track["RMSE(x-x2)"][0] std_y = track["RMSE(y-y2)"][0] std_z = track["RMSE(z-z2)"][0] print("X std = " + '{:5.3f}'.format(std_x) + " m") print("Y std = " + '{:5.3f}'.format(std_y) + " m") print("Z std = " + '{:5.3f}'.format(std_z) + " m")
class SpatialIndex: """Definition of a spatial index""" def __init__(self, collection, resolution=None, margin=0.05, verbose=True): """Constructor of :class:`SaptialIndex` class TODO: update documentation Parameters ---------- features : bbox() + iterable TrackCollection : on construit une grille dont l’emprise est calculée sur la fonction getBBox de TrackCollection et dans un deuxième temps on appelle addSegment([c1,c2], [i,j]) pour chaque segment [c1,c2] (localisé entre les points GPS i et i+1) de chaque trace j, de la collection. Network : on construit une grille (de taille 100 x 100) par défaut, dont l’emprise est calculée sur celle du réseau, et on appelle addSegment ([c1,c2], [i,j]) pour chaque segment [c1,c2] (localisé entre les points GPS i et i+1) de chaque tronçon j, du réseau. resolution : tuple (xsize, ysize) DESCRIPTION. The default is (100, 100). Returns ------- None. """ # Bbox only or collection if isinstance(collection, Bbox): bb = collection else: bb = collection.bbox() bb = bb.copy() bb.addMargin(margin) (self.xmin, self.xmax, self.ymin, self.ymax) = bb.asTuple() ax, ay = bb.getDimensions() if resolution is None: am = max(ax, ay) r = am / 100 resolution = (int(ax / r), int(ay / r)) else: r = resolution resolution = (int(ax / r[0]), int(ay / r[1])) self.collection = collection # Keeps track of registered features self.inventaire = set() # Nombre de dalles par cote self.csize = resolution[0] self.lsize = resolution[1] # print ('nb cellule', self.xsize * self.ysize) # Tableau de collections de features appartenant a chaque dalle. # Un feature peut appartenir a plusieurs dalles. self.grid = [] for i in range(self.csize): self.grid.append([]) for j in range(self.lsize): self.grid[i].append([]) self.dX = ax / self.csize self.dY = ay / self.lsize # Calcul de la grille if isinstance(collection, tuple): self.collection = TrackCollection() return boucle = range(collection.size()) if verbose: print( "Building [" + str(self.csize) + " x " + str(self.lsize) + "] spatial index..." ) boucle = progressbar.progressbar(boucle) for num in boucle: feature = collection[num] # On récupere la trace if isinstance(feature, Track): self.addFeature(feature, num) # On récupère l'arc du reseau qui est une trace elif isinstance(feature, Edge): self.addFeature(feature.geom, num) def __str__(self): """TODO""" c = [(self.xmin + self.xmax) / 2.0, (self.ymin + self.ymax) / 2.0] output = "[" + str(self.csize) + " x " + str(self.lsize) + "] " output += "spatial index centered on [" + str(c[0]) + "; " + str(c[1]) + "]" return output def addFeature(self, track, num): """TODO""" coord1 = None for i in range(track.size()): obs = track.getObs(i) coord2 = obs.position if coord1 != None: p1 = self.__getCell(coord1) p2 = self.__getCell(coord2) if p1 is None or p2 is None: continue self.__addSegment(p1, p2, num) coord1 = coord2 def __addSegment(self, coord1, coord2, data): """TODO data de type: int, liste, tuple, dictionnaire ajoute les données data dans toutes les cellules de la grille traversée par le segment [coord1, coord2] avec coord1 : indices de la grille """ CELLS = self.__cellsCrossSegment(coord1, coord2) if CELLS is None: return # out of grid # print (CELLS, coord1, coord2) for cell in CELLS: i = cell[0] j = cell[1] if i > self.csize: print("error, depassement en x") exit() if j > self.lsize: print("error, depassement en y") exit() if data not in self.grid[i][j]: if (i, j, data) not in self.inventaire: self.grid[i][j].append(data) self.inventaire.add((i, j, data)) def __addPoint(self, coord, data): """TODO""" pass # ------------------------------------------------------------ # Normalized coordinates of coord: (x,) -> (i,j) with: # i = (x-xmin)/(xmax-xmin)*nb_cols # j = (y-ymin)/(ymax-ymin)*nb_rows # Returns None if out of grid # ------------------------------------------------------------ def __getCell(self, coord): """TODO""" if (coord.getX() < self.xmin) or (coord.getX() > self.xmax): overflow = "{:5.5f}".format( max(self.xmin - coord.getX(), coord.getX() - self.xmax) ) print("Warning: x overflow " + str(coord) + " OVERFLOW = " + str(overflow)) return None if (coord.getY() < self.ymin) or (coord.getY() > self.ymax): overflow = "{:5.5f}".format( max(self.ymin - coord.getY(), coord.getY() - self.ymax) ) print("Warning: y overflow " + str(coord) + " OVERFLOW = " + str(overflow)) return None idx = (float(coord.getX()) - self.xmin) / self.dX idy = (float(coord.getY()) - self.ymin) / self.dY return (idx, idy) # ------------------------------------------------------------ # Plot spatial index and collection structure together in the # same reference frame (geographic reference frame) # - base: plot support network or track collection if True # ------------------------------------------------------------ def plot(self, base=True): """TODO""" fig = plt.figure() ax = fig.add_subplot( 111, xlim=(self.xmin, self.xmax), ylim=(self.ymin, self.ymax) ) for i in range(1, self.csize): xi = i * self.dX + self.xmin ax.plot([xi, xi], [self.ymin, self.ymax], "-", color="lightgray") for j in range(1, self.lsize): yj = j * self.dY + self.ymin ax.plot([self.xmin, self.xmax], [yj, yj], "-", color="lightgray") if base: self.collection.plot(append=ax) for i in range(self.csize): xi1 = i * self.dX + self.xmin xi2 = xi1 + self.dX for j in range(self.lsize): yj1 = j * self.dY + self.ymin yj2 = yj1 + self.dY if len(self.grid[i][j]) > 0: polygon = plt.Polygon( [[xi1, yj1], [xi2, yj1], [xi2, yj2], [xi1, yj2], [xi1, yj1]] ) ax.add_patch(polygon) polygon.set_facecolor("lightcyan") # ------------------------------------------------------------ # Plot a specific cell (i,j) # ------------------------------------------------------------ def highlight(self, i, j, sym="r-", size=0.5): """TODO""" x0 = self.xmin + i * self.dX x1 = x0 + self.dX y0 = self.ymin + j * self.dY y1 = y0 + self.dY X = [x0, x1, x1, x0, x0] Y = [y0, y0, y1, y1, y0] plt.plot(X, Y, sym, linewidth=size) # ------------------------------------------------------------ # Request function to get data registered in spatial index # Inputs: # - request(i,j) returns data registered in cell (i,j) # - i: row index i of spatial index grid # - j: col index j of spatial index grid # - request(coord) returns data registered in the cell # containing GeoCoords or ENUCoors object coord # - request(list) returns data registered in all cells # crossed by a segment list=[coord1, coord2]. # - request(track) returns data registered in all cells # crossed by a track. # ------------------------------------------------------------ def request(self, obj, j=None) -> list[Any]: """Request function to get data registered in spatial index TODO """ # print (type(obj)) if isinstance(obj, int): """dans la cellule (i,j)""" i = obj return self.grid[i][j] if isinstance(obj, GeoCoords) or isinstance(obj, ENUCoords): """dans la cellule contenant le point coord""" coord = obj c = self.__getCell(coord) return self.request(math.floor(c[0]), math.floor(c[1])) if isinstance(obj, list): """dans les cellules traversées par le segment défini par des coordonnées géographiques""" [coord1, coord2] = obj p1 = self.__getCell(coord1) p2 = self.__getCell(coord2) # Les cellules traversées par le segment CELLS = self.__cellsCrossSegment(p1, p2) TAB = [] for cell in CELLS: self.__addCellValuesInTAB(TAB, cell) return TAB if isinstance(obj, Track): """dans les cellules traversée par la track""" track = obj # récupération des cellules de la track TAB = [] pos1 = None for i in range(track.size()): obs = track.getObs(i) pos2 = obs.position if pos1 != None: coord1 = self.__getCell(pos1) coord2 = self.__getCell(pos2) CELLS = self.__cellsCrossSegment(coord1, coord2) for cell in CELLS: self.__addCellValuesInTAB(TAB, cell) pos1 = pos2 return TAB # ------------------------------------------------------------ # Neighborhood function to get all data registered in spatial # index and located in the vicinity of a given location. # ------------------------------------------------------------ # - neighborhood(i,j,unit) returns all data (as a plain list) # registered in a cell located at less than 'unit' distance # from (i,j) cell. # - neighborhood(coord, unit) returns data (as a plain list) # registered in a cells located at less than 'unit' distance # from cell containing coord. # - neighborhood([c1, c2], unit) returns data (as a plain # list) registered in a cells located at less than 'unit' # distance from cells containing segment [c1, c2] # - neighborhood(track, unit) returns data (as a plain list) # registered in a cells located at less than 'unit' distance # from cells containing track # ------------------------------------------------------------ # As default value, unit=0, meaning that only data located in # (i,j) cell are selected. If unit=-1, the minimal value is # selected in order to get at least 1 data in function output. # ------------------------------------------------------------ # The number of cells inspected is given by: # - (1+2*unit)^2 if unit >= 0 # - (1+2*(unit'+1))^2 if unit < 0, with unit' is the min # value of unit such that output is not empty # ------------------------------------------------------------ def neighborhood(self, obj, j=None, unit=0): """TODO retourne toutes les données (sous forme de liste simple) référencées dans la cellule (i,j). Si unit=-1, calcule la valeur minimale à donner à unit, pour que la liste ne soit pas vide*. """ # -------------------------------------------------------- # neighborhood(i,j,unit) # -------------------------------------------------------- if isinstance(obj, int): i = obj if unit != -1: TAB = set() NC = self.__neighboringcells(i, j, unit, False) for cell in NC: TAB.update(self.request(cell[0], cell[1])) return list(TAB) # ----------------------------------------- # Case: unit < 0 -> search for unit value # ----------------------------------------- u = 0 TAB = set() found = False while u <= max(self.csize, self.lsize): NC = self.__neighboringcells(i, j, u, True) for cell in NC: TAB.update(self.request(cell[0], cell[1])) if found: break found = len(TAB) > 0 u += 1 return list(TAB) # -------------------------------------------------------- # neighborhood(coord, unit) # -------------------------------------------------------- if isinstance(obj, GeoCoords) or isinstance(obj, ENUCoords): coord = obj x = coord.getX() y = coord.getY() c = self.__getCell(ENUCoords(x, y)) return self.neighborhood(math.floor(c[0]), math.floor(c[1]), unit) # -------------------------------------------------------- # neighborhood([c1, c2], unit) # -------------------------------------------------------- if isinstance(obj, list): """cellules voisines traversées par le segment coord""" [coord1, coord2] = obj p1 = self.__getCell(coord1) p2 = self.__getCell(coord2) if unit > -1: # Tableau à retourner TAB = [] # Les cellules traversées par le segment CELLS = self.__cellsCrossSegment(p1, p2) for cell in CELLS: NC = self.__neighboringcells(cell[0], cell[1], unit) # print (' ', cell, NC) for cellu in NC: self.__addCellValuesInTAB(TAB, cellu) return TAB u = 0 while u <= max(self.csize, self.lsize): TAB = [] CELLS = self.__cellsCrossSegment(p1, p2) for cell in CELLS: NC = self.__neighboringcells(cell[0], cell[1], u) # print (cell, NC) for cellu in NC: self.__addCellValuesInTAB(TAB, cellu) # print (TAB) if len(TAB) <= 0: u += 1 continue # Plus une marge de sécurité CELLS = self.__cellsCrossSegment(p1, p2) for cell in CELLS: NC = self.__neighboringcells(cell[0], cell[1], u + 1) # print (cell, NC) for cellu in NC: self.__addCellValuesInTAB(TAB, cellu) # print (TAB) return TAB # -------------------------------------------------------- # neighborhood(track, unit) # -------------------------------------------------------- if isinstance(obj, Track): """cellules voisines traversées par Track""" track = obj TAB2 = [] pos1 = None for i in range(track.size()): obs = track.getObs(i) pos2 = obs.position if pos1 != None: CELLS = self.neighborhood([pos1, pos2], None, unit) # print (CELLS, unit) for cell in CELLS: if cell not in TAB2: TAB2.append(cell) pos1 = pos2 return TAB2 # ------------------------------------------------------------ # Function to convert ground distance (metric system is # assumed to be orthonormal) into unit number # ------------------------------------------------------------ def groundDistanceToUnits(self, distance): """TODO""" return math.floor(distance / max(self.dX, self.dY) + 1) # ------------------------------------------------------------ # Returns all cells (i',j') in a vicinity unit of (i,j) # ------------------------------------------------------------ # - incremental = True: gets all cells where distance is to # central cell is exactly u units (Manhattan L1 discretized # distance). Used for incremental search of neighbors. # - incremental = False: gets all cells where distance is less # or equal than u units (Manhattan L1 discretized distance) # ------------------------------------------------------------ def __neighboringcells(self, i, j, u=0, incremental=False): """TODO""" NC = [] imin = max(i - u, 0) imax = min(i + u + 1, self.csize) jmin = max(j - u, 0) jmax = min(j + u + 1, self.lsize) for ii in range(imin, imax): for jj in range(jmin, jmax): if incremental: if (ii != imin) and (ii != imax - 1): if (jj != jmin) and (jj != jmax - 1): continue NC.append((ii, jj)) return NC # ------------------------------------------------------------ # Add data registered in cell within TAB structure # ------------------------------------------------------------ def __addCellValuesInTAB(self, TAB, cell): """TODO""" values = self.request(cell[0], cell[1]) for d in values: if d not in TAB: TAB.append(d) # ------------------------------------------------------------ # List of cells crossing segment [coord1, coord2] (in px) # ------------------------------------------------------------ def __cellsCrossSegment(self, coord1, coord2): """TODO""" CELLS = [] segment2 = [coord1[0], coord1[1], coord2[0], coord2[1]] xmin = min(math.floor(coord1[0]), math.floor(coord2[0])) xmax = max(math.floor(coord1[0]), math.floor(coord2[0])) ymin = min(math.floor(coord1[1]), math.floor(coord2[1])) ymax = max(math.floor(coord1[1]), math.floor(coord2[1])) for i in range(xmin, xmax + 1): for j in range(ymin, ymax + 1): # complètement inclus if ( i < coord1[0] and coord1[0] < i + 1 and i < coord2[0] and coord2[0] < i + 1 and j < coord1[1] and coord1[1] < j + 1 and j < coord2[1] and coord2[1] < j + 1 ): if (i, j) not in CELLS: CELLS.append((i, j)) continue # traverse segment1 = [i, j, i + 1, j] if Geometry.isSegmentIntersects(segment1, segment2): if (i, j) not in CELLS: CELLS.append((i, j)) continue segment1 = [i, j, i, j + 1] if Geometry.isSegmentIntersects(segment1, segment2): if (i, j) not in CELLS: CELLS.append((i, j)) continue segment1 = [i, j + 1, i + 1, j + 1] if Geometry.isSegmentIntersects(segment1, segment2): if (i, j) not in CELLS: CELLS.append((i, j)) continue segment1 = [i + 1, j, i + 1, j + 1] if Geometry.isSegmentIntersects(segment1, segment2): if (i, j) not in CELLS: CELLS.append((i, j)) continue return CELLS def save(self, filename): """TODO""" outfile = open(filename, "wb") pickle.dump(self, outfile) outfile.close() def load(filename): """TODO""" infile = open(filename, "rb") index = pickle.load(infile) infile.close() return index
def setUp(self): GPSTime.GPSTime.setReadFormat("4Y-2M-2D 2h:2m:2s") self.TRACES = [] # --------------------------------------------------------------------- trace1 = Track.Track([], 1) c1 = Coords.ENUCoords(10, 10, 0) p1 = Obs.Obs(c1, GPSTime.GPSTime.readTimestamp("2018-01-01 10:00:00")) trace1.addObs(p1) c2 = Coords.ENUCoords(10, 110, 0) p2 = Obs.Obs(c2, GPSTime.GPSTime.readTimestamp("2018-01-01 10:00:12")) trace1.addObs(p2) c3 = Coords.ENUCoords(270, 110, 0) p3 = Obs.Obs(c3, GPSTime.GPSTime.readTimestamp("2018-01-01 10:00:40")) trace1.addObs(p3) c4 = Coords.ENUCoords(360, 210, 0) p4 = Obs.Obs(c4, GPSTime.GPSTime.readTimestamp("2018-01-01 10:01:50")) trace1.addObs(p4) self.TRACES.append(trace1) # --------------------------------------------------------------------- trace2 = Track.Track([], 2) c7 = Coords.ENUCoords(25, 10, 0) p7 = Obs.Obs(c7, GPSTime.GPSTime.readTimestamp("2018-01-01 10:00:15")) trace2.addObs(p7) c6 = Coords.ENUCoords(280, 90, 0) p6 = Obs.Obs(c6, GPSTime.GPSTime.readTimestamp("2018-01-01 10:00:45")) trace2.addObs(p6) c5 = Coords.ENUCoords(330, 20, 0) p5 = Obs.Obs(c5, GPSTime.GPSTime.readTimestamp("2018-01-01 10:01:55")) trace2.addObs(p5) self.TRACES.append(trace2) self.collection = TrackCollection(self.TRACES) # Construction de la grille #self.grille = Grid.Grid(Xmin, Ymin, Xmax, Ymax, PixelSize) marge = 0.05 self.grille = Grid.Grid(self.collection, (60, 60), marge) #self.grille.plot() #plt.show() self.assertEqual(self.grille.xmin, 10.0 - marge * (360 - 10)) self.assertEqual(self.grille.xmax, 360.0 + marge * (360 - 10)) self.assertEqual(self.grille.ymin, 10.0 - marge * (210 - 10)) self.assertEqual(self.grille.ymax, 210.0 + marge * (210 - 10)) self.assertEqual(self.grille.ncol, int(((360 - 10) + marge * (360 - 10)) / 60)) self.assertEqual(self.grille.nrow, int(((210 - 10) + marge * (210 - 10)) / 60)) self.assertEqual(self.grille.XPixelSize, ((360 - 10) + 2 * marge * (360 - 10)) / self.grille.ncol) self.assertEqual(self.grille.YPixelSize, ((210 - 10) + 2 * marge * (210 - 10)) / self.grille.nrow)
class TestGrille(TestCase): def setUp(self): GPSTime.GPSTime.setReadFormat("4Y-2M-2D 2h:2m:2s") self.TRACES = [] # --------------------------------------------------------------------- trace1 = Track.Track([], 1) c1 = Coords.ENUCoords(10, 10, 0) p1 = Obs.Obs(c1, GPSTime.GPSTime.readTimestamp("2018-01-01 10:00:00")) trace1.addObs(p1) c2 = Coords.ENUCoords(10, 110, 0) p2 = Obs.Obs(c2, GPSTime.GPSTime.readTimestamp("2018-01-01 10:00:12")) trace1.addObs(p2) c3 = Coords.ENUCoords(270, 110, 0) p3 = Obs.Obs(c3, GPSTime.GPSTime.readTimestamp("2018-01-01 10:00:40")) trace1.addObs(p3) c4 = Coords.ENUCoords(360, 210, 0) p4 = Obs.Obs(c4, GPSTime.GPSTime.readTimestamp("2018-01-01 10:01:50")) trace1.addObs(p4) self.TRACES.append(trace1) # --------------------------------------------------------------------- trace2 = Track.Track([], 2) c7 = Coords.ENUCoords(25, 10, 0) p7 = Obs.Obs(c7, GPSTime.GPSTime.readTimestamp("2018-01-01 10:00:15")) trace2.addObs(p7) c6 = Coords.ENUCoords(280, 90, 0) p6 = Obs.Obs(c6, GPSTime.GPSTime.readTimestamp("2018-01-01 10:00:45")) trace2.addObs(p6) c5 = Coords.ENUCoords(330, 20, 0) p5 = Obs.Obs(c5, GPSTime.GPSTime.readTimestamp("2018-01-01 10:01:55")) trace2.addObs(p5) self.TRACES.append(trace2) self.collection = TrackCollection(self.TRACES) # Construction de la grille #self.grille = Grid.Grid(Xmin, Ymin, Xmax, Ymax, PixelSize) marge = 0.05 self.grille = Grid.Grid(self.collection, (60, 60), marge) #self.grille.plot() #plt.show() self.assertEqual(self.grille.xmin, 10.0 - marge * (360 - 10)) self.assertEqual(self.grille.xmax, 360.0 + marge * (360 - 10)) self.assertEqual(self.grille.ymin, 10.0 - marge * (210 - 10)) self.assertEqual(self.grille.ymax, 210.0 + marge * (210 - 10)) self.assertEqual(self.grille.ncol, int(((360 - 10) + marge * (360 - 10)) / 60)) self.assertEqual(self.grille.nrow, int(((210 - 10) + marge * (210 - 10)) / 60)) self.assertEqual(self.grille.XPixelSize, ((360 - 10) + 2 * marge * (360 - 10)) / self.grille.ncol) self.assertEqual(self.grille.YPixelSize, ((210 - 10) + 2 * marge * (210 - 10)) / self.grille.nrow) def test_summarize_af(self): self.collection.addAnalyticalFeature(Analytics.speed) af_algos = ['speed'] #, utils.stop_point] cell_operators = [Summarising.co_avg] #, utils.sum] raster = Summarising.summarize(self.grille, af_algos, cell_operators) raster.plot(Analytics.speed, Summarising.co_avg) rasterBand = raster.getRasterBand(Analytics.speed, Summarising.co_avg) speedTrace1 = self.collection.getTrack(0).getAnalyticalFeature('speed') speedTrace2 = self.collection.getTrack(1).getAnalyticalFeature('speed') self.assertEqual(rasterBand[0][0], 0) self.assertEqual(rasterBand[1][0], speedTrace1[1]) self.assertEqual(rasterBand[2][0], (speedTrace1[0] + speedTrace2[0]) / 2) self.assertEqual(rasterBand[0][1], 0) self.assertEqual(rasterBand[1][1], 0) self.assertEqual(rasterBand[2][1], 0) self.assertEqual(rasterBand[0][2], 0) self.assertEqual(rasterBand[1][2], 0) self.assertEqual(rasterBand[2][2], 0) self.assertEqual(rasterBand[0][3], 0) self.assertEqual(rasterBand[1][3], 0) self.assertEqual(rasterBand[2][3], 0) self.assertEqual(rasterBand[0][4], 0) self.assertEqual(rasterBand[1][4], (speedTrace1[2] + speedTrace2[1]) / 2) self.assertEqual(rasterBand[2][4], 0) self.assertEqual(rasterBand[0][5], speedTrace1[3]) self.assertEqual(rasterBand[1][5], 0) self.assertEqual(rasterBand[2][5], speedTrace2[2])
def __init__(self, collection, resolution=None, margin=0.05, verbose=True): """Constructor of :class:`SaptialIndex` class TODO: update documentation Parameters ---------- features : bbox() + iterable TrackCollection : on construit une grille dont l’emprise est calculée sur la fonction getBBox de TrackCollection et dans un deuxième temps on appelle addSegment([c1,c2], [i,j]) pour chaque segment [c1,c2] (localisé entre les points GPS i et i+1) de chaque trace j, de la collection. Network : on construit une grille (de taille 100 x 100) par défaut, dont l’emprise est calculée sur celle du réseau, et on appelle addSegment ([c1,c2], [i,j]) pour chaque segment [c1,c2] (localisé entre les points GPS i et i+1) de chaque tronçon j, du réseau. resolution : tuple (xsize, ysize) DESCRIPTION. The default is (100, 100). Returns ------- None. """ # Bbox only or collection if isinstance(collection, Bbox): bb = collection else: bb = collection.bbox() bb = bb.copy() bb.addMargin(margin) (self.xmin, self.xmax, self.ymin, self.ymax) = bb.asTuple() ax, ay = bb.getDimensions() if resolution is None: am = max(ax, ay) r = am / 100 resolution = (int(ax / r), int(ay / r)) else: r = resolution resolution = (int(ax / r[0]), int(ay / r[1])) self.collection = collection # Keeps track of registered features self.inventaire = set() # Nombre de dalles par cote self.csize = resolution[0] self.lsize = resolution[1] # print ('nb cellule', self.xsize * self.ysize) # Tableau de collections de features appartenant a chaque dalle. # Un feature peut appartenir a plusieurs dalles. self.grid = [] for i in range(self.csize): self.grid.append([]) for j in range(self.lsize): self.grid[i].append([]) self.dX = ax / self.csize self.dY = ay / self.lsize # Calcul de la grille if isinstance(collection, tuple): self.collection = TrackCollection() return boucle = range(collection.size()) if verbose: print( "Building [" + str(self.csize) + " x " + str(self.lsize) + "] spatial index..." ) boucle = progressbar.progressbar(boucle) for num in boucle: feature = collection[num] # On récupere la trace if isinstance(feature, Track): self.addFeature(feature, num) # On récupère l'arc du reseau qui est une trace elif isinstance(feature, Edge): self.addFeature(feature.geom, num)
def test_create_index_collection1(self): GPSTime.setReadFormat("4Y-2M-2D 2h:2m:2s") track = Track() p1 = Obs(ENUCoords(0, 0), GPSTime.readTimestamp('2020-01-01 10:00:00')) track.addObs(p1) p2 = Obs(ENUCoords(2.5, 3), GPSTime.readTimestamp('2020-01-01 10:08:00')) track.addObs(p2) p3 = Obs(ENUCoords(2.5, 5), GPSTime.readTimestamp('2020-01-01 10:17:00')) track.addObs(p3) p4 = Obs(ENUCoords(7, 5), GPSTime.readTimestamp('2020-01-01 10:21:00')) track.addObs(p4) p5 = Obs(ENUCoords(10, 10), GPSTime.readTimestamp('2020-01-01 10:25:00')) track.addObs(p5) #track.plot() #track.plotAsMarkers() TRACES = [] TRACES.append(track) collection = TrackCollection(TRACES) index = SpatialIndex(collection, (2, 2)) index.plot() # ===================================================================== # ===================================================================== self.assertEqual(index.request(0, 0), [0]) self.assertEqual(index.request(1, 0), []) self.assertEqual(index.request(0, 1), [0]) self.assertEqual(index.request(1, 1), [0]) self.assertEqual(index.request(2, 0), []) self.assertEqual(index.request(2, 1), []) self.assertEqual(index.request(1, 2), [0]) self.assertEqual(index.request(2, 2), [0]) self.assertEqual(index.request(3, 2), [0]) self.assertEqual(index.request(3, 3), [0]) self.assertEqual(index.request(4, 3), [0]) self.assertEqual(index.request(4, 4), [0]) # # ===================================================================== self.assertEqual(index.request(ENUCoords(0, 0)), [0]) self.assertEqual(index.request(ENUCoords(2.5, 3)), [0]) self.assertEqual(index.request(ENUCoords(2.5, 5)), [0]) self.assertEqual(index.request(ENUCoords(7, 5)), [0]) self.assertEqual(index.request(ENUCoords(10, 10)), [0]) self.assertEqual(index.request(ENUCoords(0.5, 2.5)), [0]) self.assertEqual(index.request(ENUCoords(4.2, 5.8)), [0]) # # ===================================================================== self.assertEqual(index.request([ENUCoords(2.1, 0.5), ENUCoords(1.1, 1.1)]), [0]) self.assertEqual(index.request([ENUCoords(2.1, 0.5), ENUCoords(7.1, 3.5)]), []) self.assertEqual(index.request([ENUCoords(5.8, 5.8), ENUCoords(2.1, 1.1)]), [0]) # # ===================================================================== self.assertEqual(index.request(track), [0]) track2 = Track() p6 = Obs(ENUCoords(2.2, 0), GPSTime.readTimestamp('2020-01-01 10:00:00')) track2.addObs(p6) p7 = Obs(ENUCoords(2.2, 3.8), GPSTime.readTimestamp('2020-01-01 10:08:00')) track2.addObs(p7) p8 = Obs(ENUCoords(6.5, 3.8), GPSTime.readTimestamp('2020-01-01 10:08:00')) track2.addObs(p8) self.assertEqual(index.request(track2), [0]) track3 = Track() p9 = Obs(ENUCoords(6.5, 3.8), GPSTime.readTimestamp('2020-01-01 10:00:00')) track3.addObs(p9) p10 = Obs(ENUCoords(6.5, 7), GPSTime.readTimestamp('2020-01-01 10:08:00')) track3.addObs(p10) p11 = Obs(ENUCoords(10, 7), GPSTime.readTimestamp('2020-01-01 10:08:00')) track3.addObs(p11) self.assertEqual(index.request(track3), [0]) # # ===================================================================== # # ===================================================================== self.assertCountEqual(index.neighborhood(0, 4, 0), []) self.assertCountEqual(index.neighborhood(0, 4, 1), []) self.assertCountEqual(index.neighborhood(0, 4, 2), [0]) self.assertCountEqual(index.neighborhood(0, 4, 3), [0]) self.assertCountEqual(index.neighborhood(3, 0, 0), []) self.assertCountEqual(index.neighborhood(3, 0, 1), []) self.assertCountEqual(index.neighborhood(3, 0, 2), [0]) self.assertCountEqual(index.neighborhood(3, 0, 3), [0]) self.assertCountEqual(index.neighborhood(2, 2, 0), [0]) self.assertCountEqual(index.neighborhood(2, 2, 1), [0]) self.assertCountEqual(index.neighborhood(2, 2, 2), [0]) #self.assertCountEqual(index.neighborhood(2, 2, 3), [0]) # # UNIT = -1 self.assertCountEqual(index.neighborhood(2, 1, -1), [0]) self.assertCountEqual(index.neighborhood(2, 0, -1), [0]) self.assertCountEqual(index.neighborhood(0, 1, -1), [0]) self.assertCountEqual(index.neighborhood(1, 1, -1), [0]) self.assertCountEqual(index.neighborhood(0, 4, -1), [0]) self.assertCountEqual(index.neighborhood(3, 4, -1), [0]) self.assertCountEqual(index.neighborhood(4, 4, -1), [0]) self.assertCountEqual(index.neighborhood(2, 4, -1), [0]) # # ===================================================================== self.assertCountEqual(index.neighborhood(ENUCoords(0, 0.1)), [0]) self.assertCountEqual(index.neighborhood(ENUCoords(2.5, 3)), [0]) self.assertCountEqual(index.neighborhood(ENUCoords(2.5, 5)), [0]) self.assertCountEqual(index.neighborhood(ENUCoords(7, 5)), [0]) self.assertCountEqual(index.neighborhood(ENUCoords(10, 10)), [0]) self.assertCountEqual(index.neighborhood(ENUCoords(6.5, 3.8), None, 0), []) self.assertCountEqual(index.neighborhood(ENUCoords(6.5, 3.8), None, 1), [0]) self.assertCountEqual(index.neighborhood(ENUCoords(6.5, 3.8), None, 2), [0]) self.assertCountEqual(index.neighborhood(ENUCoords(6.5, 3.8), None, 3), [0]) self.assertCountEqual(index.neighborhood(ENUCoords(2.2, 3.8), None, 0), [0]) self.assertCountEqual(index.neighborhood(ENUCoords(2.2, 3.8), None, 1), [0]) self.assertCountEqual(index.neighborhood(ENUCoords(2.2, 3.8), None, 2), [0]) self.assertCountEqual(index.neighborhood(ENUCoords(2.2, 3.8), None, 3), [0]) self.assertCountEqual(index.neighborhood(ENUCoords(9.9, 7), None, 0), [0]) self.assertCountEqual(index.neighborhood(ENUCoords(9.9, 7), None, 1), [0]) self.assertCountEqual(index.neighborhood(ENUCoords(9.9, 7), None, 2), [0]) self.assertCountEqual(index.neighborhood(ENUCoords(9.9, 7), None, 3), [0]) # # UNIT = -1 self.assertCountEqual(index.neighborhood(ENUCoords(0, 0), None, -1), [0]) self.assertCountEqual(index.neighborhood(ENUCoords(2.5, 3), None, -1), [0]) self.assertCountEqual(index.neighborhood(ENUCoords(2.5, 5), None, -1), [0]) self.assertCountEqual(index.neighborhood(ENUCoords(7, 5), None, -1), [0]) self.assertCountEqual(index.neighborhood(ENUCoords(10, 10), None, -1), [0]) self.assertCountEqual(index.neighborhood(ENUCoords(6.5, 3.8), None, -1), [0]) self.assertCountEqual(index.neighborhood(ENUCoords(2.2, 3.8), None, -1), [0]) self.assertCountEqual(index.neighborhood(ENUCoords(9.9, 7), None, -1), [0]) # # ===================================================================== self.assertEqual(index.neighborhood([ENUCoords(2.1, 0.5), ENUCoords(0.1, 2.1)], None, 0), [0]) self.assertEqual(index.neighborhood([ENUCoords(2.1, 0.5), ENUCoords(0.1, 2.1)], None, 1), [0]) self.assertEqual(index.neighborhood([ENUCoords(2.1, 0.5), ENUCoords(0.1, 2.1)], None, 2), [0]) self.assertEqual(index.neighborhood([ENUCoords(2.1, 0.5), ENUCoords(0.1, 2.1)], None, -1), [0]) self.assertEqual(index.neighborhood([ENUCoords(2.1, 0.5), ENUCoords(7.1, 3.5)]), []) self.assertEqual(index.neighborhood([ENUCoords(2.1, 0.5), ENUCoords(7.1, 3.5)], None, 2), [0]) self.assertEqual(index.neighborhood([ENUCoords(2.1, 0.5), ENUCoords(7.1, 3.5)], None, -1), [0]) self.assertEqual(index.neighborhood([ENUCoords(5.8, 5.8), ENUCoords(2.1, 1.1)]), [0]) self.assertEqual(index.neighborhood([ENUCoords(5.8, 5.8), ENUCoords(2.1, 1.1)], None, 1), [0]) self.assertEqual(index.neighborhood([ENUCoords(5.8, 5.8), ENUCoords(2.1, 1.1)], None, 2), [0]) self.assertEqual(index.neighborhood([ENUCoords(5.8, 5.8), ENUCoords(2.1, 1.1)], None, -1), [0]) # # ===================================================================== self.assertEqual(index.neighborhood(track), [0]) self.assertEqual(index.neighborhood(track, None, 1), [0]) self.assertEqual(index.neighborhood(track, None, 3), [0]) self.assertEqual(index.neighborhood(track, None, -1), [0]) self.assertEqual(index.neighborhood(track2), [0]) self.assertEqual(index.neighborhood(track2, None, 0), [0]) self.assertEqual(index.neighborhood(track2, None, 1), [0]) self.assertEqual(index.neighborhood(track2, None, 3), [0]) self.assertEqual(index.neighborhood(track2, None, -1), [0]) self.assertEqual(index.neighborhood(track3), [0]) self.assertEqual(index.neighborhood(track3, None, 0), [0]) self.assertEqual(index.neighborhood(track3, None, 1), [0]) self.assertEqual(index.neighborhood(track3, None, 2), [0]) self.assertEqual(index.neighborhood(track3, None, 3), [0]) self.assertEqual(index.neighborhood(track3, None, -1), [0])
def addTrackPair(self, track1, track2): """TODO""" self.addTrackCollection(TrackCollection([track1, track2]))