-
-
Notifications
You must be signed in to change notification settings - Fork 0
added route for calculating which points drone should fly to. #57
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 12 commits
a0f82ba
3dabc02
e066f7d
5e307e9
77ff9d3
ac809d3
2862c68
6524fe5
189b4a2
b5373a9
8b5931c
70e6a22
f4dfa26
76032e4
0fed727
b8b7c6d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add this to .gitignore |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| { | ||
| "python.testing.unittestArgs": [ | ||
| "-v", | ||
| "-s", | ||
| "./src", | ||
| "-p", | ||
| "*test*.py" | ||
| ], | ||
| "python.testing.pytestEnabled": false, | ||
| "python.testing.unittestEnabled": true | ||
| } |
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does storing these waypoint as a json instead of an array of
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ^ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,3 +12,20 @@ def save(self, **kwargs): | |
| if AreaOfInterest.objects.count() != 0: | ||
| AreaOfInterest.objects.all().delete() | ||
| super().save(**kwargs) # Call the "real" save() method. | ||
|
|
||
|
|
||
| class MappingRoute(models.Model): | ||
| """Singleton Model for drone route for mapping""" | ||
|
|
||
| # fields | ||
| # Stored list of points as arbitrary length JSON field to be consistent with area of interest | ||
| # altitude is how high the drone needs to be from ground when taking these pictures. | ||
| points_on_route = models.JSONField() | ||
| altitude = models.FloatField() | ||
|
|
||
| # methods | ||
| def save(self, **kwargs): | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this is a Singleton, please add that to the class name. Not too sure if a Singleton design pattern is necessary though, we can easily support two mapping areas that we do sequentially
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ^ |
||
|
|
||
| if MappingRoute.objects.count() != 0: | ||
| MappingRoute.objects.all().delete() | ||
| super().save(**kwargs) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| import math | ||
|
|
||
|
|
||
| def distance(p1x, p1y, p2x, p2y): | ||
| return math.sqrt(math.pow(p1x - p2x, 2) + math.pow(p1y - p2y, 2)) | ||
|
|
||
|
|
||
| def meshl(xcount, ycount, overlap): | ||
| meshGrid = [] | ||
| for i in range(xcount * ycount): | ||
| meshGrid.append(((i % xcount) + overlap) / (xcount - (1 - 2 * overlap))) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this be separated into a nested loop for code clarity? |
||
| return meshGrid | ||
|
|
||
|
|
||
| def meshr(xcount, ycount, overlap): | ||
| meshGrid = [] | ||
| for i in range(xcount * ycount): | ||
| meshGrid.append( | ||
| (math.floor(i / xcount) + overlap) / (ycount - (1 - 2 * overlap)) | ||
| ) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment as above here |
||
| return meshGrid | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,7 +2,12 @@ | |
| from django.views.decorators.csrf import csrf_exempt | ||
| from .serializers import AreaOfInterestSerializer | ||
| from .models import AreaOfInterest | ||
| from .models import MappingRoute | ||
| from .service import distance | ||
| from .service import meshl | ||
| from .service import meshr | ||
| import json | ||
| import math | ||
|
|
||
| # pylint: disable=no-member | ||
|
|
||
|
|
@@ -39,3 +44,97 @@ def process_area_of_interest(request): | |
| return HttpResponse("Correct Address, Incorrect Method", status=405) | ||
| except (KeyError, ValueError, TypeError) as e: | ||
| return HttpResponse("Server Error\n" + str(e), status=500) | ||
|
|
||
|
|
||
| @csrf_exempt | ||
| def process_points_on_route(request): | ||
| # Uses 4 most recent boundary points to make route mapping | ||
| try: | ||
| if request.method == "POST": | ||
| # Gets most recent Boundary points for computation | ||
| area_modelled = AreaOfInterest.objects.last() | ||
| if area_modelled is None: | ||
| return HttpResponse("No Area Of Interest Saved", status=204) | ||
| else: | ||
| # Camera Parameters (Focal length, Sensor Width, Sensor Height, Image Width | ||
| # Image Height, Ground Sample Distance, Image overlap %) | ||
| d_focal, sw, iw, ih, gsd, o = ( | ||
| 0.012, | ||
| 0.0131328, | ||
| 3840, | ||
| 2160, | ||
| 0.025, | ||
| 0.317, | ||
| ) | ||
|
|
||
| width, height = gsd * iw, gsd * ih | ||
| area = json.loads(area_modelled.area_of_interest) | ||
|
|
||
| # Generating List of Points | ||
| p1, p2, p3, p4 = area | ||
| p1x = p1["latitude"] | ||
| p1y = p1["longitude"] | ||
| p2x = p2["latitude"] | ||
| p2y = p2["longitude"] | ||
| p3x = p3["latitude"] | ||
| p3y = p3["longitude"] | ||
| p4x = p4["latitude"] | ||
| p4y = p4["longitude"] | ||
| # required altitude (meters) | ||
| alt = (iw * d_focal * gsd) / sw | ||
|
|
||
| # Maximum X and Y distances | ||
| ylen1 = distance(p1x, p1y, p2x, p2y) | ||
| ylen2 = distance(p3x, p3y, p4x, p4y) | ||
| ymax = max(ylen1, ylen2) | ||
|
|
||
| xlen1 = distance(p1x, p1y, p4x, p4y) | ||
| xlen2 = distance(p2x, p2y, p3x, p3y) | ||
| xmax = max(xlen1, xlen2) | ||
|
|
||
| # Num pictures needed on X-axis and Y-axis | ||
| xcount = math.ceil((xmax - (o * width)) / ((1 - o) * width)) + 1 | ||
| ycount = math.ceil((ymax - (o * height)) / ((1 - o) * height)) + 1 | ||
|
|
||
| # Creating Mesh Grids | ||
| gridl = meshl(xcount, ycount, o) | ||
| gridr = meshr(xcount, ycount, o) | ||
|
|
||
| # Projecting Mesh Grid onto images | ||
| final_grid = [] | ||
| for i in range(xcount * ycount): | ||
| newx = (p3x + gridl[i] * (p2x - p3x)) + gridr[i] * ( | ||
| p4x - p3x + gridl[i] * (p1x - p2x + p3x - p4x) | ||
| ) | ||
| newy = (p3y + gridl[i] * (p2y - p3y)) + gridr[i] * ( | ||
| p4y - p3y + gridl[i] * (p1y - p2y + p3y - p4y) | ||
| ) | ||
| final_grid.append([newx, newy]) | ||
|
|
||
| points = MappingRoute( | ||
| points_on_route=json.dumps(final_grid), altitude=json.dumps(alt) | ||
| ) | ||
| points.save() | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fine for now, but we will probably not need the grid to be saved once we've integrated your work with Kai's |
||
|
|
||
| return HttpResponse( | ||
| "New Mapping Route Successfully Saved" + "\n" + str(points), | ||
| status=200, | ||
| ) | ||
|
|
||
| elif request.method == "GET": | ||
| # Getting most recent drone rout from MappingRoute | ||
| route = MappingRoute.objects.last() | ||
| if route is None: | ||
| return HttpResponse("No Drone Route Saved", status=204) | ||
|
|
||
| points = { | ||
| "points_on_route": json.loads(route.points_on_route), | ||
| "altitude": route.altitude, | ||
| } | ||
|
|
||
| return JsonResponse(points, status=200) | ||
|
|
||
| else: | ||
| return HttpResponse("Correct Address, Incorrect Method", status=405) | ||
| except (KeyError, ValueError, TypeError) as e: | ||
| return HttpResponse("Server Error\n" + str(e), status=500) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add this folder to
.gitignore. also, in order to have test run by the CI, unittests should be done with django