past3d/pastebin/models.py

172 lines
5.3 KiB
Python

import os.path
import struct
import re
from hashlib import md5
from datetime import datetime, timedelta
from django.urls import reverse
from django.contrib.auth.models import User
from django.db import models
vertex_pattern = re.compile(r'vertex\s+([0-9.e+-]+)\s+([0-9.e+-]+)\s+([0-9.e+-]+)')
def model_path(instance, filename):
ext = os.path.splitext(filename)[1]
md5sum = md5()
md5sum.update(instance.name.encode('utf-8') +
str(datetime.now()).encode('utf-8') +
filename.encode('utf-8'))
randomname = md5sum.hexdigest()
return os.path.join('models', '%s%s' % (randomname, ext))
def source_path(instance, filename):
ext = os.path.splitext(filename)[1]
md5sum = md5()
md5sum.update(instance.name.encode('utf-8') +
str(datetime.now()).encode('utf-8') +
filename.encode('utf-8'))
randomname = md5sum.hexdigest()
return os.path.join('sources', '%s%s' % (randomname, ext))
class Geometry(models.Model):
HOUR = 0
DAY = 1
WEEK = 2
MONTH = 3
FORERVER = 4
EXPIRATION_CHOICES = ((HOUR, 'one hour'), (DAY, 'one day'), (WEEK, 'one week'),
(MONTH, 'one month'), (FORERVER, 'forever'))
DELTAS = {
HOUR: timedelta(hours=1),
DAY: timedelta(days=1),
WEEK: timedelta(weeks=1),
MONTH: timedelta(weeks=4)
}
name = models.CharField(max_length=128)
description = models.TextField(blank=True)
user = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE)
date = models.DateTimeField(auto_now_add=True)
expiration = models.IntegerField(default=0, choices=EXPIRATION_CHOICES)
public = models.BooleanField(default=True)
polycount = models.IntegerField(blank=True, default=0)
width = models.FloatField(blank=True, default=0)
depth = models.FloatField(blank=True, default=0)
height = models.FloatField(blank=True, default=0)
file = models.FileField(upload_to=model_path)
sourcefile = models.FileField(upload_to=source_path, blank=True)
def get_absolute_url(self):
return reverse('geometry_details', kwargs={'id': self.pk})
@classmethod
def get_latest(cls):
return cls.objects.all().filter(public=True).order_by('-date')[:10]
def get_expiration_date(self):
for expiration in [self.HOUR, self.DAY, self.WEEK, self.MONTH]:
if self.expiration == expiration:
return self.date + self.DELTAS[expiration]
return None
def _generate_meta_infos(self):
print("Generating metainfos %s" % self.name)
self.file.open()
count = 0
min_coord = [None, None, None]
max_coord = [None, None, None]
if self.file.read(5) != "solid":
print("binary")
# Skip header
self.file.seek(80)
count = struct.unpack("i", self.file.read(4))[0]
done = False
for pos in range(0, count):
# Skip normal (3 * 32bit)
self.file.seek(self.file.tell() + 3 * 4)
# Loop over each coordinate
for vert in range(0, 3):
# Loop over each coordinate
for i in range(0, 3):
x = struct.unpack("<f", self.file.read(4))[0]
if min_coord[i] is not None:
min_coord[i] = min(min_coord[i], x)
else:
min_coord[i] = x
if max_coord[i] is not None:
max_coord[i] = max(max_coord[i], x)
else:
max_coord[i] = x
# Skip attributes (16bit)
self.file.seek(self.file.tell() + 2)
else:
print("ascii")
line = self.file.readline()
while line != "":
line = line.strip()
if line.startswith("facet"):
count = count + 1
if line.startswith("vertex"):
coords = vertex_pattern.match(line).groups()
for i in range(0, 3):
x = float(coords[i])
if min_coord[i] is not None:
min_coord[i] = min(min_coord[i], x)
else:
min_coord[i] = x
if max_coord[i] is not None:
max_coord[i] = max(max_coord[i], x)
else:
max_coord[i] = x
line = self.file.readline()
self.file.close()
self.width = max_coord[0] - min_coord[0]
self.depth = max_coord[1] - min_coord[1]
self.height = max_coord[2] - min_coord[2]
self.polycount = count
self.save()
def get_polycount(self):
if self.polycount == 0:
self._generate_meta_infos()
return self.polycount
def get_width(self):
if self.polycount == 0:
self._generate_meta_infos()
return self.width
def get_depth(self):
if self.polycount == 0:
self._generate_meta_infos()
return self.depth
def get_height(self):
if self.polycount == 0:
self._generate_meta_infos()
return self.height