Skip to content

Commit

Permalink
reverted assert, update examples, readme added
Browse files Browse the repository at this point in the history
  • Loading branch information
fuzailpalnak committed Sep 22, 2020
1 parent b04c3b1 commit 7618f65
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 79 deletions.
50 changes: 49 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,49 @@
# kaizen
# Kaizen
![Python](https://img.shields.io/badge/python-v3.6+-blue.svg)
![Contributions welcome](https://img.shields.io/badge/contributions-welcome-orange.svg)

A Library build with two propose, to *map match* road elements either with *probe trace or road elements from different
source* and help, tackle the problem of *roads and building intersecting or overlapping*, which are results of
inaccurate digitizing, snapping, or resource mismatch.

This Library is my view on tackling the aforementioned problem, caused during map making, using obstacle avoidance
and map matching

## Installation

pip install git+https://github.com/fuzailpalnak/kaizen.git#egg=kaizen

## Additional Requirements

The library uses [Rtree](https://rtree.readthedocs.io/en/latest/) which has a dependency on
[libspatialindex](https://libspatialindex.org/),
It is recommend to resolve the dependency through [conda](https://anaconda.org/conda-forge/libspatialindex)

*_LibSpatialIndex For Linux:_*

$ sudo apt-get update -y
$ sudo apt-get install -y libspatialindex-dev
*_LibSpatialIndex For Windows:_*

Experience is pretty slim, for Windows Installation, I recommend using conda, for trouble free installation.

## Examples

1. [Map Matching Road Element with Line String](https://github.com/fuzailpalnak/kaizen/blob/master/examples/MapMatchingWithLineString.ipynb)
2. [Map Matching Road Element with List of Point](https://github.com/fuzailpalnak/kaizen/blob/master/examples/MapMatchingWithPoint.ipynb)
3. [Solving Conflict Between Building and Road without additional Reference](https://github.com/fuzailpalnak/kaizen/blob/master/examples/ConflictResolver.ipynb)
4. [Solving Conflict Between Building and Road with matching the conflict with neighbouring data and finding
associated reference points](https://github.com/fuzailpalnak/kaizen/blob/master/examples/ConflictResolverWithMapMatching.ipynb)


## References

1. [Fast Map Matching](https://people.kth.se/~cyang/bib/fmm.pdf)
2. [ST-Map Matching](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/Map-Matching20for20Low-Sampling-Rate20GPS20Trajectories-cameraReady.pdf)
3. [Game Programming](http://theory.stanford.edu/~amitp/GameProgramming/)
4. [Robot Navigation](https://github.com/AtsushiSakai/PythonRobotics)




31 changes: 20 additions & 11 deletions examples/ConflictResolver.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"source": [
"## Solve Conflict using non conflicting nodes as goal nodes\n",
"\n",
"This example answers on how to correct existing road element when the road has a conflict with building footprints and no reference data is available.\n"
"This example answers on how to correct existing road element when the road is in conflict with building footprints and has no reference data available.\n"
]
},
{
Expand Down Expand Up @@ -107,7 +107,9 @@
"metadata": {},
"source": [
"### Initialize the grid for the area on which the conflict is to be resolved\n",
"the bounding box of the area can be extracted from [this](https://boundingbox.klokantech.com/) website and export it in json format"
"the bounding box of the area can be extracted from [this](https://boundingbox.klokantech.com/) website and export it in json format\n",
"\n",
"The bounding box can be of a city, or a smaller region, what ever the extent, it should occupy all the traces and obstacle to run"
]
},
{
Expand Down Expand Up @@ -200,18 +202,25 @@
}
],
"source": [
"solved_path_list = list()\n",
"\n",
"# A GENERATOR WHICH WILL KEEP ON YEILDING FOR EVERY TRACE PRESENT IN TRACES\n",
"for solved_path in navigator.path_finder_from_traces(grid, traces, search_space_threshold=30):\n",
" solved_path_data_frame = gpd.GeoDataFrame([LineString(solved_path)],\n",
" columns=['LineString'], \n",
" geometry='LineString')\n",
" f, ax = plt.subplots(1)\n",
" obstacle_data_frame.plot(ax=ax, label='Building Footprint')\n",
" trace_data_frame.plot(ax=ax,cmap=None, color=\"red\", label='Trace Line')\n",
" solved_path_list.append(LineString(solved_path))\n",
" \n",
" \n",
" solved_path_data_frame.plot(ax=ax, cmap=None, color=\"green\", label='Solved Conflict')\n",
"solved_path_data_frame = gpd.GeoDataFrame(solved_path_list,\n",
" columns=['LineString'], \n",
" geometry='LineString')\n",
"\n",
"f, ax = plt.subplots(1)\n",
"obstacle_data_frame.plot(ax=ax, label='Building Footprint')\n",
"trace_data_frame.plot(ax=ax,cmap=None, color=\"red\", label='Trace Line')\n",
"\n",
"solved_path_data_frame.plot(ax=ax, cmap=None, color=\"green\", label='Solved Conflict')\n",
"\n",
" plt.legend()\n",
" plt.show()"
"plt.legend()\n",
"plt.show()"
]
}
],
Expand Down
18 changes: 13 additions & 5 deletions examples/ConflictResolverWithMapMatching.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
"metadata": {},
"source": [
"## When for path finding intermediate goal are to found by matching the conflicting RoadElement with nearby Referenced Lines \n",
"These Referened Lines can be of any type and not limited to *Probe Lines*, *Osm Map Data*, *Noisy observation available in the area*, *Goverment Sources*, or any other Reference Data available\n",
"These Referened Lines can be of any type and not limited to *Probe Lines*, *Osm Map Data*, *Noisy observation available in the area*, *Goverment Sources*, or any other Reference Data\n",
"\n",
"This example answers on how to correct existing road element using reference data available\n",
"This example answers on how to correct existing road element using available reference data\n",
"\n",
"NOTE - For example below OSM Map Data is used as reference for solving the conflict"
]
Expand Down Expand Up @@ -79,7 +79,8 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"### Read Reference Data Frame"
"### Read Reference Data Frame\n",
"Required Param = ['u', 'v'] (*start node* and *end node* of a edge)"
]
},
{
Expand Down Expand Up @@ -146,7 +147,9 @@
"metadata": {},
"source": [
"### Initialize the grid for the area on which the conflict is to be resolved\n",
"the bounding box of the area can be extracted from [this](https://boundingbox.klokantech.com/) website and export it in json format"
"the bounding box of the area can be extracted from [this](https://boundingbox.klokantech.com/) website and export it in json format\n",
"\n",
"The bounding box can be of a city, or a smaller region, what ever the extent, it should occupy all the traces and obstacle to run"
]
},
{
Expand Down Expand Up @@ -209,7 +212,8 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"### Initialize the Matcher with Refrence Data and The navigator to find path"
"### Initialize the Matcher with Refrence Data and The navigator to find path\n",
"observation_error is used to tell how off in *meters* the trace point are expected from the road network"
]
},
{
Expand Down Expand Up @@ -247,16 +251,20 @@
"reference_poi_list = list()\n",
"\n",
"for trace_id, trace in traces.items():\n",
" \n",
" # REFRENCE POI WILL ACT AS INTERMEDIATE GOALS FOR THE NAVIGATOR TO REACH ITS FINAL GOAL\n",
" _, _, reference_poi = matcher.match_trace(trace_id, trace)\n",
" \n",
" reference_poi_list.extend(reference_poi)\n",
" \n",
" # CONVERT COORDINATES TO TRACE\n",
" intermediate_goals = [(point.x, point.y) for point in reference_poi]\n",
" \n",
" # ADD START ANF FINAL GOAL TO NEW TRACE\n",
" intermediate_goals.insert(0, (trace[0].x, trace[0].y))\n",
" intermediate_goals.insert(-1, (trace[-1].x, trace[-1].y))\n",
" \n",
" # INIATE NEW TRACE\n",
" new_trace_coordinates = single_trace(intermediate_goals)\n",
"\n",
" \n",
Expand Down
34 changes: 20 additions & 14 deletions examples/MapMatchingWithLineString.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -182,24 +182,30 @@
"source": [
"f, ax = plt.subplots(1)\n",
"\n",
"reference_poi_list = list()\n",
"connected_shape_list = list()\n",
"\n",
"# A GENERATOR WHICH WILL KEEP ON YEILDING FOR EVERY TRACE PRESENT IN TRACES\n",
"for connected_shape, connected_info, reference_poi in matcher.match_traces(traces):\n",
" reference_poi_list.extend(reference_poi)\n",
" connected_shape_list.extend(connected_shape)\n",
" \n",
" reference_poi_data_frame = gpd.GeoDataFrame(reference_poi,\n",
" columns=['Points'], \n",
" geometry='Points') \n",
" \n",
" connected_shape_data_frame = gpd.GeoDataFrame(connected_shape,\n",
" columns=['LineString'], \n",
" geometry='LineString') \n",
"reference_poi_data_frame = gpd.GeoDataFrame(reference_poi_list,\n",
" columns=['Points'], \n",
" geometry='Points') \n",
"\n",
" road_network_data_frame.plot(ax=ax, color=\"pink\", label='Road Network')\n",
" traces_data_frame.plot(ax=ax,cmap=None, color=\"cyan\", label='Trace Line')\n",
" \n",
" connected_shape_data_frame.plot(ax=ax, cmap=None, color=\"green\", label='Matched Road Element')\n",
" reference_poi_data_frame.plot(ax=ax, cmap=None, color=\"blue\", label='Points Referenced on Matched Road')\n",
"connected_shape_data_frame = gpd.GeoDataFrame(connected_shape_list,\n",
" columns=['LineString'], \n",
" geometry='LineString') \n",
"\n",
"road_network_data_frame.plot(ax=ax, color=\"pink\", label='Road Network')\n",
"traces_data_frame.plot(ax=ax,cmap=None, color=\"cyan\", label='Trace Line')\n",
"\n",
" plt.legend()\n",
" plt.show()"
"connected_shape_data_frame.plot(ax=ax, cmap=None, color=\"green\", label='Matched Road Element')\n",
"reference_poi_data_frame.plot(ax=ax, cmap=None, color=\"blue\", label='Points Referenced on Matched Road')\n",
"\n",
"plt.legend()\n",
"plt.show()"
]
}
],
Expand Down
33 changes: 19 additions & 14 deletions examples/MapMatchingWithPoint.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -186,25 +186,30 @@
],
"source": [
"f, ax = plt.subplots(1)\n",
"reference_poi_list = list()\n",
"connected_shape_list = list()\n",
"\n",
"# A GENERATOR WHICH WILL KEEP ON YEILDING FOR EVERY TRACE PRESENT IN TRACES\n",
"for connected_shape, connected_info, reference_poi in matcher.match_traces(traces):\n",
" reference_poi_list.extend(reference_poi)\n",
" connected_shape_list.extend(connected_shape)\n",
" \n",
" reference_poi_data_frame = gpd.GeoDataFrame(reference_poi,\n",
" columns=['Points'], \n",
" geometry='Points') \n",
" \n",
" connected_shape_data_frame = gpd.GeoDataFrame(connected_shape,\n",
" columns=['LineString'], \n",
" geometry='LineString') \n",
"reference_poi_data_frame = gpd.GeoDataFrame(reference_poi_list,\n",
" columns=['Points'], \n",
" geometry='Points') \n",
"\n",
" road_network_data_frame.plot(ax=ax, color=\"pink\", label='Road Network')\n",
" traces_data_frame.plot(ax=ax,cmap=None, color=\"cyan\", label='Trace Line')\n",
" \n",
" connected_shape_data_frame.plot(ax=ax, cmap=None, color=\"green\", label='Matched Road Element')\n",
" reference_poi_data_frame.plot(ax=ax, cmap=None, color=\"blue\", label='Points Referenced on Matched Road')\n",
"connected_shape_data_frame = gpd.GeoDataFrame(connected_shape_list,\n",
" columns=['LineString'], \n",
" geometry='LineString') \n",
"\n",
"road_network_data_frame.plot(ax=ax, color=\"pink\", label='Road Network')\n",
"traces_data_frame.plot(ax=ax,cmap=None, color=\"cyan\", label='Trace Line')\n",
"\n",
" plt.legend()\n",
" plt.show()"
"connected_shape_data_frame.plot(ax=ax, cmap=None, color=\"green\", label='Matched Road Element')\n",
"reference_poi_data_frame.plot(ax=ax, cmap=None, color=\"blue\", label='Points Referenced on Matched Road')\n",
"\n",
"plt.legend()\n",
"plt.show()"
]
}
],
Expand Down
12 changes: 4 additions & 8 deletions kaizen/map/matcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,9 @@ def add(
:param trace_information: information of the trace point for which the candidate was obtained
:return:
"""
assert None not in {
x,
y,
distance,
road_information,
trace_information,
}, "Expected ['x', 'y', 'candidate_id', 'distance', 'road_information', 'trace_information'] to be not None"
assert all(
v is not None for v in [x, y, distance, road_information, trace_information]
), "Expected ['x', 'y', 'candidate_id', 'distance', 'road_information', 'trace_information'] to be not None"

assert type(distance) is float, (
"Expected type to be 'float'," "got %s",
Expand All @@ -75,7 +71,7 @@ def add(

assert hasattr(road_information.property, "u") and hasattr(
road_information.property, "v"
), ("Expected road to have start node 'u' and end node 'v'" "for every edge")
), "Expected road to have start node 'u' and end node 'v'" "for every edge"

if isinstance(trace_information, dict):
trace_information = SimpleNamespace(**trace_information)
Expand Down
22 changes: 8 additions & 14 deletions kaizen/map/navigator.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,13 +243,10 @@ def path_finder_from_traces(
filter_trace: bool = True,
area_simplify: float = 0,
):
assert None not in {
grid,
traces,
search_space_threshold,
filter_trace,
area_simplify,
}, (
assert all(
v is not None
for v in [grid, traces, search_space_threshold, filter_trace, area_simplify]
), (
"Expected ['grid', 'trace', 'search_space_threshold', 'filter_trace', 'area_simplify'']"
"to be not NONE"
)
Expand Down Expand Up @@ -292,13 +289,10 @@ def path_finder_from_trace(
filter_trace: bool = True,
area_simplify: float = 0,
):
assert None not in {
grid,
trace,
search_space_threshold,
filter_trace,
area_simplify,
}, (
assert all(
v is not None
for v in [grid, trace, search_space_threshold, filter_trace, area_simplify]
), (
"Expected ['grid', 'trace', 'search_space_threshold', 'filter_trace', 'area_simplify'']"
"to be not NONE"
)
Expand Down
10 changes: 4 additions & 6 deletions kaizen/map/road.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,10 @@ def add(
feature_geometry: dict,
weight: float,
):
assert None not in {
feature_id,
feature_property,
feature_geometry,
weight,
}, "Expected ['feature_id', 'feature_property', 'feature_geometry', 'weight'] to be not None"
assert all(
v is not None
for v in [feature_id, feature_property, feature_geometry, weight]
), "Expected ['feature_id', 'feature_property', 'feature_geometry', 'weight'] to be not None"

assert type(feature_id) is int, (
"Expected 'feature_id' type to be 'int'," "got %s",
Expand Down
9 changes: 3 additions & 6 deletions kaizen/map/trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,9 @@ def add(self, x, y, trace_point_id, trace_id, **kwargs):
:param kwargs:
:return:
"""
assert None not in {
x,
y,
trace_point_id,
trace_id,
}, "Expected ['x', 'y', 'trace_point_id', 'trace_id'] to be not None"
assert all(
v is not None for v in [x, y, trace_point_id, trace_id]
), "Expected ['x', 'y', 'trace_point_id', 'trace_id'] to be not None"

self[trace_id].append(
TracePoint(x, y, trace_point_id, trace_id, SimpleNamespace(**kwargs))
Expand Down

0 comments on commit 7618f65

Please sign in to comment.