Browse Source

Add a Reference model

Baptiste Jonglez 10 years ago
parent
commit
0334fbe08e
3 changed files with 86 additions and 1 deletions
  1. 8 1
      panorama/admin.py
  2. 37 0
      panorama/migrations/0003_auto_20150310_1853.py
  3. 41 0
      panorama/models.py

+ 8 - 1
panorama/admin.py

@@ -3,12 +3,19 @@ from __future__ import unicode_literals
 
 from django.contrib import admin
 
-from .models import Panorama, ReferencePoint
+from .models import Panorama, ReferencePoint, Reference
+
+
+class ReferenceInline(admin.TabularInline):
+    model = Reference
+    fk_name = "panorama"
+    extra = 1
 
 
 @admin.register(Panorama)
 class PanoramaAdmin(admin.ModelAdmin):
     model = Panorama
+    inlines = (ReferenceInline, )
     list_display = ('name', 'latitude', 'longitude', 'altitude', 'loop')
     fields = ('name', 'image', 'loop', ('latitude', 'longitude'), 'altitude')
 

+ 37 - 0
panorama/migrations/0003_auto_20150310_1853.py

@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('panorama', '0002_auto_20150304_1729'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Reference',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('x', models.PositiveIntegerField()),
+                ('y', models.PositiveIntegerField()),
+                ('panorama', models.ForeignKey(related_name='panorama_references', to='panorama.Panorama')),
+                ('reference_point', models.ForeignKey(related_name='refpoint_references', to='panorama.ReferencePoint')),
+            ],
+            options={
+            },
+            bases=(models.Model,),
+        ),
+        migrations.AlterUniqueTogether(
+            name='reference',
+            unique_together=set([('reference_point', 'panorama')]),
+        ),
+        migrations.AddField(
+            model_name='panorama',
+            name='references',
+            field=models.ManyToManyField(related_name='referenced_panorama', through='panorama.Reference', to='panorama.ReferencePoint'),
+            preserve_default=True,
+        ),
+    ]

+ 41 - 0
panorama/models.py

@@ -7,6 +7,7 @@ from math import radians, degrees, sin, cos, asin, atan2, sqrt
 
 from django.db import models
 from django.conf import settings
+from django.core.exceptions import ValidationError
 from django.core.validators import MinValueValidator, MaxValueValidator
 from django.utils.encoding import python_2_unicode_compatible
 
@@ -106,6 +107,10 @@ class Panorama(ReferencePoint):
     loop = models.BooleanField(default=False, verbose_name="360° panorama",
                                help_text="Whether the panorama loops around the edges")
     image = models.ImageField(verbose_name="image", upload_to="pano")
+    # Set of references, i.e. reference points with information on how
+    # they relate to this panorama.
+    references = models.ManyToManyField(ReferencePoint, through='Reference',
+                                        related_name="referenced_panorama")
 
     def tiles_dir(self):
         return os.path.join(settings.MEDIA_ROOT, settings.PANORAMA_TILES_DIR,
@@ -128,3 +133,39 @@ class Panorama(ReferencePoint):
 
     def __str__(self):
         return "Panorama : " + self.name
+
+
+class Reference(models.Model):
+    """A reference is made of a Panorama, a Reference Point, and the position
+    (x, y) of the reference point inside the image.  With enough
+    references, the panorama is calibrated.  That is, we can build a
+    mapping between pixels of the image and directions in 3D space, which
+    are represented by (azimuth, elevation) couples."""
+
+    # Components of the ManyToMany relation
+    reference_point = models.ForeignKey(ReferencePoint, related_name="refpoint_references")
+    panorama = models.ForeignKey(Panorama, related_name="panorama_references")
+    # Position of the reference point in the panorama image
+    x = models.PositiveIntegerField()
+    y = models.PositiveIntegerField()
+
+    class Meta:
+        # It makes no sense to have multiple references of the same
+        # reference point on a given panorama.
+        unique_together = (("reference_point", "panorama"),)
+
+    def clean(self):
+        # Check that the reference point and the panorama are different
+        # (remember that panoramas can *also* be seen as reference points)
+        if self.panorama.pk == self.reference_point.pk:
+            raise ValidationError("A panorama can't reference itself.")
+        # Check than the position is within the bounds of the image.
+        w = self.panorama.image.width
+        h = self.panorama.image.height
+        if self.x >= w or self.y >= h:
+            raise ValidationError("Position ({x}, {y}) is outside the bounds "
+                                  "of the image ({width}, {height}).".format(
+                                      x=self.x,
+                                      y=self.y,
+                                      width=w,
+                                      height=h))