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
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))
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)
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)
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})