Beispiel #1
0
def _do_boundary_search(search_term):
    """
    Execute full text search against all searchable boundary layers.
    """
    result = []
    query = _get_boundary_search_query(search_term)

    with connection.cursor() as cursor:
        wildcard_term = '%{}%'.format(search_term)
        cursor.execute(query, {'term': wildcard_term})

        wkb_r = WKBReader()

        for row in cursor.fetchall():
            id = row[0]
            code = row[1]
            name = row[2]
            rank = row[3]
            point = wkb_r.read(row[4])

            layer = _get_boundary_layer_by_code(code)

            result.append({
                'id': id,
                'code': code,
                'text': name,
                'label': layer['short_display'],
                'rank': rank,
                'y': point.y,
                'x': point.x,
            })

    return result
Beispiel #2
0
def convert_to_2d(geom):
    """Convert a geometry from 3D to 2D"""
    from django.contrib.gis.geos import WKBWriter, WKBReader
    wkb_r = WKBReader()
    wkb_w = WKBWriter()
    wkb_w.outdim = 2
    return wkb_r.read(wkb_w.write(geom))
Beispiel #3
0
def convert_to_2d(geom):
    """Convert a geometry from 3D to 2D"""
    from django.contrib.gis.geos import WKBWriter, WKBReader
    wkb_r = WKBReader()
    wkb_w = WKBWriter()
    wkb_w.outdim = 2
    return wkb_r.read(wkb_w.write(geom))
Beispiel #4
0
    def test03_wkbreader(self):
        # Creating a WKBReader instance
        wkb_r = WKBReader()

        hex = b'000000000140140000000000004037000000000000'
        wkb = memoryview(binascii.a2b_hex(hex))
        ref = GEOSGeometry(hex)

        # read() should return a GEOSGeometry on either a hex string or
        # a WKB buffer.
        g1 = wkb_r.read(wkb)
        g2 = wkb_r.read(hex)
        for geom in (g1, g2):
            self.assertEqual(ref, geom)

        bad_input = (1, 5.23, None, False)
        for bad_wkb in bad_input:
            self.assertRaises(TypeError, wkb_r.read, bad_wkb)
Beispiel #5
0
    def test03_wkbreader(self):
        # Creating a WKBReader instance
        wkb_r = WKBReader()

        hex = b'000000000140140000000000004037000000000000'
        wkb = memoryview(binascii.a2b_hex(hex))
        ref = GEOSGeometry(hex)

        # read() should return a GEOSGeometry on either a hex string or
        # a WKB buffer.
        g1 = wkb_r.read(wkb)
        g2 = wkb_r.read(hex)
        for geom in (g1, g2):
            self.assertEqual(ref, geom)

        bad_input = (1, 5.23, None, False)
        for bad_wkb in bad_input:
            self.assertRaises(TypeError, wkb_r.read, bad_wkb)
Beispiel #6
0
def crossovers(models,path_id,loc_id):
    
    # SET THE SEARCH OFFSET
    search_offset = 50
    
    # FIND CROSSOVERS (NON SELF-INSERSECTING)
    try:
        
        # GET LINE PATH
        line_pathz = models.segments.objects.filter(segment_id=path_id).values_list('line_path', flat=True)
        
        #line path w/out z values
        line_path = line_pathz.extra(select={'line_path':'ST_Force_2D(line_path)'}).values_list('line_path',flat=True)
        
        #Get all other line paths with z values.
        other_linesz = models.segments.objects.exclude(segment_id=path_id).filter(line_path__intersects=line_path[0])
        
        #Get all other line paths w/out z values
        other_lines = other_linesz.extra(select={'line_path':'ST_Force_2D(line_path)'}).values_list('line_path','segment_id')
      
        #Create a GEOS Well Known Binary reader and set up variables                            
        wkb_r = WKBReader()
        points1 = []
        line_ids = []
      
        #Find points of intersection w/ interpolated z values for given line
        # path
        for line in other_lines:
            l = wkb_r.read(line[0])
            crosses = l.intersection(line_pathz[0])
            if crosses.geom_type == 'MultiPoint':
                for pt in crosses:
                    points1.append(pt)
                    line_ids.append(line[1])
            else:
                points1.append(crosses)
                line_ids.append(line[1])
   
        #Find points of intersection w/ interpolated z values for other line
        #  paths
        points2 = other_linesz.intersection(line_path[0]).values_list('intersection',flat=True)
      
        #EXTRACT x/y coordinates of intersections and gps_time1/2
        x=[]
        y=[]
        gps_time1 = []
        gps_time2 = []
        #Check all point objects for multiple crossovers and extract x/y coords
        # and gps times
        for po in points1:
            if po.geom_type == 'MultiPoint':
                for p in po:
                    x.append(p[0])
                    y.append(p[1])
                    gps_time1.append(p[2])
            else:
                x.append(po[0])
                y.append(po[1])
                gps_time1.append(po[2])
        for po in points2:
            if po.geom_type == 'MultiPoint':
                for p in po:
                    gps_time2.append(p[2])
            else:
                gps_time2.append(po[2])
      
        #Create point objects for all crossover points
        cross_pts = [Point(point) for point in zip(x,y)]
      
    except:
        return error_check(sys)
   
    #Find all non-self-intersecting Crossover angles:
    try:
        #Get the lines associated w/ crossover points
        lines = models.segments.objects.filter(segment_id__in=list(set(line_ids))).values_list('line_path','segment_id')
        line_dict = {}
        for line in lines:
            line_dict[line[1]] = line[0]
   
        #Enumerate over line_ids in order to query for the nearest point paths to each cross point.
        angles = []
        for idx,pt_id in enumerate(line_ids):
            try:
                #Get the nearest point paths for the other line to the crossover
                # point and sort them by point_path_id
                line_pts = models.point_paths.objects.filter(segment_id=pt_id, gps_time__range=(repr(gps_time2[idx]-search_offset),repr(gps_time2[idx]+search_offset))).distance(cross_pts[idx]).order_by('distance','gps_time').values_list('point_path','point_path_id','gps_time', 'distance')
                line_pts = sorted(line_pts,key=lambda l_id: l_id[1])
                #Find the two points adjacent to the cross point. Use time_diff to ensure they are
                # the closest two points.

                time_diff = None
                for pt_idx in range(len(line_pts) - 1):
                    if float(line_pts[pt_idx][2]) <  gps_time2[idx] and float(line_pts[pt_idx+1][2]) > gps_time2[idx]:
                        if time_diff is None:
                            time_diff = float(line_pts[pt_idx+1][2])-float(line_pts[pt_idx][2])
                            change_x1 = line_pts[pt_idx][0].coords[0]-line_pts[pt_idx+1][0].coords[0]
                            change_y1 = line_pts[pt_idx][0].coords[1]-line_pts[pt_idx+1][0].coords[1]
                        elif float(line_pts[pt_idx+1][2])-float(line_pts[pt_idx][2]) < time_diff:
                            time_diff = float(line_pts[pt_idx+1][2])-float(line_pts[pt_idx][2])
                            change_x1 = line_pts[pt_idx][0].coords[0]-line_pts[pt_idx+1][0].coords[0]
                            change_y1 = line_pts[pt_idx][0].coords[1]-line_pts[pt_idx+1][0].coords[1]

                #Get the nearest point paths for the given line to the crossover
                # point and sort them by point_path_id.
                line_pts = models.point_paths.objects.filter(segment_id=path_id, gps_time__range=(repr(gps_time1[idx]-search_offset),repr(gps_time1[idx]+search_offset))).distance(cross_pts[idx]).order_by('distance','gps_time').values_list('point_path','point_path_id','gps_time','distance')
                line_pts = sorted(line_pts,key=lambda l_id: l_id[1])
                time_diff = None
                for pt_idx in range(len(line_pts) - 1):
                    if float(line_pts[pt_idx][2]) <  gps_time1[idx] and float(line_pts[pt_idx+1][2]) > gps_time1[idx]:
                        if time_diff is None:
                            time_diff = float(line_pts[pt_idx+1][2])-float(line_pts[pt_idx][2])
                            change_x2 = line_pts[pt_idx][0].coords[0]-line_pts[pt_idx+1][0].coords[0]
                            change_y2 = line_pts[pt_idx][0].coords[1]-line_pts[pt_idx+1][0].coords[1]
                        elif float(line_pts[pt_idx+1][2])-float(line_pts[pt_idx][2]) < time_diff:
                            time_diff = float(line_pts[pt_idx+1][2])-float(line_pts[pt_idx][2])
                            change_x2 = line_pts[pt_idx][0].coords[0]-line_pts[pt_idx+1][0].coords[0]
                            change_y2 = line_pts[pt_idx][0].coords[1]-line_pts[pt_idx+1][0].coords[1]  
             
            except:
                return error_check(sys)  
          
            #Check if either of the lines is parallel to the y-axis and find
            # the angle of intersection.
            if change_x1 == 0 and change_x2 == 0:
                angle = 180
            elif change_x1 == 0:
                angle = degrees(atan(fabs(1/(change_y2/change_x2))))
            elif change_x2 == 0:
                angle = degrees(atan(fabs(1/(change_y1/change_x1))))
            else:
                slope1 = change_y1/change_x1
                slope2 = change_y2/change_x2
                if slope1*slope2 == -1:
                    angle = 90
                else:
                    angle = degrees(atan(fabs((slope1 - slope2)/(1 + slope1 * slope2))))
          
            #Save all the angles for later
            angles.append(angle)
    except:
        return error_check(sys)
   
    #FIND all self-intersecting crossovers
    try:
        #Fetch the given line path from the db as a multilinestring.
        # 'ST_UnaryUnion' results in a multilinestring with the last point of
        # every linestring except the last linestring is a crossover and the
        # first point of every linestring except the first linestring is a
        # crossover.
        line = models.segments.objects.filter(segment_id=path_id).extra(select={'multi_line_path':'ST_UnaryUnion(line_path)'}
                                                ).values_list('multi_line_path', flat=True)
      
        #Create a GEOS MultiLineString from the multilinestring fetched above.
        lines = wkb_r.read(line[0])
        #Check if resulting object is a multilinestring, indicating crossovers.
        if lines.geom_type.encode('ascii', 'ignore') == 'MultiLineString':
            self_cross = True
            #Loop through all linestrings created by ST_UnaryUnion to get crossover
            # points and interpolate GPS times.
            crossover_gps = {}
            crossover_slopes = {}
            for idx in range(len(lines) - 1):  
                #Check if current linestring is composed only of crossovers.
                if len(lines[idx].coords) ==2 and idx != 0:
                    #Fall back on the next linestring not made exclusively of
                    # crossovers in order to get a good GPS time.
                    idx1 = idx-1
                    while idx1 >= 0:
                        if idx1 == 0 or len(lines[idx1].coords) > 2:
                        
                            #Check if next linestring is made only of crossovers
                            # in order to obtain the next linestring w/ good GPS
                            # time.
                            if len(lines[idx+1].coords) == 2 and idx+1 != len(lines)-1:
                                idx2 = idx+2
                                while idx2 < len(lines):
                                    if idx2 == len(lines)-1 or len(lines[idx2].coords) > 2:
                                        point1 = Point(lines[idx1].coords[-2])
                                        point2 = Point(lines[idx2].coords[1])
                                        #Break while loop
                                        break
                                    else:
                                        idx2 += 1
                            else:
                                point1 = Point(lines[idx1].coords[-2])
                                point2 = Point(lines[idx+1].coords[1])
                            #Break while loop
                            break        
                        else:
                            idx1 = idx1 - 1
                #If current linestring is not made exclusively of crossovers, check
                # if next one is.
                elif len(lines[idx+1].coords) == 2 and idx+1 != len(lines)-1:
                    idx2 = idx+2
                    while idx2 < len(lines):
                        if idx2 == len(lines)-1 or len(lines[idx2].coords) > 2:
                            point1 = Point(lines[idx].coords[-2])
                            point2 = Point(lines[idx2].coords[1])
                            #break loop
                            break
                        else:
                            idx2 += 1
                else:
                    point1 = Point(lines[idx].coords[-2])
                    point2 = Point(lines[idx+1].coords[1])
               
                #Find the change in x/y in order to determine slope
                change_x = point1[0] - point2[0]
                change_y = point1[1] - point2[1]
              
                #Check if the change in x is zero
                if change_x == 0:
                    slope = None
                else:
                    slope = change_y/change_x
              
                #Create a new line object from the two points adjacent to the
                # crossover.
                newline = LineString(point1,point2)
                #Find the crossover point/interpolate the gps time.
                crossover = Point(lines[idx].coords[-1])
                cross_pt = newline.interpolate(newline.project(crossover))
              
                #Use crossover coordinates as keys for a dictionary storing gps
                # times
                if (crossover[0],crossover[1]) not in crossover_gps.keys():
                    crossover_gps[crossover[0],crossover[1]] = [cross_pt[2]]
                else:
                    crossover_gps[crossover[0],crossover[1]].append(cross_pt[2])
              
                #Use crossover coordinates as keys for a dictionary storing slopes
                if (crossover[0],crossover[1]) not in crossover_slopes.keys():
                    crossover_slopes[crossover[0], crossover[1]] = [slope]
                else:
                    crossover_slopes[crossover[0], crossover[1]].append(slope)
              
            #Create a dictionary holding both gps times and slopes.
            crossovers = crossover_gps
            for key in crossover_slopes:
                crossovers[key].append(crossover_slopes[key][0])
                crossovers[key].append(crossover_slopes[key][1])
            del crossover_gps, crossover_slopes
          
            #Extract self-intersecting crossovers information from above.
            self_cross_pts = []
            self_gps1 = []
            self_gps2 = []
            self_angles = []
            for x,y in crossovers:
                self_cross_pts.append(Point(x,y))
                self_gps1.append(crossovers[x,y][0])
                self_gps2.append(crossovers[x,y][1])
                #Determine angle of intersection
                slope1 = crossovers[x,y][2]
                slope2 = crossovers[x,y][3]
                if slope1 == None and slope2 == None:
                    angle = 180
                elif slope1 == None:
                    angle = degrees(atan(fabs(1/slope2)))
                elif slope2 == None:
                    angle = degrees(atan(fabs(1/slope1)))
                else:
                    if slope1*slope2 == -1:
                        angle = 90
                    else:
                        angle = degrees(atan(fabs((slope1 - slope2)/
                                                      (1 + slope1 * slope2))))
                self_angles.append(angle)
        else:
            self_cross = False
    except:
        return error_check(sys)
   
    
    #Format and return crossovers for writing to CSV file:
    try:
        rows = []
        #Non-self-intersecting crossovers
        for idx, pt in enumerate(cross_pts):
            rows.append([path_id,line_ids[idx],repr(gps_time1[idx]), repr(gps_time2[idx]), repr(angles[idx]), repr(pt[0]), repr(pt[1]), loc_id])
        
        if self_cross:
            #Self-intersecting crossovers
            for idx, pt in enumerate(self_cross_pts):
                rows.append([path_id,path_id,repr(self_gps1[idx]),repr(self_gps2[idx]),repr(self_angles[idx]),repr(pt[0]),repr(pt[1]),loc_id])
       
        return rows

    except:
        return error_check(sys)
Beispiel #7
0
def find_items(request):
    bounds_string = request.GET.get("bbox")
    point_string = request.GET.get("coord")
    gazetteer_polygon_id = request.GET.get("polygon")
    osm_id = request.GET.get("osm_id")
    field_string = request.GET.get("return")
    years_string = request.GET.get("years")
    keyword_string = request.GET.get("keyword")
    originator_string = request.GET.get("originator")
    datatype_string = request.GET.get("datatype")
    start = int(request.GET.get("start", 0))
    end = int(request.GET.get("end", 0))
    grouped = request.GET.get("grouped")
    group_id = request.GET.get("id")

    if not (bounds_string or gazetteer_polygon_id or point_string or osm_id) or not field_string:
        errors = []

        if not (bounds_string or gazetteer_polygon_id or point_string or osm_id):
            errors.append("MISSING: osm_id, bbox, polygon, point")
        if not field_string:
            errors.append("MISSING: return")

        return bad_request(errors)

    query = Q()

    if gazetteer_polygon_id:
        query &= Q(bounds__intersects=GeneratedGeometry.objects.get(gazetteer_id=gazetteer_polygon_id).geometry)
    elif osm_id:
        polygon = None

        try:
            polygon = Placex.objects.get(osm_id=osm_id).geometry
        except MultipleObjectsReturned:
            with connections["nominatim"].cursor() as c:
                c.execute('select ST_Collect("placex"."geometry") from "placex" where "placex"."osm_id"=%s', [osm_id])
                polygon = WKBReader().read(c.fetchone()[0])

        query &= Q(bounds__intersects=polygon)
    if point_string:
        (lng, lat) = [float(x) for x in point_string.split(",")]
        point = Point(lat,lng)
    elif bounds_string:
        (minX, minY, maxX, maxY) = (float(b) for b in bounds_string.split(","))
        bounds_polygon = Polygon(((minX, minY), (minX, maxY), (maxX, maxY), (maxX, minY), (minX, minY)))
        query &= Q(bounds__intersects=bounds_polygon)

    if keyword_string:
        keyword_query =  Q(LayerDisplayName__icontains=keyword_string)
#       keyword_query =  Q(Name__icontains=keyword_string)
        keyword_query |= Q(PlaceKeywords__icontains=keyword_string)
        keyword_query |= Q(ThemeKeywords__icontains=keyword_string)
        keyword_query |= Q(collection__full_name__icontains=keyword_string)
        query &= keyword_query

    if originator_string:
        query &= Q(Originator__icontains=originator_string)

    if datatype_string:
        datatype_query = Q()
        for datatype in datatype_string.split(","):
            datatype_query |= Q(DataType=datatype)
        query &= datatype_query

    #dates are strings in the format %Y-%m-%dT%H:%M:%SZ
    if years_string:
        (start_year, end_year) = years_string.split("-")
        date_query = Q()

        if (start_year):
            date_query &= Q(ContentDate__gt=start_year)
        if (end_year):
            date_query &= Q(ContentDate__lt=end_year)

        query &= date_query

    if grouped == "collection":
        groups = []

        collections = [ItemCollection.objects.get(Q(short_name = group_id) | Q(full_name = group_id))] if group_id else ItemCollection.objects.all().order_by("external", "short_name") 

        for ic in collections: 
            items = BoundedItem.objects.filter(query & Q(collection=ic, collection__enabled = True)).order_by("LayerDisplayName")

            if items.count() == 0:
                continue

            total_number = items.count()
            items = items[start:end] if end else items
            
            name = ic.short_name if not ic.external else ic.full_name
            groups.append({"name": name, "id": ic.id, "items": [x.as_dictionary(field_string) for x in items], "totalNumber": total_number})
        return completed_request({"groups": groups})
    elif grouped == "datatype":
        groups = []

        data_types = {}

        if group_id == "Maps and Images":
            data_types["Maps and Images"] = Q(DataType="Raster") | Q(DataType="Paper Map")
        elif group_id:
            data_types[group_id] = Q(DataType=group_id)
        else:
            data_types["Book"] = Q(DataType="Book")
            data_types["Line"] = Q(DataType="Line")
            data_types["Maps and Images"] = Q(DataType="Raster") | Q(DataType="Paper Map")
            data_types["Point"] = Q(DataType="Point")
            data_types["Polygon"] = Q(DataType="Polygon")

        for data_type in data_types:
            data_type_query = data_types[data_type]
            items = BoundedItem.objects.filter(query & data_type_query).order_by("LayerDisplayName")
            total_number = items.count()
            items = items[start:end] if end else items
            groups.append({"name": data_type, "items": [x.as_dictionary(field_string) for x in items], "totalNumber": total_number, "id": data_type})

        return completed_request({"groups": groups})
    elif grouped == "category":
        groups = []

        if not group_id:
            misc_query = Q()
            for c in Category.objects.all().order_by("name"):
                items = c.items.filter(query).order_by("LayerDisplayName")
                total_number = items.count()
                items = items[start:end] if end else items
                groups.append({"name": c.name, "items": [x.as_dictionary(field_string) for x in items], "totalNumber": total_number, "id": c.id})
                misc_query = misc_query & ~Q(ThemeKeywords__icontains=c.keyword)
    
            misc_items = BoundedItem.objects.filter(query & misc_query).order_by("LayerDisplayName")
            misc_total = misc_items.count()
            misc_items = misc_items[start:end] if end > 0 else misc_items
            groups.append({
                "name": "Uncategorized",
                "items": [x.as_dictionary(field_string) for x in misc_items],
                "totalNumber": misc_total,
                "id": "misc"
            })
        elif group_id == "Uncategorized":
            misc_query = Q()
            for c in Category.objects.all().order_by("name"):
                misc_query = misc_query & ~Q(ThemeKeywords__icontains=c.keyword)
            misc_items = BoundedItem.objects.filter(query & misc_query).order_by("LayerDisplayName")
            misc_total = misc_items.count()
            misc_items = misc_items[start:end] if end > 0 else misc_items
            groups.append({
                "name": "Uncategorized",
                "items": [x.as_dictionary(field_string) for x in misc_items],
                "totalNumber": misc_total,
                "id": "misc"
            })
        elif group_id:
            c = Category.objects.get(name=group_id)
            items = c.items.filter(query).order_by("LayerDisplayName")
            total_number = items.count()
            items = items[start:end] if end else items
            groups.append({"name": c.name, "items": [x.as_dictionary(field_string) for x in items], "totalNumber": total_number, "id": c.id})

        return completed_request({"groups": groups})
    elif grouped == "year":
        groups = []
        years = {}
        items = BoundedItem.objects.filter(query).order_by("LayerDisplayName")

        for item in items:
            year = item.ContentDate[0:4]
            if not year in years:
                years[year] = []
            years[year].append(item)
        for year in years:
            groups.append({"name": unicode(year), "items": [x.as_dictionary(field_string) for x in years[year]]})

        return completed_request({"groups": groups})
    else:
        items = BoundedItem.objects.filter(query).order_by("LayerDisplayName")
        total_number = items.count()
        items = items[start:end] if end else items
        
        groups = [{"name": "All Items Alphabetically", "items": [x.as_dictionary(field_string) for x in items], "totalNumber": total_number, "id": "all"}]

        return completed_request({"groups": groups})