def __init__(self, way): self.way = way self.reset_location_variables() self.direction = DIRECTION.NONE self._speed_limit = None self._one_way = way.tags.get("oneway") self.name = way.tags.get('name') self.ref = way.tags.get('ref') self.highway_type = way.tags.get("highway") self.highway_rank = _HIGHWAY_RANK.get(self.highway_type) try: self.lanes = int(way.tags.get('lanes')) except Exception: self.lanes = 2 # Create a numpy array with nodes data to support calculations. self._nodes_np = np.radians(np.array([[nd.lat, nd.lon] for nd in way.nodes], dtype=float)) # Get the vectors representation of the segments betwheen consecutive nodes. (N-1, 2) v = vectors(self._nodes_np) * R # Calculate the vector magnitudes (or distance) between nodes. (N-1) self._way_distances = np.linalg.norm(v, axis=1) # Calculate the bearing (from true north clockwise) for every section of the way (vectors between nodes). (N-1) self._way_bearings = np.arctan2(v[:, 0], v[:, 1]) # Define bounding box to ease the process of locating a node in a way. # [[min_lat, min_lon], [max_lat, max_lon]] self.bbox = np.row_stack((np.amin(self._nodes_np, 0) - _WAY_BBOX_PADING, np.amax(self._nodes_np, 0) + _WAY_BBOX_PADING)) # Get the edge nodes ids. self.edge_nodes_ids = [way.nodes[0].id, way.nodes[-1].id]
def node_calculations(points): """Provides node calculations based on an array of (lat, lon) points in radians. points is a (N x 1) array where N >= 3 """ if len(points) < 3: raise(IndexError) # Get the vector representation of node points in cartesian plane. # (N-1, 2) array. Not including (0., 0.) v = vectors(points) * R # Calculate the vector magnitudes (or distance) # (N-1, 1) array. No distance for v[-1] d = np.linalg.norm(v, axis=1) # Calculate the bearing (from true north clockwise) for every node. # (N-1, 1) array. No bearing for v[-1] b = np.arctan2(v[:, 0], v[:, 1]) # Add origin to vector space. (i.e first node in list) v = np.concatenate(([[0., 0.]], v)) # Provide distance to previous node and distance to next node dp = np.concatenate(([0.], d)) dn = np.concatenate((d, [0.])) # Provide cumulative distance on route dr = np.cumsum(dp, axis=0) # Bearing of last node should keep bearing from previous. b = np.concatenate((b, [b[-1]])) return v, dp, dn, dr, b
def test_way_relation_init(self): wayRelation = WayRelation(mockOSMWay_01_01_LongCurvy) nodes_np_expected = np.radians( np.array([[nd.lat, nd.lon] for nd in wayRelation.way.nodes], dtype=float)) v = vectors(wayRelation._nodes_np) way_distances_expected = np.linalg.norm(v * R, axis=1) way_bearings_expected = np.arctan2(v[:, 0], v[:, 1]) bbox_expected = np.array([[0.91321784, 0.2346417], [0.91344672, 0.23475751]]) self.assertEqual(wayRelation.way.id, 179532213) self.assertIsNone(wayRelation.parent_wr_id) self.assertEqual(wayRelation.direction, DIRECTION.NONE) self.assertEqual(wayRelation._speed_limit, None) self.assertEqual(wayRelation._one_way, 'yes') self.assertEqual(wayRelation.name, None) self.assertEqual(wayRelation.ref, 'B 96') self.assertEqual(wayRelation.highway_type, 'trunk') self.assertEqual(wayRelation.highway_rank, 10) self.assertEqual(wayRelation.lanes, 2) assert_array_almost_equal(wayRelation._nodes_np, nodes_np_expected) assert_array_almost_equal(wayRelation._way_distances, way_distances_expected) assert_array_almost_equal(wayRelation._way_bearings, way_bearings_expected) assert_array_almost_equal(wayRelation.bbox, bbox_expected) self.assertEqual( wayRelation.edge_nodes_ids, [wayRelation.way.nodes[0].id, wayRelation.way.nodes[-1].id])
def __init__(self, way_coords): self.degrees = np.array(way_coords) self.radians = np.radians(self.degrees) # ***************** # Expected code implementation nodes_data self.v = vectors(self.radians) * R self.d = np.linalg.norm(self.v, axis=1) self.b = np.arctan2(self.v[:, 0], self.v[:, 1]) self.v = np.concatenate(([[0., 0.]], self.v)) self.dp = np.concatenate(([0.], self.d)) self.dn = np.concatenate((self.d, [0.])) self.dr = np.cumsum(self.dp, axis=0) self.b = np.concatenate((self.b, [self.b[-1]])) # Expected code implementation spline_curvature_calculations vect = self.v dist_prev = self.dp too_far_idxs = np.nonzero(self.dp >= _MIN_NODE_DISTANCE)[0] for idx in too_far_idxs[::-1]: dp = dist_prev[ idx] # distance of vector that needs to be replaced by higher resolution vectors. n = int(np.ceil( dp / _ADDED_NODES_DIST)) # number of vectors that need to be added. new_v = vect[idx, :] / n # new relative vector to insert. vect = np.delete( vect, idx, axis=0 ) # remove the relative vector to be replaced by the insertion of new vectors. vect = np.insert(vect, [idx] * n, [new_v] * n, axis=0) # insert n new relative vectors ds = np.cumsum(dist_prev, axis=0) vs = np.cumsum(vect, axis=0) tck, u = splprep([vs[:, 0], vs[:, 1]]) # pylint: disable=W0632 n = max(int(ds[-1] / _SPLINE_EVAL_STEP), len(u)) unew = np.arange(0, n + 1) / n d1 = splev(unew, tck, der=1) d2 = splev(unew, tck, der=2) num = d1[0] * d2[1] - d1[1] * d2[0] den = (d1[0]**2 + d1[1]**2)**(1.5) self.curv = num / den self.curv_ds = unew * ds[-1]
def test_vectors(self): points = mockNodesData01.radians expected = np.array([[-1.34011951e-05, 1.00776468e-05], [-5.83610920e-06, 4.41046897e-06], [-7.83348567e-06, 5.94114032e-06], [-7.08560788e-06, 5.30408795e-06], [-6.57632550e-06, 4.05791838e-06], [-1.16077872e-06, 6.91151252e-07], [-1.53178098e-05, 9.62215139e-06], [-5.76314175e-06, 3.55176643e-06], [-1.61124141e-05, 9.86127759e-06], [-1.48006628e-05, 8.58192512e-06], [-1.72237209e-06, 1.60570482e-06], [-8.68985228e-06, 9.22062311e-06], [-1.42922812e-06, 1.51494711e-06], [-3.39761486e-06, 2.57087743e-06], [-2.75467373e-06, 1.28631255e-06], [-1.57501989e-05, 5.72309451e-06], [-2.52143954e-06, 1.34565295e-06], [-1.65278643e-06, 1.28630942e-06], [-2.22196114e-05, 1.64360838e-05], [-5.88675934e-06, 4.08234746e-06], [-1.83673390e-06, 1.46782408e-06], [-1.55004206e-06, 1.51843800e-06], [-1.20451533e-06, 2.06298011e-06], [-1.91801338e-06, 4.64083285e-06], [-2.38653483e-06, 5.60076524e-06], [-1.65269781e-06, 5.78402290e-06], [-3.66908309e-07, 2.75412965e-06], [0.00000000e+00, 1.92858882e-06], [9.09242615e-08, 2.66162711e-06], [3.14490354e-07, 1.53065382e-06], [8.66452477e-08, 4.83456208e-07], [2.41750593e-07, 1.10828411e-06], [7.43745228e-06, 1.27618831e-05], [5.59968054e-06, 9.63947367e-06], [2.01951467e-06, 2.75413219e-06], [4.59952643e-07, 6.42281301e-07], [1.74353749e-06, 1.74533121e-06], [2.57144338e-06, 2.11185266e-06], [1.46893187e-05, 1.11999169e-05], [3.84659229e-05, 2.85527952e-05], [2.71627936e-05, 1.98727946e-05], [8.44632540e-06, 6.15058628e-06], [2.29420323e-06, 1.92859222e-06], [2.58083439e-06, 3.16952222e-06], [3.76373643e-06, 5.14174911e-06], [5.32416098e-06, 6.51707770e-06], [8.62890928e-06, 1.11998258e-05], [1.25762497e-05, 1.65231340e-05], [8.90452991e-06, 1.10148240e-05], [4.86505726e-06, 4.59023120e-06], [3.85545276e-06, 3.39642031e-06], [3.48753893e-06, 3.30566145e-06], [2.99557303e-06, 2.61276368e-06], [2.15496788e-06, 1.87797727e-06], [4.10564937e-06, 3.58142649e-06], [1.53680853e-06, 1.33866906e-06], [4.99540175e-06, 4.35635790e-06], [1.37744970e-06, 1.19380643e-06], [1.74319821e-06, 1.28456429e-06], [9.99931238e-07, 1.14493663e-06], [6.42735560e-07, 1.19380547e-06], [3.66818436e-07, 1.46782199e-06], [5.45413874e-08, 1.83783170e-06], [-1.35818548e-07, 1.14842666e-06], [-5.50758101e-07, 3.02989178e-06], [-4.58785270e-07, 2.66162724e-06], [-2.51315555e-07, 1.19031459e-06], [-3.91409773e-07, 1.65457223e-06], [-2.14525206e-06, 5.67755902e-06], [-4.24558096e-07, 1.39102753e-06], [-1.46936730e-06, 5.32325561e-06], [-1.37632061e-06, 4.59021715e-06], [-8.26642899e-07, 4.68097349e-06], [-6.42702724e-07, 4.95673534e-06], [-3.66796960e-07, 7.25009780e-06], [-1.82861669e-07, 8.99542699e-06], [4.09564134e-07, 6.11214315e-06], [7.80629912e-08, 1.45734993e-06], [4.81205526e-07, 7.56076647e-06], [2.01036346e-07, 2.42775302e-06]]) v = vectors(points) assert_array_almost_equal(v, expected)