1 from django.contrib.gis.db import models
2 from django.conf import settings
3 from django.contrib.gis.measure import A, D
4 from madrona.unit_converter.models import length_in_display_units, area_in_display_units
5 from madrona.common.utils import KmlWrap, ComputeLookAt
6 from django.contrib.gis.geos import Point, Polygon, LinearRing
9 """Returns the currently active study region. The active study region is
10 determined by the active attribute.
11 """
13 return self.get(active=True)
14
18 """Model used for representing study regions
19
20 ====================== ==============================================
21 Attribute Description
22 ====================== ==============================================
23
24 ``name`` Name of the Study Region
25
26 ``active`` Whether the study region is treated as the
27 current authoritative copy. This should not be
28 set using the admin interface
29
30 ``creation_date`` Automatically assigned
31
32 ``modification_date`` Automatically assigned
33
34 ``geometry`` PolygonField representing the study region boundary
35
36 ``date_modified`` When the Study Region geometry was last updated.
37
38 ``lookAt_Lat`` Latitude of the default look-at point
39
40 ``lookAt_Lon`` Longitude of the default look-at point
41
42 ``lookAt_Range`` Range camera sits from the default look-at point
43
44 ``lookAt_Tilt`` Angle offset from vertical for default camera pos
45
46 ``lookAt_Heading`` Angle offset from North for default camera pos
47
48 ====================== ==============================================
49 """
50 name = models.CharField(verbose_name="Study Region Name", max_length=255)
51
52 active = models.BooleanField(default=False, help_text='This options will usually not be set using the admin interface, but rather by using the management commands relating to study region changes.')
53
54 creation_date = models.DateTimeField(auto_now_add=True)
55 modification_date = models.DateTimeField(auto_now=True)
56
57 geometry = models.MultiPolygonField(srid=settings.GEOMETRY_DB_SRID, null=True, blank=True, verbose_name="Study region boundary")
58
59 date_modified = models.DateTimeField(auto_now=True, verbose_name="Date Modified")
60
61 lookAt_Lat = models.FloatField(default=0, null=True, blank=True)
62 lookAt_Lon = models.FloatField(default=0, null=True, blank=True)
63 lookAt_Range = models.FloatField(default=80000, help_text='Distance from lookAt point in meters')
64 lookAt_Tilt = models.FloatField(default=0, help_text='Degrees from vertical (0=directly above)')
65 lookAt_Heading = models.FloatField(default=0, help_text='View direction in degrees (0=look North)')
66
67 objects = StudyRegionManager()
68
71
73 return u'%s' % self.name
74
75 - def save(self, *args, **kwargs):
81
82 @models.permalink
84 return ('madrona.studyregion.views.show', [self.pk])
85
86 @property
88 """
89 WARNING: This method assumes that the native units of the geometry are meters.
90 Returns the area of the study region in sq_mi
91 """
92 return area_in_display_units(self.geometry.area)
93
94 - def kml(self, style_domain):
95 """
96 Get the kml of the entire study region
97 """
98 bUseLod = False
99
100 if not bUseLod:
101 transform_geom = self.geometry.simplify(settings.KML_SIMPLIFY_TOLERANCE, preserve_topology=True)
102 transform_geom.transform(4326)
103
104 shape_kml = transform_geom.kml
105
106
107 shape_kml = shape_kml.replace('<Polygon>', '')
108 shape_kml = shape_kml.replace('</Polygon>', '')
109 shape_kml = shape_kml.replace('<outerBoundaryIs>', '')
110 shape_kml = shape_kml.replace('</outerBoundaryIs>', '')
111 shape_kml = shape_kml.replace('<innerBoundaryIs>', '')
112 shape_kml = shape_kml.replace('</innerBoundaryIs>', '')
113
114 return '<Document><name>%s</name>' % (self.name,) + self.lookAtKml() + '<Placemark><name>Study Region Boundaries</name>%s<styleUrl>http://%s/media/studyregion/styles.kml#StudyRegionStyle</styleUrl>%s</Placemark></Document>' % (self.lookAtKml(), style_domain, shape_kml,)
115
116 else:
117
118 trans_geom = self.geometry.clone()
119 trans_geom.transform(4326)
120
121 w = trans_geom.extent[0]
122 s = trans_geom.extent[1]
123 e = trans_geom.extent[2]
124 n = trans_geom.extent[3]
125
126 return '<Document><name>%s</name>' % (self.name,) + self.lookAtKml() + self.kml_chunk(n,s,e,w) + '</Document>'
127
128
130 """
131 Get the kml of a lat/lon bounded part of the study region,
132 with geometry simplified in proportion to the visible % of the region
133 """
134
135 bounds = Polygon(LinearRing([Point(w, n), Point(e, n), Point(e, s), Point(w, s), Point(w, n)]))
136 bounds.set_srid(4326)
137 center_lat = bounds.centroid.y
138 center_lon = bounds.centroid.x
139 bounds.transform(settings.GEOMETRY_DB_SRID)
140
141
142 zoom_width = (Point(bounds.extent[0], bounds.centroid.y)).distance(Point(bounds.extent[2], bounds.centroid.y))
143
144 full_shape_width = (Point(self.geometry.extent[0], self.geometry.centroid.y)).distance(Point(self.geometry.extent[2], self.geometry.centroid.y))
145
146
147
148
149
150 min_simplify_val = 50.0
151 max_simplify_val = 200.0
152 simplify_factor = max(min_simplify_val, min(max_simplify_val, max_simplify_val * zoom_width / full_shape_width))
153
154 transform_geom = self.geometry.simplify(simplify_factor, preserve_topology=True)
155 transform_geom = transform_geom.intersection(bounds)
156 transform_geom.transform(4326)
157
158
159
160
161
162
163
164
165
166 bLastLodLevel = simplify_factor < max_simplify_val
167 max_lod_pixels = 500
168 min_lod_pixels = 250
169
170
171 if bLastLodLevel:
172 max_lod_pixels = -1
173
174 retval = '<Region><LatLonAltBox><north>%f</north><south>%f</south><east>%f</east><west>%f</west></LatLonAltBox><Lod><minLodPixels>%f</minLodPixels><maxLodPixels>%f</maxLodPixels><minFadeExtent>0</minFadeExtent><maxFadeExtent>0</maxFadeExtent></Lod></Region>' % (n, s, e, w, min_lod_pixels, max_lod_pixels) + '<Placemark> <name>Study Region Boundaries</name><Style> <LineStyle> <color>ff00ffff</color> <width>2</width> </LineStyle> <PolyStyle> <color>8000ffff</color> </PolyStyle></Style>%s</Placemark>' % (transform_geom.kml,)
175
176
177 if not bLastLodLevel:
178 subregions = '<Folder><name>Study Region LODs</name>' + '<Folder><name>SE</name>' + self.kml_chunk(center_lat, s, e, center_lon) + '</Folder>'
179
180 subregions = subregions + '<Folder><name>NE</name>' + self.kml_chunk(n, center_lat, e, center_lon) + '</Folder>'
181
182 subregions = subregions + '<Folder><name>SW</name>' + self.kml_chunk(center_lat, s, center_lon, w) + '</Folder>'
183
184 subregions = subregions + '<Folder><name>NW</name>' + self.kml_chunk(n, center_lat, center_lon, w) + '</Folder>'
185
186 retval = retval + subregions + '</Folder>'
187
188 return retval
189
191 """
192 Get the kml for the region's lookat values saved in the DB,
193 or compute them if they are set to 0
194 """
195
196 if self.lookAt_Lat == 0.0 and self.lookAt_Lon == 0.0:
197 self.cacheLookAt()
198
199 retval = '<LookAt><latitude>%f</latitude><longitude>%f</longitude><range>%f</range><tilt>%f</tilt><heading>%f</heading><altitudeMode>clampToGround</altitudeMode></LookAt>' % (self.lookAt_Lat, self.lookAt_Lon, self.lookAt_Range, self.lookAt_Tilt, self.lookAt_Heading)
200 return retval
201
203 """
204 Compute and store the camera perspective that puts the whole study region in view
205 """
206
207 lookAtParams = ComputeLookAt(self.geometry)
208
209 self.lookAt_Range = lookAtParams['range']
210 self.lookAt_Lat = lookAtParams['latitude']
211 self.lookAt_Lon = lookAtParams['longitude']
212 self.lookAt_Tilt = lookAtParams['tilt']
213 self.lookAt_Heading = lookAtParams['heading']
214
215 self.save()
216
217
218
219
220
221
222