Package eoxserver :: Package resources :: Package coverages :: Module filters
[hide private]
[frames] | no frames]

Source Code for Module eoxserver.resources.coverages.filters

   1  #----------------------------------------------------------------------- 
   2  # $Id: filters.py 1362 2012-02-27 17:14:03Z schindlerf $ 
   3  # 
   4  # Project: EOxServer <http://eoxserver.org> 
   5  # Authors: Stephan Krause <stephan.krause@eox.at> 
   6  #          Stephan Meissl <stephan.meissl@eox.at> 
   7  # 
   8  #------------------------------------------------------------------------------- 
   9  # Copyright (C) 2011 EOX IT Services GmbH 
  10  # 
  11  # Permission is hereby granted, free of charge, to any person obtaining a copy 
  12  # of this software and associated documentation files (the "Software"), to deal 
  13  # in the Software without restriction, including without limitation the rights 
  14  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell  
  15  # copies of the Software, and to permit persons to whom the Software is  
  16  # furnished to do so, subject to the following conditions: 
  17  # 
  18  # The above copyright notice and this permission notice shall be included in all 
  19  # copies of this Software or works derived from this Software. 
  20  # 
  21  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
  22  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
  23  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
  24  # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
  25  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
  26  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
  27  # THE SOFTWARE. 
  28  #----------------------------------------------------------------------- 
  29  """ 
  30  This module defines filters and filter expressions for EO Coverages. 
  31  For more information on filters, see :mod:`eoxserver.core.filters`. 
  32  """ 
  33   
  34  import math 
  35  from datetime import datetime 
  36   
  37  from django.db.models import Q, Count 
  38  from django.contrib.gis.geos import ( 
  39      fromstr as geos_fromstr, Polygon 
  40  ) 
  41  from django.contrib.gis.gdal import SpatialReference 
  42   
  43  from eoxserver.core.system import System 
  44  from eoxserver.core.registry import FactoryInterface 
  45  from eoxserver.core.filters import ( 
  46      FilterExpressionInterface, FilterInterface, SimpleExpression, 
  47      SimpleExpressionFactory 
  48  ) 
  49  from eoxserver.core.util.timetools import UTCOffsetTimeZoneInfo 
  50  from eoxserver.core.exceptions import ( 
  51      InternalError, InvalidExpressionError, UnknownAttribute 
  52  ) 
  53  from eoxserver.backends.base import LocationWrapper 
  54  from eoxserver.resources.coverages.models import EOMetadataRecord 
  55  from eoxserver.resources.coverages.wrappers import ( 
  56      RectifiedDatasetWrapper, ReferenceableDatasetWrapper, 
  57      RectifiedStitchedMosaicWrapper, DatasetSeriesWrapper 
  58  ) 
59 60 #----------------------------------------------------------------------- 61 # Helper classes 62 #----------------------------------------------------------------------- 63 64 -class Slice(object):
65 """ 66 This class contains information about a slice subsetting. The 67 constructor accepts three arguments: 68 69 * ``crs_id``: either ``"imageCRS"`` or an integer EPSG SRID, 70 * ``axis_label``: the axis label the slicing operation refers to, 71 * ``slice_point``: a :class:`float` or :class:`int` containing the 72 slice point information 73 74 :exc:`~.InternalError` is raised if arguments do not validate. 75 """
76 - def __init__(self, crs_id, axis_label, slice_point):
77 self.__validate(crs_id, axis_label, slice_point) 78 79 self.__crs_id = crs_id 80 self.__axis_label = axis_label 81 self.__slice_point = slice_point
82
83 - def __validate(self, crs_id, axis_label, slice_point):
84 if not (crs_id == "imageCRS" or isinstance(crs_id, int)): 85 raise InternalError( 86 "'crs_id' must be set to 'imageCRS' or to an integer." 87 ) 88 89 if not (isinstance(slice_point, float) or\ 90 isinstance(slice_point, int)): 91 raise InternalError( 92 "Slice point must be float or int." 93 )
94 95 #: Read only attribute. 96 @property
97 - def crs_id(self):
98 return self.__crs_id
99 100 #: Read only attribute. 101 @property
102 - def axis_label(self):
103 return self.__axis_label
104 105 # Read only attribute. 106 @property
107 - def slice_point(self):
108 return self.__slice_point
109
110 -class BoundedArea(object):
111 """ 112 This class contains information about a bounded area. The 113 constructor accepts a ``crs_id`` and four bounds arguments 114 ``minx, miny, maxx, maxy``. The ``crs_id`` parameter may be set to 115 ``"imageCRS"`` or an integer EPSG SRID. The bounds parameters may 116 be set to a :class:`float` or :class:`int` value designating the 117 bound in the given coordinate system or to ``"unbounded"``. 118 119 :exc:`~.InternalError` is raised if the arguments do not validate. 120 :exc:`~.InvalidExpressionError` is raised if the lower bounds of 121 an axis are greater than the upper bounds. 122 """
123 - def __init__(self, crs_id, minx, miny, maxx, maxy):
124 self.__validate(crs_id, minx, miny, maxx, maxy) 125 126 self.__crs_id = crs_id 127 self.__minx = minx 128 self.__miny = miny 129 self.__maxx = maxx 130 self.__maxy = maxy
131
132 - def __validate(self, crs_id, minx, miny, maxx, maxy):
133 if not (crs_id == "imageCRS" or isinstance(crs_id, int)): 134 raise InternalError( 135 "'crs_id' must be set to 'imageCRS' or to an integer." 136 ) 137 138 for bound in (minx, miny, maxx, maxy): 139 if not (bound == "unbounded" or isinstance(bound, float) or\ 140 isinstance(bound, int)): 141 raise InternalError( 142 "Bounds must be set to 'unbounded', float or int." 143 ) 144 145 if (not (minx == "unbounded" or maxx == "unbounded") and minx > maxx) or\ 146 (not (miny == "unbounded" or maxy == "unbounded") and miny > maxy): 147 raise InvalidExpressionError( 148 "Invalid bounds: lower bound greater than upper bound." 149 )
150 151 #: Read only attribute. 152 @property
153 - def crs_id(self):
154 return self.__crs_id
155 156 #: Read only attribute. 157 @property
158 - def minx(self):
159 return self.__minx
160 161 #: Read only attribute. 162 @property
163 - def miny(self):
164 return self.__miny
165 166 #: Read only attribute. 167 @property
168 - def maxx(self):
169 return self.__maxx
170 171 #: Read only attribute. 172 @property
173 - def maxy(self):
174 return self.__maxy
175
176 -class TimeInterval(object):
177 """ 178 This class contains information about a time interval. The 179 constructor accepts two arguments: ``begin`` and ``end`` which 180 must be set either to the string ``"unbounded"`` or a 181 :class:`datetime.datetime` object. 182 183 :exc:`~.InternalError` is raised if the arguments do not validate. 184 :exc:`~.InvalidExpressionError` is raised if the begin time is 185 later than the end time. 186 """ 187
188 - def __init__(self, begin, end):
189 self.__validate(begin, end) 190 191 self.__begin = begin 192 self.__end = end
193
194 - def __validate(self, begin, end):
195 for timestamp in (begin, end): 196 if not (timestamp == "unbounded" or isinstance(timestamp, datetime)): 197 raise InternalError( 198 "Time bound must be 'unbounded' or 'datetime.datetime' object." 199 ) 200 201 if not (begin == "unbounded" or end == "unbounded") and end < begin: 202 raise InvalidExpressionError( 203 "Begin of time interval later than end." 204 )
205 206 @property
207 - def begin(self):
208 return self.__begin
209 210 @property
211 - def end(self):
212 return self.__end
213
214 #----------------------------------------------------------------------- 215 # Filter Expressions 216 #----------------------------------------------------------------------- 217 218 -class AttributeExpression(SimpleExpression):
219 """ 220 Filter expression implementation representing an attribute lookup 221 on a model. Expects three operands: 222 223 * the attribute name; the possible names are defined separately for 224 each resource class; 225 * the matching operation; the range of applicable operations 226 comprises the field lookups defined by Django; the 'search', 227 'regex' and 'iregex' operations are not supported because they are 228 database dependent; the shortcuts "=", "<", "<=", ">=", ">" are 229 allowed; 230 * the search value; has to be convertible to the type of the 231 attribute 232 """ 233 REGISTRY_CONF = { 234 "name": "Attribute Lookup Expression", 235 "impl_id": "resources.coverages.filters.AttributeExpression", 236 "factory_ids": ("resources.coverages.filters.CoverageExpressionFactory",) 237 } 238 239 OP_NAME = "attr" 240 NUM_OPS = 3 241 242 LOOKUPS = ( 243 "=", "exact", "iexact", "contains", "icontains", "in", ">" , 244 "gt", ">=", "gte", "<", "lt", "<=", "lte", "startswith", 245 "istartswith", "endswith", "iendswith", "range", "year", 246 "month", "day", "weekday", "isnull" 247 ) 248 249
250 - def _validateOperands(self, operands):
251 super(AttributeExpression, self)._validateOperands(operands) 252 253 if operands[1].lstrip("!") not in self.LOOKUPS: 254 raise InternalError( 255 "'%s' is not a known field lookup operation." % \ 256 operands[1] 257 )
258 259 AttributeExpressionImplementation = \ 260 FilterExpressionInterface.implement(AttributeExpression)
261 262 -class TimeSliceExpression(SimpleExpression):
263 """ 264 Filter expression implementation representing a time slice. Expects 265 one operand: a :class:`datetime.datetime` object representing the 266 slice point in time. 267 """ 268 REGISTRY_CONF = { 269 "name": "Time Slice Expression", 270 "impl_id": "resources.coverages.filters.TimeSliceExpression", 271 "factory_ids": ("resources.coverages.filters.CoverageExpressionFactory",) 272 } 273 274 OP_NAME = "time_slice" 275 NUM_OPS = 1 276
277 - def _validateOperands(self, operands):
278 super(TimeSliceExpression, self)._validateOperands(operands) 279 280 if not isinstance(operands[0], datetime): 281 raise InternalError( 282 "Expected 'datetime.datetime' object as operand, got '%s' object." % operands[0].__class__.__name__ 283 )
284 285 TimeSliceExpressionImplementation = \ 286 FilterExpressionInterface.implement(TimeSliceExpression)
287 288 -class TimeIntervalExpression(SimpleExpression):
289 """ 290 Filter expression implementation representing a time interval. 291 It expects one operand of type :class:`TimeInterval`. 292 """ 293 NUM_OPS = 1 294
295 - def _validateOperands(self, operands):
296 super(TimeIntervalExpression, self)._validateOperands(operands) 297 298 if not isinstance(operands[0], TimeInterval): 299 raise InternalError( 300 "Expected 'TimeInterval' object as operand, got '%s' object." % operands[0].__class__.__name__ 301 )
302
303 -class IntersectingTimeIntervalExpression(TimeIntervalExpression):
304 """ 305 Filter expression implementation that matches if a time or 306 time interval intersects with the time interval specified in the 307 expression. Inherits from :class:`TimeIntervalExpression`. 308 """ 309 REGISTRY_CONF = { 310 "name": "Intersecting Time Interval Expression", 311 "impl_id": "resources.coverages.filters.IntersectingTimeIntervalExpression", 312 "factory_ids": ("resources.coverages.filters.CoverageExpressionFactory",) 313 } 314 315 OP_NAME = "time_intersects"
316 317 IntersectingTimeIntervalExpressionImplementation = \ 318 FilterExpressionInterface.implement(IntersectingTimeIntervalExpression)
319 320 -class ContainingTimeIntervalExpression(TimeIntervalExpression):
321 """ 322 Filter expression implementation that matches if a time or time 323 interval is contained in the time interval specified in the 324 expression. Inherits from :class:`TimeIntervalExpression`. 325 """ 326 REGISTRY_CONF = { 327 "name": "Containing Time Interval Expression", 328 "impl_id": "resources.coverages.filters.ContainingTimeIntervalExpression", 329 "factory_ids": ("resources.coverages.filters.CoverageExpressionFactory",) 330 } 331 332 OP_NAME = "time_within"
333 334 ContainingTimeIntervalExpressionImplementation = \ 335 FilterExpressionInterface.implement(ContainingTimeIntervalExpression)
336 337 -class SpatialSliceExpression(SimpleExpression):
338 """ 339 Filter expression implementation that represents a slice subsetting. 340 It expects one operand of type :class:`Slice`. 341 """ 342 REGISTRY_CONF = { 343 "name": "Spatial Slice Expression", 344 "impl_id": "resources.coverages.filters.SpatialSliceExpression", 345 "factory_ids": ("resources.coverages.filters.CoverageExpressionFactory",) 346 } 347 348 OP_NAME = "spatial_slice" 349 NUM_OPS = 1 350
351 - def _validateOperands(self, operands):
352 super(SpatialSliceExpression, self)._validateOperands(operands) 353 354 if not isinstance(operands[0], Slice): 355 raise InternalError( 356 "Expected operand of type 'Slice', got '%s' object" %\ 357 operands[0].__class__.__name__ 358 )
359 360 SpatialSliceExpressionImplementation = \ 361 FilterExpressionInterface.implement(SpatialSliceExpression)
362 363 -class BoundedAreaExpression(SimpleExpression):
364 """ 365 Filter expression implementation that represents a trim or BBOX 366 subsetting. It expects one operand of type :class:`BoundedArea`. 367 """ 368 NUM_OPS = 1 369
370 - def _validateOperands(self, operands):
371 super(BoundedAreaExpression, self)._validateOperands(operands) 372 373 if not isinstance(operands[0], BoundedArea): 374 raise InvalidExpressionError( 375 "Expected 'BoundedArea' object as operand, got '%s' object" %\ 376 operands[0].__class__.__name__ 377 )
378
379 -class FootprintIntersectsAreaExpression(BoundedAreaExpression):
380 """ 381 Filter expression implementation that matches if the footprint 382 of an object intersects the given :class:`BoundedArea`. Inherits 383 from :class:`BoundedAreaExpression`. 384 """ 385 REGISTRY_CONF = { 386 "name": "Footprint intersects area Expression", 387 "impl_id": "resources.coverages.filters.FootprintIntersectsAreaExpression", 388 "factory_ids": ("resources.coverages.filters.CoverageExpressionFactory",) 389 } 390 391 OP_NAME = "footprint_intersects_area"
392 393 FootprintIntersectsAreaExpressionImplementation = \ 394 FilterExpressionInterface.implement(FootprintIntersectsAreaExpression)
395 396 -class FootprintWithinAreaExpression(BoundedAreaExpression):
397 """ 398 Filter expression implementation that matches if the footprint 399 of an object is contained within the given :class:`BoundedArea`. 400 Inherits from :class:`BoundedAreaExpression`. 401 """ 402 REGISTRY_CONF = { 403 "name": "Footprint within area Expression", 404 "impl_id": "resources.coverages.filters.FootprintWithinAreaExpression", 405 "factory_ids": ("resources.coverages.filters.CoverageExpressionFactory",) 406 } 407 408 OP_NAME = "footprint_within_area"
409 410 FootprintWithinAreaExpressionImplementation = \ 411 FilterExpressionInterface.implement(FootprintWithinAreaExpression)
412 413 -class ContainedCoverageExpression(SimpleExpression):
414 """ 415 Filter expression referring to the coverages contained in a 416 container object (StitchedMosaic or DatasetSeries). Expects one 417 operand, namely an integer resource ID relating to the container 418 object. 419 """ 420 REGISTRY_CONF = { 421 "name": "Contained Coverage Expression", 422 "impl_id": "resources.coverages.filters.ContainedCoverageExpression", 423 "factory_ids": ("resources.coverages.filters.CoverageExpressionFactory",) 424 } 425 426 OP_NAME = "contained_in" 427 NUM_OPS = 1 428
429 - def _validateOperands(self, operands):
430 super(ContainedCoverageExpression, self)._validateOperands(operands) 431 432 if not isinstance(operands[0], int): 433 raise InternalError( 434 "Expected integer resource ID, got '%s' object." % 435 operands[0].__class__.__name__ 436 )
437 438 ContainedCoverageExpressionImplementation = \ 439 FilterExpressionInterface.implement(ContainedCoverageExpression)
440 441 -class ContainsCoverageExpression(SimpleExpression):
442 """ 443 Filter expression referring to the coverages containing a 444 StitchedMosaic or Dataset. Expects one operand, namely an integer resource 445 ID relating to the contained object. 446 """ 447 REGISTRY_CONF = { 448 "name": "Contains Coverage Expression", 449 "impl_id": "resources.coverages.filters.ContainsCoverageExpression", 450 "factory_ids": ("resources.coverages.filters.CoverageExpressionFactory",) 451 } 452 453 OP_NAME = "contains" 454 NUM_OPS = 1 455
456 - def _validateOperands(self, operands):
457 super(ContainsCoverageExpression, self)._validateOperands(operands) 458 459 if not isinstance(operands[0], int): 460 raise InternalError( 461 "Expected integer resource ID, got '%s' object." % 462 operands[0].__class__.__name__ 463 )
464 465 ContainsCoverageExpressionImplementation = \ 466 FilterExpressionInterface.implement(ContainsCoverageExpression)
467 468 -class OrphanedCoverageExpression(SimpleExpression):
469 """ 470 Filter expression implementation that matches coverages which are 471 not related to any container (StitchedMosaic or DatasetSeries). 472 Takes no operands. 473 """ 474 475 REGISTRY_CONF = { 476 "name": "Orphaned Coverage Expression", 477 "impl_id": "resources.coverages.filters.OrphanedCoverageExpression", 478 "factory_ids": ("resources.coverages.filters.CoverageExpressionFactory",) 479 } 480 481 OP_NAME = "orphaned" 482 NUM_OPS = 0
483 484 OrphanedCoverageExpressionImplementation = \ 485 FilterExpressionInterface.implement(OrphanedCoverageExpression)
486 487 488 -class LocationReferencesDatasetExpression(SimpleExpression):
489 """ 490 Filter expression that matches datasets which are referenced by a location. 491 """ 492 493 REGISTRY_CONF = { 494 "name": "Location References Dataset Expression", 495 "impl_id": "resources.coverages.filters.LocationReferencesDatasetExpression", 496 "factory_ids": ("resources.coverages.filters.CoverageExpressionFactory",) 497 } 498 499 OP_NAME = "referenced_by" 500 NUM_OPS = 1 501
502 - def _validateOperands(self, operands):
503 super(LocationReferencesDatasetExpression, self)._validateOperands(operands) 504 505 if not isinstance(operands[0], LocationWrapper): 506 raise InternalError( 507 "Expected LocationWrapper, got '%s' object." % 508 operands[0].__class__.__name__ 509 )
510 511 LocationReferencesDatasetExpressionImplementation = \ 512 FilterExpressionInterface.implement(LocationReferencesDatasetExpression)
513 514 #----------------------------------------------------------------------- 515 # Filters 516 #----------------------------------------------------------------------- 517 518 -class AttributeFilter(object):
519 """ 520 Base class for attribute lookup filters. 521 """ 522 523 WRAPPER_CLASS = None # To be overridden by implementations 524
525 - def _getField(self, attr):
526 return self.WRAPPER_CLASS().getAttrField(attr)
527
528 - def _getLookup(self, op):
529 if op == "=": 530 return "" 531 elif op == "<": 532 return "__lt" 533 elif op == "<=": 534 return "__lte" 535 elif op == ">=": 536 return "__gte" 537 elif op == ">": 538 return "__gt" 539 else: 540 return "__%s" % op
541
542 - def _matchValues(self, model_value, op, value):
543 try: 544 if op in ("=", "exact"): 545 return model_value == value 546 elif op == "iexact": 547 return model_value.lower() == value.lower() 548 elif op == "contains": 549 return model_value.find(value) != -1 550 elif op == "icontains": 551 return model_value.lower().find(value.lower()) != -1 552 elif op == "in": 553 return model_value in value 554 elif op in ("<", "lt"): 555 return model_value < value 556 elif op in ("<=", "lte"): 557 return model_value <= value 558 elif op in (">=", "gte"): 559 return model_value >= value 560 elif op in (">", "gt"): 561 return model_value > value 562 elif op == "startswith": 563 return model_value.startswith(value) 564 elif op == "istartswith": 565 return model_value.lower().startswith(value.lower()) 566 elif op == "endswith": 567 return model_value.endswith(value) 568 elif op == "iendswith": 569 return model_value.lower().endswith(value.lower()) 570 elif op == "range": 571 return value[0] <= model_value and model_value <= value[1] 572 elif op == "year": 573 return model_value.year == value 574 elif op == "month": 575 return model_value.month == value 576 elif op == "day": 577 return model_value.day == value 578 elif op == "weekday": 579 return model_value.weekday() == value 580 elif op == "isnull": 581 if value: 582 return model_value is None 583 else: 584 return model_value is not None 585 except: 586 raise InvalidExpressionError( 587 "Could not apply attribute expression to given attribute." 588 )
589
590 - def _splitRawOp(self, raw_op):
591 if raw_op.startswith("!"): 592 invert = True 593 op = raw_op.lstrip("!") 594 else: 595 invert = False 596 op = raw_op 597 598 return (invert, op)
599
600 - def applyToQuerySet(self, expr, qs):
601 attr, raw_op, value = expr.getOperands() 602 603 invert, op = self._splitRawOp(raw_op) 604 605 try: 606 field = self._getField(attr) 607 # fail gracefully if the attribute name is unknown 608 except UnknownAttribute: 609 return qs 610 611 if not invert: 612 return qs.filter(**{ 613 "%s%s" % (field, self._getLookup(op)): value 614 }) 615 else: 616 return qs.exclude(**{ 617 "%s%s" % (field, self._getLookup(op)): value 618 })
619
620 - def resourceMatches(self, expr, res):
621 attr, raw_op, value = expr.getOperands() 622 623 invert, op = self._splitRawOp(raw_op) 624 625 model_value = res.getAttrValue(attr) 626 627 if not invert: 628 return self._matchValues(model_value, op, value) 629 else: 630 return not self._matchValues(model_value, op, value)
631
632 -class RectifiedDatasetAttributeFilter(AttributeFilter):
633 """ 634 Filter that executes attribute lookups on Rectified Datasets. 635 """ 636 637 REGISTRY_CONF = { 638 "name": "Attribute Lookup Filter for Rectified Datasets", 639 "impl_id": "resources.coverages.filters.RectifiedDatasetAttribute", 640 "registry_values": { 641 "core.filters.res_class_id": "resources.coverages.wrappers.RectifiedDatasetWrapper", 642 "core.filters.expr_class_id": "resources.coverages.filters.AttributeExpression" 643 } 644 } 645 646 WRAPPER_CLASS = RectifiedDatasetWrapper
647 648 RectifiedDatasetAttributeFilterImplementation = \ 649 FilterInterface.implement(RectifiedDatasetAttributeFilter)
650 651 -class ReferenceableDatasetAttributeFilter(AttributeFilter):
652 """ 653 Filter that executes attribute lookup operations on Referenceable 654 Datasets. 655 """ 656 657 REGISTRY_CONF = { 658 "name": "Attribute Lookup Filter for Referenceable Datasets", 659 "impl_id": "resources.coverages.filters.ReferenceableDatasetAttribute", 660 "registry_values": { 661 "core.filters.res_class_id": "resources.coverages.wrappers.ReferenceableDatasetWrapper", 662 "core.filters.expr_class_id": "resources.coverages.filters.AttributeExpression" 663 } 664 } 665 666 WRAPPER_CLASS = ReferenceableDatasetWrapper
667 668 ReferenceableDatasetAttributeFilterImplementation = \ 669 FilterInterface.implement(ReferenceableDatasetAttributeFilter)
670 671 -class RectifiedStitchedMosaicAttributeFilter(AttributeFilter):
672 """ 673 Filter that executes attribute lookup operations on Rectified 674 Stitched Mosaics. 675 """ 676 677 REGISTRY_CONF = { 678 "name": "Attribute Lookup Filter for Rectified Stitched Mosaics", 679 "impl_id": "resources.coverages.filters.RectifiedStitchedMosaicAttribute", 680 "registry_values": { 681 "core.filters.res_class_id": "resources.coverages.wrappers.RectifiedStitchedMosaicWrapper", 682 "core.filters.expr_class_id": "resources.coverages.filters.AttributeExpression" 683 } 684 } 685 686 WRAPPER_CLASS = RectifiedStitchedMosaicWrapper
687 688 RectifiedStitchedMosaicAttributeFilterImplementation = \ 689 FilterInterface.implement(RectifiedStitchedMosaicAttributeFilter)
690 691 -class TimeSliceFilter(object):
692 """ 693 Filter class for time slice operations. 694 """
695 - def applyToQuerySet(self, expr, qs):
696 timestamp = expr.getOperands()[0] 697 698 qs = qs.exclude(eo_metadata__timestamp_begin__gt=timestamp) 699 qs = qs.exclude(eo_metadata__timestamp_end__lt=timestamp) 700 701 return qs
702
703 - def resourceMatches(self, expr, res):
704 timestamp = expr.getOperands()[0] 705 706 return not timestamp < res.getBeginTime() or\ 707 not res.getEndTime() < timestamp
708
709 -class RectifiedDatasetTimeSliceFilter(TimeSliceFilter):
710 """ 711 Filter which matches Rectified Datasets whose acquisition time 712 interval contains a given timestamp. 713 """ 714 REGISTRY_CONF = { 715 "name": "Time Slice Filter for Rectified Datasets", 716 "impl_id": "resources.coverages.filters.RectifiedDatasetTimeSlice", 717 "registry_values": { 718 "core.filters.res_class_id": "resources.coverages.wrappers.RectifiedDatasetWrapper", 719 "core.filters.expr_class_id": "resources.coverages.filters.TimeSliceExpression" 720 } 721 }
722 723 RectifiedDatasetTimeSliceFilterImplementation = \ 724 FilterInterface.implement(RectifiedDatasetTimeSliceFilter)
725 726 -class ReferenceableDatasetTimeSliceFilter(TimeSliceFilter):
727 """ 728 Filter which matches Referenceable Datasets whose acquisition time 729 interval contains a given timestamp. 730 """ 731 REGISTRY_CONF = { 732 "name": "Time Slice Filter for Referenceable Datasets", 733 "impl_id": "resources.coverages.filters.ReferenceableDatasetTimeSlice", 734 "registry_values": { 735 "core.filters.res_class_id": "resources.coverages.wrappers.ReferenceableDatasetWrapper", 736 "core.filters.expr_class_id": "resources.coverages.filters.TimeSliceExpression" 737 } 738 }
739 740 ReferenceableDatasetTimeSliceFilterImplementation = \ 741 FilterInterface.implement(ReferenceableDatasetTimeSliceFilter)
742 743 -class RectifiedStitchedMosaicTimeSliceFilter(TimeSliceFilter):
744 """ 745 Filter which matches Rectified Stitched Mosaics whose acquisition 746 time interval contains a given timestamp. 747 """ 748 REGISTRY_CONF = { 749 "name": "Time Slice Filter for Rectified Stitched Mosaics", 750 "impl_id": "resources.coverages.filters.RectifiedStitchedMosaicTimeSlice", 751 "registry_values": { 752 "core.filters.res_class_id": "resources.coverages.wrappers.RectifiedStitchedMosaicWrapper", 753 "core.filters.expr_class_id": "resources.coverages.filters.TimeSliceExpression" 754 } 755 }
756 757 RectifiedStitchedMosaicTimeSliceFilterImplementation = \ 758 FilterInterface.implement(RectifiedStitchedMosaicTimeSliceFilter)
759 760 -class IntersectingTimeIntervalFilter(object):
761 """ 762 Filter class for 'time_intersects' operations. 763 """
764 - def applyToQuerySet(self, expr, qs):
765 begin = expr.getOperands()[0].begin 766 end = expr.getOperands()[0].end 767 768 if begin == "unbounded": 769 if end == "unbounded": 770 return qs 771 else: 772 return qs.filter( 773 eo_metadata__timestamp_begin__lte=end 774 ) 775 else: 776 if end == "unbounded": 777 return qs.filter( 778 eo_metadata__timestamp_end__gte=begin 779 ) 780 else: 781 return qs.exclude( 782 eo_metadata__timestamp_begin__gt=end 783 ).exclude( 784 eo_metadata__timestamp_end__lt=begin 785 )
786
787 - def resourceMatches(self, expr, res):
788 begin = expr.getOperands()[0].begin 789 end = expr.getOperands()[0].end 790 791 res_begin = res.getBeginTime() 792 res_end = res.getEndTime() 793 794 if res_begin.tzinfo is None and begin.tzinfo is not None: 795 res_begin = res_begin.replace(tzinfo=UTCOffsetTimeZoneInfo()) 796 if res_end.tzinfo is None and end.tzinfo is not None: 797 res_end = res_end.replace(tzinfo=UTCOffsetTimeZoneInfo()) 798 799 return not end < res_begin and \ 800 not res_end < begin
801
802 -class RectifiedDatasetIntersectingTimeIntervalFilter(IntersectingTimeIntervalFilter):
803 """ 804 Filter which matches Rectified Datasets whose acquisition time 805 interval intersects a given time interval. 806 """ 807 REGISTRY_CONF = { 808 "name": "Filter for 'time_intersects' operations on Rectified Datasets", 809 "impl_id": "resources.coverages.filters.RectifiedDatasetIntersectingTimeInterval", 810 "registry_values": { 811 "core.filters.res_class_id": "resources.coverages.wrappers.RectifiedDatasetWrapper", 812 "core.filters.expr_class_id": "resources.coverages.filters.IntersectingTimeIntervalExpression" 813 } 814 }
815 816 RectifiedDatasetIntersectingTimeIntervalFilterImplementation = \ 817 FilterInterface.implement(RectifiedDatasetIntersectingTimeIntervalFilter)
818 819 -class ReferenceableDatasetIntersectingTimeIntervalFilter(IntersectingTimeIntervalFilter):
820 """ 821 Filter which matches Referenceable Datasets whose acquisition time 822 interval intersects a given time interval. 823 """ 824 REGISTRY_CONF = { 825 "name": "Filter for 'time_intersects' operations on Referenceable Datasets", 826 "impl_id": "resources.coverages.filters.ReferenceableDatasetIntersectingTimeInterval", 827 "registry_values": { 828 "core.filters.res_class_id": "resources.coverages.wrappers.ReferenceableDatasetWrapper", 829 "core.filters.expr_class_id": "resources.coverages.filters.IntersectingTimeIntervalExpression" 830 } 831 }
832 833 ReferenceableDatasetIntersectingTimeIntervalFilterImplementation = \ 834 FilterInterface.implement(ReferenceableDatasetIntersectingTimeIntervalFilter)
835 836 -class RectifiedStitchedMosaicIntersectingTimeIntervalFilter(IntersectingTimeIntervalFilter):
837 """ 838 Filter which matches Rectified Stitched Mosaics whose acquisition 839 time interval intersects a given time interval. 840 """ 841 REGISTRY_CONF = { 842 "name": "Filter for 'time_intersects' operations on Rectified Stitched Mosaics", 843 "impl_id": "resources.coverages.filters.RectifiedStitchedMosaicIntersectingTimeInterval", 844 "registry_values": { 845 "core.filters.res_class_id": "resources.coverages.wrappers.RectifiedStitchedMosaicWrapper", 846 "core.filters.expr_class_id": "resources.coverages.filters.IntersectingTimeIntervalExpression" 847 } 848 }
849 850 RectifiedStitchedMosaicIntersectingTimeIntervalFilterImplementation = \ 851 FilterInterface.implement(RectifiedStitchedMosaicIntersectingTimeIntervalFilter)
852 853 -class ContainingTimeIntervalFilter(object):
854 """ 855 Filter class for 'time_within' operations. 856 """
857 - def applyToQuerySet(self, expr, qs):
858 begin = expr.getOperands()[0].begin 859 end = expr.getOperands()[0].end 860 861 if begin == "unbounded": 862 if end == "unbounded": 863 return qs 864 else: 865 return qs.filter( 866 eo_metadata__timestamp_end__lte=end 867 ) 868 else: 869 if end == "unbounded": 870 return qs.filter( 871 eo_metadata__timestamp_begin__gte=begin 872 ) 873 else: 874 return qs.filter( 875 eo_metadata__timestamp_begin__gte=begin, 876 eo_metadata__timestamp_end__lte=end 877 )
878
879 - def resourceMatches(self, expr, res):
880 begin = expr.getOperands()[0].begin 881 end = expr.getOperands()[0].end 882 883 return not res.getBeginTime() < begin and\ 884 not end < res.getEndTime()
885
886 -class RectifiedDatasetContainingTimeIntervalFilter(ContainingTimeIntervalFilter):
887 """ 888 Filter which matches Rectified Datasets whose acquisition time 889 interval is contained within a given time interval. 890 """ 891 REGISTRY_CONF = { 892 "name": "Filter for 'time_within' operations on Rectified Datasets", 893 "impl_id": "resources.coverages.filters.RectifiedDatasetContainingTimeInterval", 894 "registry_values": { 895 "core.filters.res_class_id": "resources.coverages.wrappers.RectifiedDatasetWrapper", 896 "core.filters.expr_class_id": "resources.coverages.filters.ContainingTimeIntervalExpression" 897 } 898 }
899 900 RectifiedDatasetContainingTimeIntervalFilterImplementation = \ 901 FilterInterface.implement(RectifiedDatasetContainingTimeIntervalFilter)
902 903 -class ReferenceableDatasetContainingTimeIntervalFilter(ContainingTimeIntervalFilter):
904 """ 905 Filter which matches Referenceable Datasets whose acquisition time 906 interval is contained within a given time interval. 907 """ 908 REGISTRY_CONF = { 909 "name": "Filter for 'time_within' operations on Referenceable Datasets", 910 "impl_id": "resources.coverages.filters.ReferenceableDatasetContainingTimeInterval", 911 "registry_values": { 912 "core.filters.res_class_id": "resources.coverages.wrappers.ReferenceableDatasetWrapper", 913 "core.filters.expr_class_id": "resources.coverages.filters.ContainingTimeIntervalExpression" 914 } 915 }
916 917 ReferenceableDatasetContainingTimeIntervalFilterImplementation = \ 918 FilterInterface.implement(ReferenceableDatasetContainingTimeIntervalFilter)
919 920 -class RectifiedStitchedMosaicContainingTimeIntervalFilter(ContainingTimeIntervalFilter):
921 """ 922 Filter which matches Rectified Stitched Mosaics whose acquisition 923 time interval is contained within a given time interval. 924 """ 925 REGISTRY_CONF = { 926 "name": "Filter for 'time_within' operations on Rectified Stitched Mosaics", 927 "impl_id": "resources.coverages.filters.RectifiedStitchedMosaicContainingTimeInterval", 928 "registry_values": { 929 "core.filters.res_class_id": "resources.coverages.wrappers.RectifiedStitchedMosaicWrapper", 930 "core.filters.expr_class_id": "resources.coverages.filters.ContainingTimeIntervalExpression" 931 } 932 }
933 934 RectifiedStitchedMosaicContainingTimeIntervalFilterImplementation = \ 935 FilterInterface.implement(RectifiedStitchedMosaicContainingTimeIntervalFilter)
936 937 -class SpatialFilter(object):
938 """ 939 Common base class for spatial filters. 940 """ 941
942 - def _getSRS(self, crs_id):
943 if crs_id == "imageCRS": 944 raise InvalidExpressionError( 945 "Cannot use geospatial filters with pixel coordinates." 946 ) 947 948 try: 949 srs = SpatialReference(crs_id) 950 except Exception, e: 951 raise InvalidExpressionError( 952 "Unknown SRID %d." % crs_id 953 ) 954 955 return srs
956
957 - def _getCRSBounds(self, crs_id):
958 srs = self._getSRS(crs_id) 959 960 if srs.geographic: 961 return (-180.0, -90.0, 180.0, 90.0) 962 else: 963 earth_circumference = 2*math.pi*srs.semi_major 964 965 return ( 966 -earth_circumference, 967 -earth_circumference, 968 earth_circumference, 969 earth_circumference 970 )
971
972 - def _getCRSTolerance(self, crs_id):
973 srs = self._getSRS(crs_id) 974 975 if srs.geographic: 976 return 1e-8 977 else: 978 return 1e-2
979
980 -class SpatialSliceFilter(SpatialFilter):
981 """ 982 Common base class for spatial slice filters. 983 """ 984
985 - def _getLine(self, slice, max_extent):
986 #_max_extent = self._transformMaxExtent(slice.crs_id, max_extent) 987 _max_extent = self._getCRSBounds(slice.crs_id) 988 989 if slice.axis_label.lower() in ("x", "lon", "long"): 990 line = Line( 991 (slice.slice_point, _max_extent[1]), 992 (slice.slice_point, _max_extent[3]) 993 ) 994 elif slice.axis_label.lower() in ("y", "lat"): 995 line = Line( 996 (_max_extent[0], slice.slice_point), 997 (_max_extent[2], slice.slice_point) 998 ) 999 else: 1000 raise InvalidExpressionError( 1001 "Unknown axis label '%s'." % slice.axis_label 1002 ) 1003 1004 line.srid = slice.crs_id 1005 1006 if slice.crs_id != 4326: 1007 line.transform(4326) 1008 1009 return line
1010
1011 - def applyToQuerySet(self, expr, qs):
1012 slice = expr.getOperands()[0] 1013 1014 line = self._getLine(slice) 1015 1016 # NOTE: this is a hack to account for bugs in GeoDjango 1017 # Should be: 1018 # return qs.filter(eo_metadata__footprint__intersects=line) 1019 1020 eoqs = EOMetadataRecord.objects.filter( 1021 footprint__intersects=line 1022 ) 1023 1024 return qs.filter( 1025 eo_metadata__in=tuple(eoqs.values_list("pk", flat=True)) 1026 )
1027 1028 # End of hack 1029
1030 - def resourceMatches(self, expr, res):
1031 slice = expr.getOperands()[0] 1032 1033 footprint = res.getFootprint() 1034 1035 line = self._getLine(slice) 1036 1037 return footprint.intersects(line)
1038
1039 -class RectifiedDatasetSpatialSliceFilter(SpatialSliceFilter):
1040 """ 1041 Filter which matches Rectified Datasets whose footprint intersects 1042 a given spatial slice. 1043 """ 1044 REGISTRY_CONF = { 1045 "name": "Spatial Slice Filter for Rectified Datasets", 1046 "impl_id": "resources.coverages.filters.RectifiedDatasetSpatialSlice", 1047 "registry_values": { 1048 "core.filters.res_class_id": "resources.coverages.wrappers.RectifiedDatasetWrapper", 1049 "core.filters.expr_class_id": "resources.coverages.filters.SpatialSliceExpression" 1050 } 1051 } 1052
1053 - def _getRelationName(self):
1054 return "rectifieddatasetrecord_set"
1055 1056 RectifiedDatasetSpatialSliceFilterImplementation = \ 1057 FilterInterface.implement(RectifiedDatasetSpatialSliceFilter)
1058 1059 -class ReferenceableDatasetSpatialSliceFilter(SpatialSliceFilter):
1060 """ 1061 Filter which matches Referenceable Datasets whose footprint 1062 intersects a given spatial slice. 1063 """ 1064 REGISTRY_CONF = { 1065 "name": "Spatial Slice Filter for Referenceable Datasets", 1066 "impl_id": "resources.coverages.filters.ReferenceableDatasetSpatialSlice", 1067 "registry_values": { 1068 "core.filters.res_class_id": "resources.coverages.wrappers.ReferenceableDatasetWrapper", 1069 "core.filters.expr_class_id": "resources.coverages.filters.SpatialSliceExpression" 1070 } 1071 } 1072
1073 - def _getRelationName(self):
1074 return "referenceabledatasetrecord_set"
1075 1076 1077 ReferenceableDatasetSpatialSliceFilterImplementation = \ 1078 FilterInterface.implement(ReferenceableDatasetSpatialSliceFilter)
1079 1080 -class RectifiedStitchedMosaicSpatialSliceFilter(SpatialSliceFilter):
1081 """ 1082 Filter which matches Rectified Stitched Mosaics whose footprint 1083 intersects a given spatial slice. 1084 """ 1085 1086 REGISTRY_CONF = { 1087 "name": "Spatial Slice Filter for Rectified Stitched Mosaics", 1088 "impl_id": "resources.coverages.filters.RectifiedStitchedMosaicSpatialSlice", 1089 "registry_values": { 1090 "core.filters.res_class_id": "resources.coverages.wrappers.RectifiedStitchedMosaicWrapper", 1091 "core.filters.expr_class_id": "resources.coverages.filters.SpatialSliceExpression" 1092 } 1093 } 1094
1095 - def _getRelationName(self):
1096 return "rectifiedstitchedmosaicrecord_set"
1097
1098 - def _getSizeField(self, axis_label):
1099 if axis_label in ("x", "lon", "long", "Long"): 1100 return "extent__size_x" 1101 else: 1102 return "extent__size_y"
1103 1104 1105 RectifiedStitchedMosaicSpatialSliceFilterImplementation = \ 1106 FilterInterface.implement(RectifiedStitchedMosaicSpatialSliceFilter)
1107 1108 1109 -class FootprintFilter(SpatialFilter):
1110 """ 1111 Common base class for footprint-related filters. 1112 """
1113 - def _getPolygon(self, bounded_area):
1114 #_max_extent = self._transformMaxExtent( 1115 # bounded_area.crs_id, max_extent 1116 #) 1117 1118 _max_extent = self._getCRSBounds(bounded_area.crs_id) 1119 1120 if bounded_area.minx == "unbounded": 1121 minx = _max_extent[0] 1122 else: 1123 minx = max(bounded_area.minx, _max_extent[0]) 1124 1125 if bounded_area.miny == "unbounded": 1126 miny = _max_extent[1] 1127 else: 1128 miny = max(bounded_area.miny, _max_extent[1]) 1129 1130 if bounded_area.maxx == "unbounded": 1131 maxx = _max_extent[2] 1132 else: 1133 maxx = min(bounded_area.maxx, _max_extent[2]) 1134 1135 if bounded_area.maxy == "unbounded": 1136 maxy = _max_extent[3] 1137 else: 1138 maxy = min(bounded_area.maxy, _max_extent[3]) 1139 1140 # add a tolerance to the extent to account for string conversion and 1141 # rounding errors 1142 e = self._getCRSTolerance(bounded_area.crs_id) 1143 minx -= e; miny -= e; maxx += e; maxy += e 1144 1145 poly = Polygon.from_bbox((minx, miny, maxx, maxy)) 1146 poly.srid = bounded_area.crs_id 1147 1148 if bounded_area.crs_id != 4326: 1149 # reproject to WGS 84 1150 poly.transform(4326) 1151 1152 return poly
1153
1154 -class FootprintIntersectsAreaFilter(FootprintFilter):
1155 """ 1156 Base filter class matching EO Coverages whose footprint intersects a 1157 given area. 1158 """
1159 - def applyToQuerySet(self, expr, qs):
1160 #max_extent = self._getMaxExtent(qs) 1161 1162 poly = self._getPolygon(expr.getOperands()[0]) 1163 1164 # NOTE: this is a hack to account for bugs in GeoDjango 1165 # Should be: 1166 #return qs.filter(eo_metadata__footprint__intersects=poly) 1167 1168 eoqs = EOMetadataRecord.objects.filter( 1169 footprint__intersects=poly 1170 ) 1171 1172 return qs.filter( 1173 eo_metadata__in=tuple(eoqs.values_list("pk", flat=True)) 1174 )
1175 1176 # End of hack 1177
1178 - def resourceMatches(self, expr, res):
1179 footprint = res.getFootprint() 1180 1181 poly = self._getPolygon(expr.getOperands()[0]) 1182 1183 return footprint.intersects(poly)
1184
1185 -class FootprintWithinAreaFilter(FootprintFilter):
1186 """ 1187 Filter matching EO Coverages whose footprint lies within a given 1188 area. 1189 """ 1190
1191 - def applyToQuerySet(self, expr, qs):
1192 poly = self._getPolygon(expr.getOperands()[0]) 1193 1194 # NOTE: this is a hack to account for bugs in GeoDjango 1195 # Should be: 1196 # return qs.filter(eo_metadata__footprint__within=poly) 1197 1198 eoqs = EOMetadataRecord.objects.filter(footprint__within=poly) 1199 1200 return qs.filter( 1201 eo_metadata__in=tuple(eoqs.values_list("pk", flat=True)) 1202 )
1203 1204 # End of hack 1205
1206 - def resourceMatches(self, expr, res):
1207 footprint = res.getFootprint() 1208 1209 poly = self._getPolygon(expr.getOperands()[0]) 1210 1211 return footprint.within(poly)
1212
1213 -class RectifiedDatasetFootprintIntersectsAreaFilter(FootprintIntersectsAreaFilter):
1214 """ 1215 Filter which matches Rectified Datasets whose footprint intersects 1216 a given bounded area. 1217 """ 1218 REGISTRY_CONF = { 1219 "name": "Footprint intersects area Filter for Rectified Datasets", 1220 "impl_id": "resources.coverages.filters.RectifiedDatasetFootprintIntersectsArea", 1221 "registry_values": { 1222 "core.filters.res_class_id": "resources.coverages.wrappers.RectifiedDatasetWrapper", 1223 "core.filters.expr_class_id": "resources.coverages.filters.FootprintIntersectsAreaExpression" 1224 } 1225 } 1226
1227 - def _getRelationName(self):
1228 return "rectifieddatasetrecord_set"
1229 1230 RectifiedDatasetFootprintIntersectsAreaFilterImplementation = \ 1231 FilterInterface.implement(RectifiedDatasetFootprintIntersectsAreaFilter)
1232 1233 1234 -class RectifiedDatasetFootprintWithinAreaFilter(FootprintWithinAreaFilter):
1235 """ 1236 Filter which matches Rectified Datasets whose footprint is 1237 contained within a given bounded area. 1238 """ 1239 REGISTRY_CONF = { 1240 "name": "Footprint within area Filter for Rectified Datasets", 1241 "impl_id": "resources.coverages.filters.RectifiedDatasetFootprintWithinArea", 1242 "registry_values": { 1243 "core.filters.res_class_id": "resources.coverages.wrappers.RectifiedDatasetWrapper", 1244 "core.filters.expr_class_id": "resources.coverages.filters.FootprintWithinAreaExpression" 1245 } 1246 } 1247
1248 - def _getRelationName(self):
1249 return "rectifieddatasetrecord_set"
1250 1251 RectifiedDatasetFootprintWithinAreaFilterImplementation = \ 1252 FilterInterface.implement(RectifiedDatasetFootprintWithinAreaFilter)
1253 1254 -class ReferenceableDatasetFootprintIntersectsAreaFilter(FootprintIntersectsAreaFilter):
1255 """ 1256 Filter which matches Referenceable Datasets whose footprint 1257 intersects a given bounded area. 1258 """ 1259 REGISTRY_CONF = { 1260 "name": "Footprint intersects area Filter for Referenceable Datasets", 1261 "impl_id": "resources.coverages.filters.ReferenceableDatasetFootprintIntersectsArea", 1262 "registry_values": { 1263 "core.filters.res_class_id": "resources.coverages.wrappers.ReferenceableDatasetWrapper", 1264 "core.filters.expr_class_id": "resources.coverages.filters.FootprintIntersectsAreaExpression" 1265 } 1266 } 1267
1268 - def _getRelationName(self):
1269 return "referenceabledatasetrecord_set"
1270 1271 ReferenceableDatasetFootprintIntersectsAreaFilterImplementation = \ 1272 FilterInterface.implement(ReferenceableDatasetFootprintIntersectsAreaFilter)
1273 1274 -class ReferenceableDatasetFootprintWithinAreaFilter(FootprintWithinAreaFilter):
1275 """ 1276 Filter which matches Referenceable Datasets whose footprint is 1277 contained within a given bounded area. 1278 """ 1279 REGISTRY_CONF = { 1280 "name": "Footprint intersects area Filter for Rectified Datasets", 1281 "impl_id": "resources.coverages.filters.ReferenceableDatasetFootprintWithinArea", 1282 "registry_values": { 1283 "core.filters.res_class_id": "resources.coverages.wrappers.ReferenceableDatasetWrapper", 1284 "core.filters.expr_class_id": "resources.coverages.filters.FootprintWithinAreaExpression" 1285 } 1286 } 1287
1288 - def _getRelationName(self):
1289 return "referenceabledatasetrecord_set"
1290 1291 ReferenceableDatasetFootprintWithinAreaFilterImplementation = \ 1292 FilterInterface.implement(ReferenceableDatasetFootprintWithinAreaFilter)
1293 1294 -class RectifiedStitchedMosaicFootprintIntersectsAreaFilter(FootprintIntersectsAreaFilter):
1295 """ 1296 Filter which matches Rectified Stitched Mosaics whose footprint 1297 intersects a given bounded area. 1298 """ 1299 REGISTRY_CONF = { 1300 "name": "Footprint intersects area Filter for Rectified StitchedMosaics", 1301 "impl_id": "resources.coverages.filters.RectifiedStitchedMosaicFootprintIntersectsArea", 1302 "registry_values": { 1303 "core.filters.res_class_id": "resources.coverages.wrappers.RectifiedStitchedMosaicWrapper", 1304 "core.filters.expr_class_id": "resources.coverages.filters.FootprintIntersectsAreaExpression" 1305 } 1306 } 1307
1308 - def _getRelationName(self):
1309 return "rectifiedstitchedmosaicrecord_set"
1310 1311 RectifiedStitchedMosaicFootprintIntersectsAreaFilterImplementation = \ 1312 FilterInterface.implement(RectifiedStitchedMosaicFootprintIntersectsAreaFilter)
1313 1314 1315 -class RectifiedStitchedMosaicFootprintWithinAreaFilter(FootprintWithinAreaFilter):
1316 """ 1317 Filter which matches Rectified Stiched Mosaics whose footprint is 1318 contained within given bounded area. 1319 """ 1320 REGISTRY_CONF = { 1321 "name": "Footprint within area Filter for Rectified StitchedMosaics", 1322 "impl_id": "resources.coverages.filters.RectifiedStitchedMosaicFootprintWithinArea", 1323 "registry_values": { 1324 "core.filters.res_class_id": "resources.coverages.wrappers.RectifiedStitchedMosaicWrapper", 1325 "core.filters.expr_class_id": "resources.coverages.filters.FootprintWithinAreaExpression" 1326 } 1327 } 1328
1329 - def _getRelationName(self):
1330 return "rectifiedstitchedmosaicrecord_set"
1331 1332 RectifiedStitchedMosaicFootprintWithinAreaFilterImplementation = \ 1333 FilterInterface.implement(RectifiedStitchedMosaicFootprintWithinAreaFilter)
1334 1335 -class ContainedRectifiedDatasetFilter(object):
1336 """ 1337 Filter which matches RectifiedDatasets contained in a given 1338 RectifiedStitchedMosaic or Dataset series. 1339 """ 1340 REGISTRY_CONF = { 1341 "name": "Contained Rectified Dataset Filter", 1342 "impl_id": "resources.coverages.filters.ContainedRectifiedDataset", 1343 "registry_values": { 1344 "core.filters.res_class_id": "resources.coverages.wrappers.RectifiedDatasetWrapper", 1345 "core.filters.expr_class_id": "resources.coverages.filters.ContainedCoverageExpression" 1346 } 1347 } 1348
1349 - def applyToQuerySet(self, expr, qs):
1350 container_id = expr.getOperands()[0] 1351 1352 return qs.filter( 1353 Q(rect_stitched_mosaics__pk=container_id) | \ 1354 Q(dataset_series_set__pk=container_id) 1355 )
1356
1357 - def resourceMatches(self, expr, res):
1358 container_id = expr.getOperands()[0] 1359 1360 return res.containedIn(container_id)
1361 1362 ContainedRectifiedDatasetFilterImplementation = \ 1363 FilterInterface.implement(ContainedRectifiedDatasetFilter)
1364 1365 -class ContainedReferenceableDatasetFilter(object):
1366 """ 1367 Filter which matches ReferenceableDatasets contained in a given 1368 DatasetSeries. 1369 """ 1370 REGISTRY_CONF = { 1371 "name": "Contained Referenceable Dataset Filter", 1372 "impl_id": "resources.coverages.filters.ContainedReferenceableDatasetFilter", 1373 "registry_values": { 1374 "core.filters.res_class_id": "resources.coverages.wrappers.ReferenceableDatasetWrapper", 1375 "core.filters.expr_class_id": "resources.coverages.filters.ContainedCoverageExpression" 1376 } 1377 } 1378
1379 - def applyToQuerySet(self, expr, qs):
1380 container_id = expr.getOperands()[0] 1381 1382 return qs.filter(dataset_series_set__pk=container_id)
1383
1384 - def resourceMatches(self, expr, res):
1385 container_id = expr.getOperands()[0] 1386 1387 return res.containedIn(container_id)
1388 1389 ContainedReferenceableDatasetFilterImplementation = \ 1390 FilterInterface.implement(ContainedReferenceableDatasetFilter)
1391 1392 -class ContainedRectifiedStitchedMosaicFilter(object):
1393 """ 1394 Filter which matches RectifiedStitchedMosaics contained in a given 1395 DatasetSeries. 1396 """ 1397 REGISTRY_CONF = { 1398 "name": "Contained Referenceable Dataset Filter", 1399 "impl_id": "resources.coverages.filters.ContainedRectifiedStitchedMosaicFilter", 1400 "registry_values": { 1401 "core.filters.res_class_id": "resources.coverages.wrappers.RectifiedStitchedMosaicWrapper", 1402 "core.filters.expr_class_id": "resources.coverages.filters.ContainedCoverageExpression" 1403 } 1404 } 1405
1406 - def applyToQuerySet(self, expr, qs):
1407 container_id = expr.getOperands()[0] 1408 1409 return qs.filter(dataset_series_set__pk=container_id)
1410
1411 - def resourceMatches(self, expr, res):
1412 container_id = expr.getOperands()[0] 1413 1414 return res.containedIn(container_id)
1415 1416 ContainedRectifiedStitchedMosaicFilterImplementation = \ 1417 FilterInterface.implement(ContainedRectifiedStitchedMosaicFilter)
1418 1419 -class RectifiedStitchedMosaicContainsFilter(object):
1420 """ 1421 Filter which matches RectifiedStitchedMosaics which contain the 1422 RectifiedDataset with the resource primary key conveyed with the 1423 expression. 1424 """ 1425 1426 REGISTRY_CONF = { 1427 "name": "Filter for 'contains' operations on RectifiedStitchedMosaics", 1428 "impl_id": "resources.coverages.filters.RectifiedStitchedMosaicContains", 1429 "registry_values": { 1430 "core.filters.res_class_id": "resources.coverages.wrappers.RectifiedStitchedMosaicWrapper", 1431 "core.filters.expr_class_id": "resources.coverages.filters.ContainsCoverageExpression" 1432 } 1433 } 1434
1435 - def applyToQuerySet(self, expr, qs):
1436 res_id = expr.getOperands()[0] 1437 1438 return qs.filter(rect_datasets__pk=res_id)
1439
1440 - def resourceMatches(self, expr, res):
1441 res_id = expr.getOperands()[0] 1442 1443 return res.contains(res_id)
1444 1445 RectifiedStitchedMosaicContainsFilterImplementation = \ 1446 FilterInterface.implement(RectifiedStitchedMosaicContainsFilter)
1447 1448 -class DatasetSeriesContainsFilter(object):
1449 """ 1450 Filter which matches DatasetSeries which contain the (Rectified 1451 or Referenceable) Dataset with the resource primary key conveyed 1452 with the expression. 1453 """ 1454 1455