def testAddition(self): "Test addition & subtraction" a1 = A(sq_m=100) a2 = A(sq_m=200) a3 = a1 + a2 self.assertEqual(a3.sq_m, 300) a3 += a1 self.assertEqual(a3.sq_m, 400) a4 = a1 - a2 self.assertEqual(a4.sq_m, -100) a4 -= a1 self.assertEqual(a4.sq_m, -200) with self.assertRaises(TypeError): a1 + 1 with self.assertRaises(TypeError): a1 - 1 with self.assertRaises(TypeError): a1 += 1 with self.assertRaises(TypeError): a1 -= 1
def test_hash(self): a1 = A(sq_m=100) a2 = A(sq_m=1000000) a3 = A(sq_km=1) self.assertEqual(hash(a2), hash(a3)) self.assertNotEqual(hash(a1), hash(a2)) self.assertNotEqual(hash(a1), hash(a3))
def handle(self, *args, **options): print("Calculando country codes") b = kings aas = AdministrativeArea.objects.filter(depth=1) for aa in aas: cc = next(v['country_code'] for k, v in kings.items() if v['id'] == aa.osm_id) print(f' > {aa.osm_type} {aa.osm_id} {aa.name}') print(' - Lineas: ', end='') # Linea.objects.filter(envolvente__intersects=aa.geometry_simple).update(country_code=cc) print(Linea.objects \ .annotate(intersection_area=Area(Intersection(F('envolvente'), aa.geometry_simple)) / Area(F('envolvente'))) \ .filter(intersection_area__gt=A(sq_m=0.65)) \ .update(country_code=cc)) print(' - Recorrido: ', end='') print(Recorrido.objects \ .annotate(intersection_len=Length(Intersection(F('ruta_simple'), aa.geometry_simple)) / Length(F('ruta_simple'))) \ .filter(intersection_len__gt=D(m=0.65)) \ .update(country_code=cc)) print(' - Parada: ', end='') print( Parada.objects.filter( latlng__intersects=aa.geometry_simple).update( country_code=cc)) print(' - Poi: ', end='') print( Poi.objects.filter( latlng__intersects=aa.geometry_simple).update( country_code=cc)) print(' - AdministrativeArea: ', end='') print(AdministrativeArea.objects \ .annotate(intersection_area=Area(Intersection(F('geometry_simple'), aa.geometry_simple)) / Area(F('geometry_simple'))) \ .filter(intersection_area__gt=A(sq_m=0.65)) \ .update(country_code=cc)) print(' > DONE')
def testMultiplication(self): "Test multiplication & division" a1 = A(sq_m=100) a3 = a1 * 2 self.assertEqual(a3.sq_m, 200) a3 = 2 * a1 self.assertEqual(a3.sq_m, 200) a3 *= 5 self.assertEqual(a3.sq_m, 1000) a4 = a1 / 2 self.assertEqual(a4.sq_m, 50) a4 /= 5 self.assertEqual(a4.sq_m, 10) with self.assertRaises(TypeError): a1 * A(sq_m=1) with self.assertRaises(TypeError): a1 *= A(sq_m=1) with self.assertRaises(TypeError): a1 / A(sq_m=1) with self.assertRaises(TypeError): a1 /= A(sq_m=1)
def testMultiplication(self): "Test multiplication & division" a1 = A(sq_m=100) a3 = a1 * 2 self.assertEqual(a3.sq_m, 200) a3 = 2 * a1 self.assertEqual(a3.sq_m, 200) a3 *= 5 self.assertEqual(a3.sq_m, 1000) a4 = a1 / 2 self.assertEqual(a4.sq_m, 50) a4 /= 5 self.assertEqual(a4.sq_m, 10) with self.assertRaises(TypeError): a5 = a1 * A(sq_m=1) self.fail('Area * Area should raise TypeError') with self.assertRaises(TypeError): a1 *= A(sq_m=1) self.fail('Area *= Area should raise TypeError') with self.assertRaises(TypeError): a5 = a1 / A(sq_m=1) self.fail('Area / Area should raise TypeError') with self.assertRaises(TypeError): a1 /= A(sq_m=1) self.fail('Area /= Area should raise TypeError')
def testAddition(self): "Test addition & subtraction" a1 = A(sq_m=100) a2 = A(sq_m=200) a3 = a1 + a2 self.assertEqual(a3.sq_m, 300) a3 += a1 self.assertEqual(a3.sq_m, 400) a4 = a1 - a2 self.assertEqual(a4.sq_m, -100) a4 -= a1 self.assertEqual(a4.sq_m, -200) with self.assertRaises(TypeError): a5 = a1 + 1 self.fail('Area + number should raise TypeError') with self.assertRaises(TypeError): a5 = a1 - 1 self.fail('Area - number should raise TypeError') with self.assertRaises(TypeError): a1 += 1 self.fail('Area += number should raise TypeError') with self.assertRaises(TypeError): a1 -= 1 self.fail('Area -= number should raise TypeError')
def test_units_str(self): "Testing conversion to strings" a1 = A(sq_m=100) a2 = A(sq_km=3.5) self.assertEqual(str(a1), "100.0 sq_m") self.assertEqual(str(a2), "3.5 sq_km") self.assertEqual(repr(a1), "Area(sq_m=100.0)") self.assertEqual(repr(a2), "Area(sq_km=3.5)")
def testUnitsStr(self): "Testing conversion to strings" a1 = A(sq_m=100) a2 = A(sq_km=3.5) self.assertEqual(str(a1), '100.0 sq_m') self.assertEqual(str(a2), '3.5 sq_km') self.assertEqual(repr(a1), 'Area(sq_m=100.0)') self.assertEqual(repr(a2), 'Area(sq_km=3.5)')
def testComparisons(self): "Testing comparisons" a1 = A(sq_m=100) a2 = A(sq_km=1) a3 = A(sq_km=0) self.assertGreater(a2, a1) self.assertEqual(a1, a1) self.assertLess(a1, a2) self.assertFalse(a3)
def testComparisons(self): "Testing comparisons" a1 = A(sq_m=100) a2 = A(sq_km=1) a3 = A(sq_km=0) self.assertTrue(a2 > a1) self.assertTrue(a1 == a1) self.assertTrue(a1 < a2) self.assertFalse(a3)
def testInit(self): "Testing initialization from valid units" a = Area(sq_m=100) self.assertEqual(a.sq_m, 100) a = A(sq_m=100) self.assertEqual(a.sq_m, 100) a = A(sq_mi=100) self.assertEqual(a.sq_m, 258998811.0336)
def testComparisons(self): "Testing comparisons" a1 = A(sq_m=100) a2 = A(sq_km=1) a3 = A(sq_km=0) self.assert_(a2 > a1) self.assert_(a1 == a1) self.assert_(a1 < a2) self.failIf(a3)
def testUnitConversions(self): "Testing default units during maths" a1 = A(sq_m=100) a2 = A(sq_km=1) a3 = a1 + a2 self.assertEqual(a3._default_unit, 'sq_m') a4 = a2 + a1 self.assertEqual(a4._default_unit, 'sq_km') a5 = a1 * 2 self.assertEqual(a5._default_unit, 'sq_m') a6 = a1 / 2 self.assertEqual(a6._default_unit, 'sq_m')
def testMultiplication(self): "Test multiplication & division" a1 = A(sq_m=100) a3 = a1 * 2 self.assertEqual(a3.sq_m, 200) a3 *= 5 self.assertEqual(a3.sq_m, 1000) a4 = a1 / 2 self.assertEqual(a4.sq_m, 50) a4 /= 5 self.assertEqual(a4.sq_m, 10) try: a5 = a1 * A(sq_m=1) except TypeError, e: pass
def testAddition(self): "Test addition & subtraction" a1 = A(sq_m=100) a2 = A(sq_m=200) a3 = a1 + a2 self.assertEqual(a3.sq_m, 300) a3 += a1 self.assertEqual(a3.sq_m, 400) a4 = a1 - a2 self.assertEqual(a4.sq_m, -100) a4 -= a1 self.assertEqual(a4.sq_m, -200) try: a5 = a1 + 1 except TypeError, e: pass
def ver_linea(request, osm_type=None, osm_id=None, slug=None, country_code=None): """ osm_type = - 'c': cualbondi recorrido, usar id de la tabla directamente - 'r': relation de osm, usar osm_id con el campo osm_id """ # TODO: redirect id c123 a r123 si viene con osm_type=c y existe el osm_id linea_q = Linea.objects.only('nombre', 'slug', 'img_cuadrada', 'info_empresa', 'info_terminal', 'img_panorama', 'envolvente') linea = None if osm_type == 'c': linea = get_object_or_404(linea_q, id=osm_id) elif osm_type == 'r': linea = get_object_or_404(linea_q, osm_id=osm_id) linea__envolvente = linea.envolvente.simplify(0.001, True) recorridos = natural_sort_qs(linea.recorridos.all().defer('ruta'), 'slug') # aa = AdministrativeArea.objects \ # .filter(geometry_simple__intersects=linea.envolvente) \ # .annotate(inter_area=DBArea(Intersection(F('geometry_simple'), linea.envolvente))) \ # .filter(inter_area__gt=Area(sq_m=linea.envolvente.area * 0.8)) \ # .annotate(area=DBArea(F('geometry_simple'))) \ # .order_by('area') # aa = AdministrativeArea.objects \ # .filter(geometry_simple__intersects=linea.envolvente) \ # .annotate(symdiff_area=Area(SymDifference(F('geometry_simple'), linea.envolvente)) / Area(Union(F('geometry_simple'), linea.envolvente))) \ # .order_by('symdiff_area') aa = AdministrativeArea.objects \ .filter(geometry_simple__intersects=linea__envolvente) \ .annotate(symdiff_area=Area(SymDifference(F('geometry_simple'), linea__envolvente)) / (Area(F('geometry_simple')) + Area(linea__envolvente))) \ .annotate(intersection_area=Area(Intersection(F('geometry_simple'), linea__envolvente)) / Area(linea__envolvente)) \ .filter(intersection_area__gt=A(sq_m=0.8)) \ .order_by('symdiff_area') # for a in aa: # print(f'{a.symdiff_area, a.intersection_area, a.name}') # aa = AdministrativeArea.objects \ # .filter(geometry_simple__intersects=linea.envolvente) \ # .annotate(symdiff_area=Area(SymDifference(F('geometry_simple'), linea.envolvente))) \ # .order_by('symdiff_area') if aa: aa = aa[0] aaancestors = aa.get_ancestors().reverse() else: aa = None aaancestors = None # linea found, check if url is ok correct_url = linea.get_absolute_url() if correct_url not in request.build_absolute_uri(): return HttpResponsePermanentRedirect(add_lang_qs(correct_url, request)) # Zonas por las que pasa el recorrido aas = AdministrativeArea.objects \ .filter(geometry_simple__intersects=linea__envolvente, depth__gt=3) \ .order_by('depth', 'name') return render( request, "core/ver_linea.html", { 'obj': linea, 'recorridos': recorridos, 'adminarea': aa, 'adminareaancestors': aaancestors, 'adminareas': aas, } )
def test_access_invalid_a(self): "Testing access in invalid units" a = A(sq_m=100) self.assertFalse(hasattr(a, "banana"))
def testAccessInvaliA(self): "Testing access in invalid units" a = A(sq_m=100) self.assertFalse(hasattr(a, 'banana'))
def testAccess(self): "Testing access in different units" a = A(sq_m=100) self.assertEqual(a.sq_km, 0.0001) self.assertAlmostEqual(a.sq_ft, 1076.391, 3)
def testInitInvaliA(self): "Testing initialization from invalid units" with self.assertRaises(AttributeError): A(banana=100)
self.assertEqual(a3.sq_m, 1000) a4 = a1 / 2 self.assertEqual(a4.sq_m, 50) a4 /= 5 self.assertEqual(a4.sq_m, 10) try: a5 = a1 * A(sq_m=1) except TypeError, e: pass else: self.fail('Area * Area should raise TypeError') try: a1 *= A(sq_m=1) except TypeError, e: pass else: self.fail('Area *= Area should raise TypeError') try: a5 = a1 / A(sq_m=1) except TypeError, e: pass else: self.fail('Area / Area should raise TypeError') try: a1 /= A(sq_m=1) except TypeError, e:
def ver_recorrido(request, osm_type=None, osm_id=None, slug=None, country_code=None): """ osm_type = - 'c': cualbondi recorrido, usar id de la tabla directamente - 'r': relation de osm, usar osm_id con el campo osm_id """ recorrido_q = Recorrido.objects \ .only('nombre', 'slug', 'inicio', 'fin', 'img_cuadrada', 'img_panorama', 'ruta', 'linea', 'osm_id') \ .select_related('linea') recorrido = None if osm_type == 'c': recorrido = get_object_or_404(recorrido_q, id=osm_id) elif osm_type == 'w': # there can be multiple with the same id, so we filter using the most approximate slug recorridos = Recorrido.objects.filter(osm_id=osm_id).annotate(similarity=TrigramSimilarity('slug', slug or '')).order_by('-similarity') if recorridos: recorrido = recorridos[0] else: raise Http404 recorrido_simplified = recorrido.ruta.simplify(0.00005) recorrido_buffer = recorrido_simplified.buffer(0.0001) # aa = AdministrativeArea.objects \ # .filter(geometry_simple__intersects=recorrido_simplified) \ # .annotate(symdiff_area=Area(SymDifference(F('geometry_simple'), recorrido_simplified)) / (Area(F('geometry_simple')) + Area(recorrido_simplified))) \ # .order_by('symdiff_area') aa = AdministrativeArea.objects \ .filter(geometry_simple__intersects=recorrido_buffer) \ .annotate(symdiff_area=Area(SymDifference(F('geometry_simple'), recorrido_buffer)) / (Area(F('geometry_simple')) + Area(recorrido_buffer))) \ .annotate(intersection_area=Area(Intersection(F('geometry_simple'), recorrido_buffer)) / Area(recorrido_buffer)) \ .filter(intersection_area__gt=A(sq_m=0.8)) \ .order_by('symdiff_area') if aa: aa = aa[0] aaancestors = aa.get_ancestors().reverse() else: aa = None aaancestors = None # recorrido found, check if url is ok correct_url = recorrido.get_absolute_url() if correct_url not in request.build_absolute_uri(): return HttpResponsePermanentRedirect(add_lang_qs(correct_url, request)) # Calles por las que pasa el recorrido """ # solucion 1 # toma todas las calles cercanas al recorrido # simple pero no funciona bien, genera "falsos positivos", trae calles perpendiculares al recorrido # igual es lento: 13 seg calles_fin = Calle.objects.filter(way__distance_lte=(recorrido.ruta, D(m=20))) # alternativa con dwithin # igual es lento, pero 10 veces mejor que antes: 1.4 seg calles_fin = Calle.objects.filter(way__dwithin=(recorrido.ruta, D(m=20))) """ """ # solucion 2 # toma las calles que estan cercanas y se repiten cada par de puntos # hace 1 query lenta por cada punto: funciona bien, pero un poco lento! # 0.003 seg x cant_puntos calles_ant = None calles_fin = [] for p in recorrido.ruta.coords: calles = Calle.objects.filter(way__dwithin=(Point(p), D(m=50))) if calles_ant is not None: for c in calles_ant: if len(calles_fin) > 0: if c.nom != calles_fin[-1].nom and c in calles: calles_fin.append(c) else: calles_fin.append(c) calles_ant = calles # TODO: tal vez se pueda mejorar eso con una custom query sola. """ # solucion 3, como la solucion 2 pero con raw query (para bs as no anda bien) if not recorrido.descripcion or not recorrido.descripcion.strip(): def uniquify(seq, idfun=None): if idfun is None: def idfun(x): return x seen = {} result = [] for item in seq: marker = idfun(item) if marker in seen: continue seen[marker] = 1 result.append(item) return result from django.db import connection cursor = connection.cursor() cursor.execute( ''' SELECT (dp).path[1] as idp, cc.nom as nom FROM (SELECT ST_DumpPoints(%s) as dp ) as dpa JOIN catastro_calle as cc ON ST_DWithin(cc.way, (dp).geom, 20) ''', ( recorrido_simplified.ewkb, ) ) from collections import OrderedDict calles = OrderedDict() for c in cursor.fetchall(): if c[0] in calles: calles[c[0]].append(c[1]) else: calles[c[0]] = [c[1]] calles_fin = [] calles_ant = [] for k in calles: calles_aca = [] for c in calles_ant: if len(calles_fin) > 0: if c not in calles_fin[-1] and c in calles[k]: calles_aca.append(c) else: calles_aca.append(c) if calles_aca: calles_fin.append(calles_aca) calles_ant = calles[k] calles_fin = [item for sublist in calles_fin for item in uniquify(sublist)] else: calles_fin = None # POI por los que pasa el recorrido pois = Poi.objects.filter(latlng__dwithin=(recorrido_simplified, D(m=400))).order_by('?')[:60] # Zonas por las que pasa el recorrido aas = AdministrativeArea.objects \ .filter(geometry_simple__intersects=recorrido_buffer, depth__gt=3) \ .order_by('depth') # Horarios + paradas que tiene este recorrido horarios = recorrido.horario_set.all().prefetch_related('parada').order_by('?')[:60] recorridos_similares = Recorrido.objects.similar_hausdorff(recorrido_simplified) aaancestors, calles_fin, pois, aas, horarios, recorridos_similares = parallelize(aaancestors, calles_fin, pois, aas, horarios, recorridos_similares) try: schemaorg_itemtype = { 'bus': 'BusTrip', 'trolleybus': 'BusTrip', 'train': 'TrainTrip', 'subway': 'TrainTrip', 'monorail': 'TrainTrip', 'tram': 'TrainTrip', 'light_rail': 'TrainTrip', }[recorrido.type] except: schemaorg_itemtype = 'Trip' context = { 'schemaorg_itemtype': schemaorg_itemtype, 'obj': recorrido, 'linea': recorrido.linea, 'adminarea': aa, 'adminareaancestors': aaancestors, 'calles': calles_fin, 'pois': pois, 'adminareas': aas, 'horarios': horarios, 'recorridos_similares': recorridos_similares, } return render(request, "core/ver_recorrido.html", context)
def testAccessInvaliA(self): "Testing access in invalid units" a = A(sq_m=100) self.failIf(hasattr(a, 'banana'))