Skip to content

Commit

Permalink
v1.6.0: added 3d profile
Browse files Browse the repository at this point in the history
  • Loading branch information
ychalier committed Dec 14, 2023
1 parent 9a86ef6 commit 8dfa086
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 9 deletions.
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ Django
django-mathfilters
gpxpy
numpy
numpy-stl
requests
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

setup(
name='django-topopartner',
version='1.5.0',
version='1.6.0',
packages=find_packages(),
include_package_data=True,
description='A Django app for topographic data management.',
Expand All @@ -32,6 +32,7 @@
"django-mathfilters",
"gpxpy",
"numpy",
"numpy-stl",
"requests",
],
)
2 changes: 1 addition & 1 deletion topopartner/templates/topopartner/partials/map_card.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@
<div class="card-footer">
<a class="btn btn-primary" href="{% url 'topopartner:view_track' tid=track.id %}">View</a>
<a class="btn btn-link" href="{% url 'topopartner:edit_track' tid=track.id %}">Edit</a>
<a class="btn btn-link" href="{% url 'topopartner:download_track' tid=track.id %}">Download</a>
<a class="btn btn-link" href="{% url 'topopartner:download_track_gpx' tid=track.id %}">Download</a>
</div>
</div>
8 changes: 7 additions & 1 deletion topopartner/templates/topopartner/track.html
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,17 @@ <h1>{{ track.label }}</h1>
</a>
</div>
<div>
<a href="{% url 'topopartner:download_track' tid=track.id %}" title="Download GPX file">
<a href="{% url 'topopartner:download_track_gpx' tid=track.id %}" title="Download GPX file">
<span class="track-info-icon" ><i class="icon icon-map"></i></span>
Download GPX
</a>
</div>
<div>
<a href="{% url 'topopartner:download_track_stl' tid=track.id %}" title="Download STL file">
<span class="track-info-icon" ><i class="icon icon-download"></i></span>
Download STL
</a>
</div>
</div>
{% if track.comment %}
<p>
Expand Down
2 changes: 2 additions & 0 deletions topopartner/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
path("track/<tid>/elevate", views.view_elevate_track, name="elevate_track"),
path("track/<tid>/smooth", views.view_smooth_track, name="smooth_track"),
path("track/<tid>/download", views.view_download_track, name="download_track"),
path("track/<tid>/download/gpx", views.view_download_track_gpx, name="download_track_gpx"),
path("track/<tid>/download/stl", views.view_download_track_stl, name="download_track_stl"),
path("track/<tid>/delete", views.view_delete_track, name="delete_track"),
path("track/<tid>/points", views.view_track_points, name="track_points"),
path("fit", views.view_fit, name="fit"),
Expand Down
54 changes: 48 additions & 6 deletions topopartner/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
"""

import io
import re
import math
import logging
import requests
import numpy
import math
import re

import gpxpy.gpx
from . import models
import numpy
import requests
import stl


LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -241,4 +242,45 @@ def clean(track, smoothing_threshold, simplification_target_proportion):
return simplify(
smooth(track, smoothing_threshold),
simplification_target_proportion * len(track)
)
)


def threed_profile(gpx: gpxpy.gpx.GPX,
latitude_scale: float=1000,
longitude_scale: float=1000,
elevation_scale: float=0.05) -> stl.mesh.Mesh:
points = [
point
for track in gpx.tracks
for segment in track.segments
for point in segment.points
]
has_elevations = any([p.elevation for p in points])
minimum_elevation = 0
if has_elevations:
minimum_elevation = min([p.elevation for p in points if p.elevation is not None])
mean_latitude = sum([p.latitude for p in points]) / len(points)
mean_longitude = sum([p.longitude for p in points]) / len(points)
vertices = []
for point in points:
x = latitude_scale * (point.latitude - mean_latitude)
y = longitude_scale * (point.longitude - mean_longitude)
z = 50
if has_elevations:
if point.elevation is None:
z = minimum_elevation
else:
z = elevation_scale * (point.elevation - minimum_elevation)
vertices.append([x, y, 0])
vertices.append([x, y, z])
faces = []
for i in range(len(points) - 1):
faces.append([2 * i, 2 * i + 1, 2 * i + 2])
faces.append([2 * i + 2, 2 * i + 1, 2 * i + 3])
vertices = numpy.array(vertices)
faces = numpy.array(faces)
mesh = stl.mesh.Mesh(numpy.zeros(faces.shape[0], dtype=stl.mesh.Mesh.dtype))
for i, face in enumerate(faces):
for j in range(3):
mesh.vectors[i][j] = vertices[face[j],:]
return mesh
20 changes: 20 additions & 0 deletions topopartner/views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import datetime
import json
import os
import tempfile

from django.shortcuts import render, redirect
from django.http import HttpResponse
Expand Down Expand Up @@ -230,6 +232,10 @@ def view_smooth_track(request, tid):


def view_download_track(request, tid):
return redirect("topopartner:download_track_gpx")


def view_download_track_gpx(request, tid):
"""Return the GPX of a track as an attachment.
"""
track = get_track_from_tid(tid, required_user=request.user, allow_public=True)
Expand All @@ -239,6 +245,20 @@ def view_download_track(request, tid):
return response


def view_download_track_stl(request, tid):
track = get_track_from_tid(tid, required_user=request.user, allow_public=True)
gpx = gpxpy.parse(track.gpx)
mesh = utils.threed_profile(gpx)
mesh_filename = os.path.join(tempfile.gettempdir(), slugify(track.label) + ".stl")
mesh.save(mesh_filename)
with open(mesh_filename, "rb") as file:
mesh_data = file.read()
os.remove(mesh_filename)
response = HttpResponse(mesh_data, content_type="model/stl")
response["Content-Disposition"] = f'attachment; filename="{slugify(track.label)}.stl"'
return response


@permission_required("topopartner.delete_track")
def view_delete_track(request, tid):
"""Delete a track.
Expand Down

0 comments on commit 8dfa086

Please sign in to comment.