15 Commits

Author SHA1 Message Date
KatKatKateryna 22176c8b8f Merge branch 'dev' into polishing_more
flake8 / flake8_py3 (push) Has been cancelled
2024-09-05 14:31:05 +01:00
KatKatKateryna 60c41dc76f double-check for display vals 2024-09-05 14:29:01 +01:00
KatKatKateryna 2900046d14 Merge branch 'dev' into polishing_more 2024-09-04 23:51:50 +01:00
KatKatKateryna f35cf4122f html syntax 2024-09-04 23:41:20 +01:00
KatKatKateryna 3b7877a0bf leaflet controls to the right 2024-09-04 23:30:44 +01:00
KatKatKateryna ab9df29ae4 add bbox per feature 2024-09-04 23:06:08 +01:00
KatKatKateryna 22968f0749 URL exceptions handling 2024-09-04 22:49:14 +01:00
KatKatKateryna ee37ca89e2 avoid multiple loops 2024-09-04 16:08:47 +01:00
KatKatKateryna 4e867c86d8 ensure speckleURL argument 2024-09-04 16:04:45 +01:00
KatKatKateryna 6d425d4212 split polygons in leaflet 2024-09-04 15:11:19 +01:00
KatKatKateryna b2c4498419 fix multipolygons 2024-09-04 14:17:15 +01:00
KatKatKateryna 3d83276498 prioritize attributes by default, less geometry divisions 2024-09-04 13:52:15 +01:00
KatKatKateryna c83f87425a fix multipolygons in 3d 2024-09-04 13:51:41 +01:00
KatKatKateryna eb381bdd2f traverse for colors 2024-09-04 11:32:11 +01:00
KatKatKateryna 93e0cd5792 colors and materials 2024-09-04 04:19:51 +01:00
33 changed files with 140 additions and 482 deletions
+1 -1
View File
@@ -530,7 +530,7 @@ paths:
- hello-world - hello-world
servers: servers:
- description: pygeoapi provides an API to geospatial data - description: pygeoapi provides an API to geospatial data
url: https://geo.speckle.systems url: http://localhost:5000
tags: tags:
- description: pygeoapi provides an API to geospatial data - description: pygeoapi provides an API to geospatial data
externalDocs: externalDocs:
-3
View File
@@ -1,6 +1,3 @@
access_log
error_log*
# Byte-compiled / optimized / DLL files # Byte-compiled / optimized / DLL files
__pycache__/ __pycache__/
*.py[cod] *.py[cod]
-3
View File
@@ -1,3 +0,0 @@
geo.speckle.systems {
reverse_proxy localhost:8000
}
+1 -1
View File
@@ -81,7 +81,7 @@ Then you can add it to the base map (e.g. using Leaflet and OpenStreetMap basema
loadSpeckleData(); loadSpeckleData();
async function loadSpeckleData() => { async function loadSpeckleData() => {
var speckle_model_url = 'https://geo.speckle.systems/speckle/?speckleUrl=https://app.speckle.systems/projects/344f803f81/models/5582ab673e&datatype=polygons'; var speckle_model_url = 'https://geo.speckle.systems/?speckleUrl=https://app.speckle.systems/projects/344f803f81/models/5582ab673e&datatype=polygons';
const speckle_data = await fetch(speckle_model_url, { const speckle_data = await fetch(speckle_model_url, {
headers: {'Accept': 'application/geo+json'} headers: {'Accept': 'application/geo+json'}
}).then(response => response.json()); }).then(response => response.json());
+1 -1
View File
@@ -128,4 +128,4 @@ resources:
hello-world: hello-world:
type: process type: process
processor: processor:
name: HelloWorld name: HelloWorld
+1 -1
View File
@@ -75,7 +75,7 @@ LOGGER = logging.getLogger(__name__)
#: Return headers for requests (e.g:X-Powered-By) #: Return headers for requests (e.g:X-Powered-By)
HEADERS = { HEADERS = {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
# 'X-Powered-By': f'pygeoapi {__version__}' 'X-Powered-By': f'pygeoapi {__version__}'
} }
CHARSET = ['utf-8'] CHARSET = ['utf-8']
+1 -1
View File
@@ -309,7 +309,7 @@ def get_collection_items(
# clear data if no URL params # clear data if no URL params
load_data = False load_data = False
for item in request.params: for item in request.params:
if item.lower() == 'speckleurl' and len(request.params[item])>40 and ('speckleurl=' + request.params[item]) in provider_def['data'].lower(): if item == 'speckleUrl' and len(request.params[item])>40 and ('speckleUrl=' + request.params[item]) in provider_def['data']:
load_data = True load_data = True
break break
if load_data is False: if load_data is False:
+24 -81
View File
@@ -34,14 +34,10 @@ import os
from typing import Union from typing import Union
import click import click
from datetime import datetime, timezone
from flask import (Flask, Blueprint, make_response, request, from flask import (Flask, Blueprint, make_response, request,
send_from_directory, Response, Request, stream_with_context) send_from_directory, Response, Request, stream_with_context)
from http import HTTPStatus from http import HTTPStatus
import json
from urllib.request import urlopen
from pygeoapi.api import API, APIRequest, apply_gzip from pygeoapi.api import API, APIRequest, apply_gzip
import pygeoapi.api.coverages as coverages_api import pygeoapi.api.coverages as coverages_api
import pygeoapi.api.environmental_data_retrieval as edr_api import pygeoapi.api.environmental_data_retrieval as edr_api
@@ -50,7 +46,6 @@ import pygeoapi.api.maps as maps_api
import pygeoapi.api.processes as processes_api import pygeoapi.api.processes as processes_api
import pygeoapi.api.stac as stac_api import pygeoapi.api.stac as stac_api
import pygeoapi.api.tiles as tiles_api import pygeoapi.api.tiles as tiles_api
from pygeoapi.provider.speckle_utils.legal import COUNTRY_CODES
from pygeoapi.openapi import load_openapi_document from pygeoapi.openapi import load_openapi_document
from pygeoapi.config import get_config from pygeoapi.config import get_config
from pygeoapi.util import get_mimetype, get_api_rules, render_j2_template from pygeoapi.util import get_mimetype, get_api_rules, render_j2_template
@@ -173,62 +168,6 @@ def execute_from_flask(api_function, request: Request, *args,
return get_response((headers, status, content)) return get_response((headers, status, content))
def handle_client(url_route: str):
# if called fromm the browser, Exceptions from this function will result in infinite load
agent = request.headers.get('User-Agent')
if request.environ.get('HTTP_X_FORWARDED_FOR') is None:
ip_address = request.environ['REMOTE_ADDR']
else:
ip_address = request.environ['HTTP_X_FORWARDED_FOR']
if agent is not None and "(https://www.checklyhq.com)" not in agent:
print(f"_______________________{datetime.now().astimezone(timezone.utc)} _URL access")
print(f"_Agent {url_route}: {agent}")
print(f"_IP Address: {ip_address}")
print(f"_Request URL: {request.url}")
request.url += f"&userAgent={agent}"
# by Agent:
if agent is not None and ("YaBrowser/" in agent or "yandex" in agent.lower()):
raise ValueError("Your browser is not supported.")
# by IP:
try:
url = 'https://ipinfo.io/' + ip_address + '/json'
res = urlopen(url)
data = json.load(res)
if isinstance(data, dict) and isinstance(data["country"], str):
if data["country"].lower() in COUNTRY_CODES:
raise PermissionError("Review Speckle Terms and Conditions")
else:
print(f"Error validating client: DATA {data}")
except Exception as e:
print(f"Error validating client from start: {e}")
def generate():
collection_id = "speckle"
yield loading_screen().data
handle_client("/")
CONFIG = get_config(request=request)
api_ = API(CONFIG, OPENAPI)
try:
browser_response = execute_from_flask(itemtypes_api.get_collection_items,
request, collection_id,
skip_valid_check=True)
yield browser_response.data
except PermissionError as ex:
raise ex
except Exception as ex:
yield error_screen(ex).data
@BLUEPRINT.route('/') @BLUEPRINT.route('/')
def landing_page(): def landing_page():
""" """
@@ -236,24 +175,41 @@ def landing_page():
:returns: HTTP response :returns: HTTP response
""" """
collection_id = "speckle"
agent = request.headers.get('User-Agent') agent = request.headers.get('User-Agent')
# Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36
# Mozilla/5.0 QGIS/32815/Windows 10 Version 2009
# ArcGIS Pro 3.3.0 (00000000000) - ArcGISPro
browser_agent = False browser_agent = False
browser_list = ["Chrome", "Safari", "Firefox", "Edg/", "Trident/"] browser_list = ["Chrome", "Safari", "Firefox", "Edg/", "Trident/"]
print(agent)
if "YaBrowser/" in agent:
raise ValueError("Your browser is not supported.")
for br in browser_list: for br in browser_list:
if agent is not None and br in agent: if br in agent:
browser_agent = True browser_agent = True
break break
# if requested from the browser, return this, otherwise ignore IF statement # if requested from the browser, return this, otherwise ignore IF statement
if request.method == 'GET' and browser_agent: # list items if request.method == 'GET' and browser_agent: # list items
def generate():
yield loading_screen().data
try:
browser_response = execute_from_flask(itemtypes_api.get_collection_items,
request, collection_id,
skip_valid_check=True)
yield browser_response.data
except Exception as ex:
yield error_screen(ex).data
return Response(stream_with_context(generate())) return Response(stream_with_context(generate()))
# for non-browsers
handle_client("/")
CONFIG = get_config(request=request)
api_ = API(CONFIG, OPENAPI)
return get_response(api_.landing_page(request)) return get_response(api_.landing_page(request))
def error_screen(ex: Exception): def error_screen(ex: Exception):
@@ -338,20 +294,10 @@ def collections(collection_id=None):
:returns: HTTP response :returns: HTTP response
""" """
handle_client("/collections") # raise NotImplementedError()
return get_response(api_.describe_collections(request, collection_id)) return get_response(api_.describe_collections(request, collection_id))
@BLUEPRINT.route('/speckle')
def speckle_collection():
handle_client("/speckle")
collection_id="speckle"
return collection_items(collection_id=collection_id)
@BLUEPRINT.route('/collections/<path:collection_id>/schema') @BLUEPRINT.route('/collections/<path:collection_id>/schema')
def collection_schema(collection_id): def collection_schema(collection_id):
""" """
@@ -397,9 +343,6 @@ def collection_items(collection_id, item_id=None):
:returns: HTTP response :returns: HTTP response
""" """
handle_client(f"/collections/{collection_id}/items")
collection_id = 'speckle' collection_id = 'speckle'
if item_id is None: if item_id is None:
+8 -39
View File
@@ -119,19 +119,11 @@ class SpeckleProvider(BaseProvider):
self.speckle_url = self.url.lower().split("speckleurl=")[-1].split("&")[0].split("@")[0].split("?")[0] self.speckle_url = self.url.lower().split("speckleurl=")[-1].split("&")[0].split("@")[0].split("?")[0]
self.speckle_data = None self.speckle_data = None
self.project_name = ""
self.project_id = ""
self.model_name = "" self.model_name = ""
self.sourceApp = ""
self.crs = None self.crs = None
self.crs_dict = None self.crs_dict = None
self.commit_gis = False
self.url_params = {"url_data_type":"", "url_preserve_attributes":"", "url_crs_authid":"", "url_lat":"","url_lon":"","url_north_degrees":"","url_limit":""}
self.times = {}
self.country_code = ""
self.requested_data_type: str = "polygons (default)" # points, lines, polygons, projectcomments self.requested_data_type: str = "polygons (default)" # points, lines, polygons, projectcomments
self.preserve_attributes: str = "true (default)" self.preserve_attributes: str = "true (default)"
self.lat: float = 48.76755913928929 #51.52486388756923 self.lat: float = 48.76755913928929 #51.52486388756923
@@ -139,13 +131,11 @@ class SpeckleProvider(BaseProvider):
self.north_degrees: float = 0 self.north_degrees: float = 0
self.crs_authid = "" self.crs_authid = ""
self.limit = 10000 self.limit = 10000
self.user_agent = ""
self.missing_url = "" self.missing_url = ""
self.limit_message = "" self.limit_message = ""
self.extent = [-180,-90,180,90] self.extent = [-180,-90,180,90]
self.extent3d = [-180,-90,0,180,90,1000]
self.material_color_proxies = {} self.material_color_proxies = {}
@@ -348,8 +338,7 @@ class SpeckleProvider(BaseProvider):
def load_speckle_data(self: str) -> Dict: def load_speckle_data(self: str) -> Dict:
"""Receive and process Speckle data, return geojson.""" """Receive and process Speckle data, return geojson."""
from datetime import datetime, timezone from pygeoapi.provider.speckle_utils.server_utils import get_stream_branch, get_client, get_comments
from pygeoapi.provider.speckle_utils.server_utils import get_stream_branch, get_client, get_comments, set_actions
from specklepy.objects.base import Base from specklepy.objects.base import Base
from specklepy.logging.exceptions import SpeckleException from specklepy.logging.exceptions import SpeckleException
@@ -371,10 +360,6 @@ class SpeckleProvider(BaseProvider):
# get stream and branch data # get stream and branch data
client = get_client(wrapper, url_proj) client = get_client(wrapper, url_proj)
stream, branch = get_stream_branch(self, client, wrapper) stream, branch = get_stream_branch(self, client, wrapper)
if stream is None:
raise ValueError(f"Project from URL '{url_proj}' not found")
if branch is None:
raise ValueError(f"Model '{wrapper.model_id}' of the project '{stream['name']}' not found")
if self.requested_data_type == "projectcomments": if self.requested_data_type == "projectcomments":
comments = get_comments(client, wrapper.stream_id, wrapper.model_id) comments = get_comments(client, wrapper.stream_id, wrapper.model_id)
@@ -383,20 +368,16 @@ class SpeckleProvider(BaseProvider):
comments = {} comments = {}
# set the Model name # set the Model name
self.project_id = wrapper.stream_id
self.project_name = stream['name']
self.model_name = branch['name'] self.model_name = branch['name']
commit = branch["commits"]["items"][0] commit = branch["commits"]["items"][0]
objId = commit["referencedObject"] objId = commit["referencedObject"]
self.sourceApp = commit["sourceApplication"]
transport = ServerTransport(client=client, account=client.account, stream_id=wrapper.stream_id) transport = ServerTransport(client=client, account=client.account, stream_id=wrapper.stream_id)
if transport == None: if transport == None:
raise SpeckleException("Transport not found") raise SpeckleException("Transport not found")
# receive commit # receive commit
set_actions(self, client)
try: try:
commit_obj = operations.receive(objId, transport, None) commit_obj = operations.receive(objId, transport, None)
except Exception as ex: except Exception as ex:
@@ -410,21 +391,18 @@ class SpeckleProvider(BaseProvider):
message="Received commit in pygeoapi", message="Received commit in pygeoapi",
) )
print(f"_{datetime.now().astimezone(timezone.utc)} _Rendering model '{branch['name']}' of the project '{stream['name']}'") print(f"Rendering model '{branch['name']}' of the project '{stream['name']}'")
speckle_data = self.traverse_data(commit_obj, comments) speckle_data = self.traverse_data(commit_obj, comments)
set_actions(self, client, "GEO post-receive")
speckle_data["features"].extend(speckle_data["comments"]) speckle_data["features"].extend(speckle_data["comments"])
speckle_data["comments"] = [] speckle_data["comments"] = []
speckle_data["project_id"] = wrapper.stream_id
speckle_data["project"] = stream['name'] speckle_data["project"] = stream['name']
speckle_data["model"] = branch['name'] speckle_data["model"] = branch['name']
speckle_data["model_last_version_date"] = datetime.strptime(commit['createdAt'].replace("T", " ").replace("Z","").split(".")[0], '%Y-%m-%d %H:%M:%S') speckle_data["model_last_version_date"] = datetime.strptime(commit['createdAt'].replace("T", " ").replace("Z","").split(".")[0], '%Y-%m-%d %H:%M:%S')
speckle_data["model_id"] = wrapper.model_id speckle_data["model_id"] = wrapper.model_id
speckle_data["extent"] = self.extent speckle_data["extent"] = self.extent
speckle_data["extent3d"] = self.extent3d
speckle_data["limit_message"] = self.limit_message speckle_data["limit_message"] = self.limit_message
return speckle_data return speckle_data
@@ -442,7 +420,7 @@ class SpeckleProvider(BaseProvider):
) )
from pygeoapi.provider.speckle_utils.crs_utils import get_set_crs_settings from pygeoapi.provider.speckle_utils.crs_utils import get_set_crs_settings
from pygeoapi.provider.speckle_utils.feature_utils import create_features from pygeoapi.provider.speckle_utils.feature_utils import create_features
from pygeoapi.provider.speckle_utils.display_utils import isDisplayable, set_default_color, get_material_color_proxies from pygeoapi.provider.speckle_utils.display_utils import set_default_color, get_material_color_proxies
supported_classes = [GisFeature, GisPolygonElement, Mesh, Brep, Point, Line, Polyline, Curve, Arc, Circle, Ellipse, Polycurve] supported_classes = [GisFeature, GisPolygonElement, Mesh, Brep, Point, Line, Polyline, Curve, Arc, Circle, Ellipse, Polycurve]
supported_types = [y().speckle_type for y in supported_classes] supported_types = [y().speckle_type for y in supported_classes]
@@ -464,22 +442,16 @@ class SpeckleProvider(BaseProvider):
"extent": [-180,-90,180,90], "extent": [-180,-90,180,90],
"model_crs": "-", "model_crs": "-",
} }
# rule to keep traversing the object's "x" attribute "item" (both conditions need to be fulfilled)
# 1. if the item type is not in supported (convertible) types or is GIS VectorLayer
# 2. if the item's value is a list or a GH object
rule = TraversalRule( rule = TraversalRule(
[lambda _: True], [lambda _: True],
lambda x: [ lambda x: [
item item
for item in x.get_member_names() for item in x.get_member_names()
if (x.speckle_type.split(":")[-1] not in supported_types or isinstance(x, VectorLayer)) if isinstance(getattr(x, item, None), list)
and (isinstance(getattr(x, item, None), list) or (self.sourceApp is not None and "grasshopper" in self.sourceApp.lower() and x.speckle_type == "Base") ) and (x.speckle_type.split(":")[-1] not in supported_types or isinstance(x, VectorLayer))
], ],
) )
context_list = [x for x in GraphTraversal([rule]).traverse(commit_obj)]
# for the context list, save the displayable objects and Layers (for getting CRS for now)
context_list = [x for x in GraphTraversal([rule]).traverse(commit_obj) if isDisplayable(x.current) or x.current.speckle_type.endswith("VectorLayer")]
get_set_crs_settings(self, commit_obj, context_list, data) get_set_crs_settings(self, commit_obj, context_list, data)
@@ -501,10 +473,7 @@ class SpeckleProvider(BaseProvider):
sorted_list[i]["properties"]["FID"] = i+1 sorted_list[i]["properties"]["FID"] = i+1
data['features'] = sorted_list data['features'] = sorted_list
time2 = datetime.now() time2 = datetime.now()
print(f"Sorting time: {(time2-time1).total_seconds()}")
time_operation = (time2-time1).total_seconds()
self.times["time_sort"] = time_operation
# print(f"Sorting time: {time_operation}")
return data return data
@@ -296,24 +296,8 @@ def assign_geometry(self: "SpeckleProvider", feature: Dict, f_base) -> Tuple[ Li
geometry["type"] = "MultiPolygon" geometry["type"] = "MultiPolygon"
coord_counts.append(None) coord_counts.append(None)
polygon_3d = False for geom in f_base["geometry"]:
convert_polygon(geom, coords, coord_counts)
for mesh in f_base["displayValue"]:
for i, coord in enumerate(mesh.vertices):
if i>60:
break
if i%3 !=0:
continue
elif coord != 0:
polygon_3d = True
break
if polygon_3d is False:
for geom in f_base["geometry"]:
convert_polygon(geom, coords, coord_counts)
else:
for geom in f_base["displayValue"]:
convert_mesh_or_brep(geom, coords, coord_counts)
elif self.requested_data_type == "points": elif self.requested_data_type == "points":
@@ -2,7 +2,6 @@
import copy import copy
import math import math
from typing import List from typing import List
from pygeoapi.provider.speckle_utils.legal import COUNTRY_CODES, STATES, POSTCODES
def reproject_bulk(self, all_coords: List[List[List[float]]], all_coord_counts: List[List[None| List[int]]], geometries) -> None: def reproject_bulk(self, all_coords: List[List[List[float]]], all_coord_counts: List[List[None| List[int]]], geometries) -> None:
@@ -14,12 +13,7 @@ def reproject_bulk(self, all_coords: List[List[List[float]]], all_coord_counts:
time1 = datetime.now() time1 = datetime.now()
flat_coords = reproject_2d_coords_list(self, all_coords) flat_coords = reproject_2d_coords_list(self, all_coords)
time2 = datetime.now() time2 = datetime.now()
time_operation = (time2-time1).total_seconds() print(f"Reproject time: {(time2-time1).total_seconds()}")
self.times["time_reproject"] = time_operation
validate_coords(self, flat_coords[0])
if len(flat_coords)>2:
validate_coords(self, flat_coords[len(flat_coords)-1])
# define type of features # define type of features
feat_coord_group_is_multi = [True if None in x else False for x in all_coord_counts] feat_coord_group_is_multi = [True if None in x else False for x in all_coord_counts]
@@ -55,15 +49,7 @@ def reproject_bulk(self, all_coords: List[List[List[float]]], all_coord_counts:
if geometry["type"] == "MultiPoint": if geometry["type"] == "MultiPoint":
poly_part.extend([local_flat_coords[ind] for ind in range_coords_indices]) poly_part.extend([local_flat_coords[ind] for ind in range_coords_indices])
else: else:
new_list = [] poly_part.append([local_flat_coords[ind] for ind in range_coords_indices])
for ind in range_coords_indices:
try:
new_list.append(local_flat_coords[ind])
except Exception as e: # corrupted geometry, ignore altogether
new_list = []
break
if len(new_list)>0:
poly_part.append(new_list)
start_index += part_count start_index += part_count
@@ -75,10 +61,7 @@ def reproject_bulk(self, all_coords: List[List[List[float]]], all_coord_counts:
geometry["coordinates"].extend(polygon_parts) geometry["coordinates"].extend(polygon_parts)
time3 = datetime.now() time3 = datetime.now()
print(f"Construct back geometry time: {(time3-time2).total_seconds()}")
time_operation = (time3-time2).total_seconds()
self.times["time_reconstruct_geometry"] = time_operation
# print(f"Construct back geometry time: {time_operation}")
def reproject_2d_coords_list(self, coords_in: List[List[float]]) -> List[List[float]]: def reproject_2d_coords_list(self, coords_in: List[List[float]]) -> List[List[float]]:
"""Return coordinates in a CRS of SpeckleProvider.""" """Return coordinates in a CRS of SpeckleProvider."""
@@ -97,9 +80,7 @@ def reproject_2d_coords_list(self, coords_in: List[List[float]]) -> List[List[fl
all_x = [x[0] for x in transformed] all_x = [x[0] for x in transformed]
all_y = [x[1] for x in transformed] all_y = [x[1] for x in transformed]
all_z = [x[2] for x in transformed]
self.extent = [min(all_x), min(all_y), max(all_x), max(all_y)] self.extent = [min(all_x), min(all_y), max(all_x), max(all_y)]
self.extent3d = [min(all_x), min(all_y), min(all_z), max(all_x), max(all_y), max(all_z)]
return transformed return transformed
def offset_rotate(self, coords_in: List[list]) -> List[List[float]]: def offset_rotate(self, coords_in: List[list]) -> List[List[float]]:
@@ -125,25 +106,3 @@ def offset_rotate(self, coords_in: List[list]) -> List[List[float]]:
) )
return final_coords return final_coords
def validate_coords(self, coords):
from geopy.geocoders import Nominatim
country_code = ""
state = ""
postcode = ""
try:
geolocator = Nominatim(user_agent="specklePygeoapi")
coord = f"{coords[1]}, {coords[0]}"
location = geolocator.reverse(coord, exactly_one=True)
if location is not None:
address = location.raw['address']
country_code = address.get('country_code', '')
state = address.get('state', '')
postcode = address.get('postcode', '')
except Exception as e:
print(f"Error validating project location: {e}")
self.country_code = country_code
if country_code in COUNTRY_CODES or state in STATES or postcode in POSTCODES:
print(f"Validating project location: blocked LAT LON {coords[1]}, {coords[0]}, {country_code}, {state}, {postcode}")
raise PermissionError("Review Speckle Terms and Conditions")
+1 -2
View File
@@ -51,7 +51,7 @@ def get_set_crs_settings(self: "SpeckleProvider", commit_obj: "Base", context_li
root_objects = [] root_objects = []
try: try:
root_objects = [commit_obj] + commit_obj.elements + [c.current for c in context_list] root_objects = [commit_obj] + commit_obj.elements
except AttributeError as ex: except AttributeError as ex:
pass # old commit structure pass # old commit structure
@@ -73,7 +73,6 @@ def get_set_crs_settings(self: "SpeckleProvider", commit_obj: "Base", context_li
offset_y = crs["offset_y"] offset_y = crs["offset_y"]
self.north_degrees = crs["rotation"] self.north_degrees = crs["rotation"]
create_crs_from_wkt(self, crs["wkt"]) create_crs_from_wkt(self, crs["wkt"])
self.commit_gis = True
if self.crs.to_authority() is not None: if self.crs.to_authority() is not None:
data["model_crs"] = f"{self.crs.to_authority()}, {self.crs.name} " data["model_crs"] = f"{self.crs.to_authority()}, {self.crs.name} "
+42 -134
View File
@@ -54,7 +54,6 @@ def separate_display_vals(displayValue: List) -> List[Tuple["Base"]]:
count = 0 count = 0
all_count = len(item.faces) all_count = len(item.faces)
sub_meshes = []
for _ in item.faces: for _ in item.faces:
if count < all_count: if count < all_count:
faces = [] faces = []
@@ -62,67 +61,33 @@ def separate_display_vals(displayValue: List) -> List[Tuple["Base"]]:
colors = [] colors = []
vert_num = item.faces[count] vert_num = item.faces[count]
if vert_num == 0:
vert_num = 3
elif vert_num == 1:
vert_num = 4
faces.append(vert_num) faces.append(vert_num)
faces.extend([ x for x in list(range(vert_num))]) faces.extend([ x for x in list(range(vert_num))])
try: for ind in range(vert_num):
for ind in range(vert_num): face_vert_index = count+1+ind
face_vert_index = count+1+ind vert_index = item.faces[face_vert_index]
#print(face_vert_index)
vert_index = item.faces[face_vert_index]
new_vert = item.vertices[3*vert_index : 3*vert_index + 3] new_vert = item.vertices[3*vert_index : 3*vert_index + 3]
verts.extend(new_vert) verts.extend(new_vert)
if isinstance(item.colors, List) and len(item.colors) > vert_index: if isinstance(item.colors, List) and len(item.colors) > vert_index:
color = item.colors[vert_index] color = item.colors[vert_index]
colors.append(color) colors.append(color)
count += vert_num+1
if len(colors)>0:
mesh = Mesh.create(faces= faces, vertices=verts, colors=colors)
else:
mesh = Mesh.create(faces= faces, vertices=verts)
sub_meshes.append((mesh, item))
except IndexError: # corrupted mesh, drop altogether count += vert_num+1
sub_meshes = [] if len(colors)>0:
break mesh = Mesh.create(faces= faces, vertices=verts, colors=colors)
else:
display_objs.extend(sub_meshes) mesh = Mesh.create(faces= faces, vertices=verts)
display_objs.append((mesh, item))
elif item is not None: elif item is not None:
display_objs.append((item, item)) display_objs.append((item, item))
return display_objs return display_objs
def isDisplayable(obj: "Base") -> bool:
if is_primitive(obj):
return True
if obj.speckle_type.endswith("Feature"):
return True
displayValue = None
if hasattr(obj, 'displayValue'):
displayValue = getattr(obj, 'displayValue')
elif hasattr(obj, '@displayValue'):
displayValue = getattr(obj, '@displayValue')
# merge to sigle object, if List
if isinstance(displayValue, List):
return True
return False
def find_display_obj(obj) -> Tuple["Base", "Base"]: def find_display_obj(obj) -> Tuple["Base", "Base"]:
"""Get displayable object.""" """Get displayable object."""
@@ -156,12 +121,11 @@ def find_display_obj(obj) -> Tuple["Base", "Base"]:
def is_convertible(obj) -> bool: def is_convertible(obj) -> bool:
"""Check if the object can be converted directly.""" """Check if the object can be converted directly."""
from specklepy.objects.geometry import Base, Point, Line, Polyline, Arc, Circle, Curve, Polycurve, Mesh, Brep from specklepy.objects.geometry import Base, Point, Line, Arc, Circle, Curve, Polycurve, Mesh, Brep
if ( (isinstance(obj, Base) and obj.speckle_type.endswith("Feature")) or if ( (isinstance(obj, Base) and obj.speckle_type.endswith("Feature")) or
isinstance(obj, Point) or isinstance(obj, Point) or
isinstance(obj, Line) or isinstance(obj, Line) or
isinstance(obj, Polyline) or
isinstance(obj, Arc) or isinstance(obj, Arc) or
isinstance(obj, Circle) or isinstance(obj, Circle) or
isinstance(obj, Curve) or isinstance(obj, Curve) or
@@ -171,23 +135,6 @@ def is_convertible(obj) -> bool:
return True return True
return False return False
def is_primitive(obj) -> bool:
"""Check if the object can be converted directly."""
from specklepy.objects.geometry import Polyline, Point, Line, Arc, Circle, Curve, Polycurve, Mesh, Brep
if (
isinstance(obj, Point) or
isinstance(obj, Line) or
isinstance(obj, Polyline) or
isinstance(obj, Arc) or
isinstance(obj, Circle) or
isinstance(obj, Curve) or
isinstance(obj, Mesh)
):
return True
return False
def get_single_display_object(displayValForColor: List) -> "Base": def get_single_display_object(displayValForColor: List) -> "Base":
"""Get a merged Mesh or a first item from displayValue list.""" """Get a merged Mesh or a first item from displayValue list."""
@@ -309,8 +256,8 @@ def set_default_color(context_list: List["TraversalContext"]) -> None:
for item in context_list: for item in context_list:
# for GIS-commits, use default blue color # for GIS-commits, use default blue color
if isinstance(item.current, VectorLayer) or (item.parent is not None and isinstance(item.parent.current, VectorLayer)): if isinstance(item.current, VectorLayer):
DEFAULT_COLOR = (255 << 24) + (10 << 16) + (132 << 8) + 255 # speckle blue, speckle_blue DEFAULT_COLOR = (255 << 24) + (10 << 16) + (132 << 8) + 255
break break
def getAllParents(tc: "TraversalContext"): def getAllParents(tc: "TraversalContext"):
@@ -334,6 +281,22 @@ def assign_color(self: "SpeckleProvider", obj_display_tc: "TraversalContext", pr
from specklepy.objects.geometry import Mesh, Brep from specklepy.objects.geometry import Mesh, Brep
for tc in getAllParents(obj_display_tc):
try:
color = self.material_color_proxies[tc.current.applicationId]
props['color'] = color
return
except:
pass
try:
color = self.material_color_proxies[obj_display.applicationId]
props['color'] = color
return
except:
pass
# initialize Speckle Blue color # initialize Speckle Blue color
color = DEFAULT_COLOR color = DEFAULT_COLOR
opacity = None opacity = None
@@ -341,62 +304,25 @@ def assign_color(self: "SpeckleProvider", obj_display_tc: "TraversalContext", pr
obj_display = obj_display_tc.current obj_display = obj_display_tc.current
try: try:
# first, choose if get color from the parent obj or displayValue
if hasattr(obj_display, 'displayStyle') or hasattr(obj_display, '@displayStyle') or hasattr(obj_display, 'renderMaterial') or hasattr(obj_display, '@renderMaterial'):
obj_display = obj_display_tc.current
else:
# this option will be not very reliable:
# there could be different colors for diff displayValues in the list
if hasattr(obj_display, 'displayValue'):
try:
displayVal = obj_display['displayValue']
except:
displayVal = obj_display.displayValue
if isinstance(displayVal, list) and len(displayVal)>0:
obj_display = displayVal[0]
elif hasattr(obj_display, '@displayValue') and isinstance(obj_display['@displayValue'], list) and len(obj_display['@displayValue'])>0:
obj_display = obj_display['@displayValue'][0]
# prioritize renderMaterials for Meshes & Brep # prioritize renderMaterials for Meshes & Brep
if isinstance(obj_display, Mesh) or isinstance(obj_display, Brep): if isinstance(obj_display, Mesh) or isinstance(obj_display, Brep):
# print(obj_display.get_member_names()) # print(obj_display.get_member_names())
if hasattr(obj_display, 'renderMaterial'): if hasattr(obj_display, 'renderMaterial'):
try: color = obj_display['renderMaterial']['diffuse']
renderMaterial = obj_display['renderMaterial'] opacity = obj_display['renderMaterial']['opacity']
except:
renderMaterial = obj_display.renderMaterial
color = renderMaterial['diffuse']
opacity = renderMaterial['opacity']
elif hasattr(obj_display, '@renderMaterial'): elif hasattr(obj_display, '@renderMaterial'):
color = obj_display['@renderMaterial']['diffuse'] color = obj_display['@renderMaterial']['diffuse']
opacity = obj_display['@renderMaterial']['opacity'] opacity = obj_display['@renderMaterial']['opacity']
elif isinstance(obj_display, Mesh) and isinstance(obj_display.colors, List) and len(obj_display.colors)>1: elif isinstance(obj_display, Mesh) and isinstance(obj_display.colors, List) and len(obj_display.colors)>1:
colors_number = 0 sameColors = True
all_colors = [] color1 = obj_display.colors[0]
for c in obj_display.colors: for c in obj_display.colors:
if c not in all_colors: if c != color1:
colors_number += 1 sameColors = False
all_colors.append(c) break
if sameColors is True:
if colors_number>1: color = color1
all_a = 0
all_r = 0
all_g = 0
all_b = 0
for col in all_colors:
a, r, g, b = get_r_g_b(col)
all_a += a
all_r += r
all_g += g
all_b += b
color = (
(int(all_a/len(obj_display.colors)) << 24) + (int(all_r/len(obj_display.colors)) << 16)
+ (int(all_g/len(obj_display.colors)) << 8) + int(all_b/len(obj_display.colors))
)
else:
color = obj_display.colors[0]
elif hasattr(obj_display, 'displayStyle'): elif hasattr(obj_display, 'displayStyle'):
color = obj_display['displayStyle']['color'] color = obj_display['displayStyle']['color']
@@ -424,24 +350,6 @@ def assign_color(self: "SpeckleProvider", obj_display_tc: "TraversalContext", pr
# hex_color = '#%02x%02x%02x' % (r, g, b) # hex_color = '#%02x%02x%02x' % (r, g, b)
props['color'] = f'rgba({r},{g},{b},{a})' props['color'] = f'rgba({r},{g},{b},{a})'
# if still not found, check proxies:
if color == DEFAULT_COLOR:
for tc in getAllParents(obj_display_tc):
try:
color = self.material_color_proxies[tc.current.applicationId]
props['color'] = color
return
except:
pass
try:
color = self.material_color_proxies[obj_display.applicationId]
props['color'] = color
return
except:
pass
def get_r_g_b(rgb: int) -> Tuple[int, int, int]: def get_r_g_b(rgb: int) -> Tuple[int, int, int]:
"""Get R, G, B values from int.""" """Get R, G, B values from int."""
@@ -13,7 +13,7 @@ def initialize_features(self: "SpeckleProvider", all_coords, all_coord_counts, d
from specklepy.objects.graph_traversal.traversal import TraversalContext from specklepy.objects.graph_traversal.traversal import TraversalContext
from specklepy.objects.other import Collection from specklepy.objects.other import Collection
# print(f"Creating features..") print(f"Creating features..")
time1 = datetime.now() time1 = datetime.now()
all_props = [] all_props = []
@@ -79,14 +79,14 @@ def initialize_features(self: "SpeckleProvider", all_coords, all_coord_counts, d
obj_get_color_tc = TraversalContext(obj_get_color, "", item) obj_get_color_tc = TraversalContext(obj_get_color, "", item)
assign_display_properties(self, feature, f_base, obj_get_color_tc) assign_display_properties(self, feature, f_base, obj_get_color_tc)
feature["max_height"] = max([c[2] for c in coords]) feature["max_height"] = max([c[2] for c in coords])
feature["bbox"] = get_feature_bbox(coords) feature["bbox"] = get_feature_bbox(coords)
data["features"].append(feature) data["features"].append(feature)
feature_count += 1 feature_count += 1
else: else:
list_of_display_obj = find_list_of_display_obj(f_base) # tuple list_of_display_obj = find_list_of_display_obj(f_base)
for k, vals in enumerate(list_of_display_obj): for k, vals in enumerate(list_of_display_obj):
obj_display, obj_get_color = vals obj_display, obj_get_color = vals
@@ -120,7 +120,7 @@ def initialize_features(self: "SpeckleProvider", all_coords, all_coord_counts, d
all_coords.extend(coords) all_coords.extend(coords)
all_coord_counts.append(coord_counts) all_coord_counts.append(coord_counts)
obj_get_color_tc = TraversalContext(obj_display, "", item) obj_get_color_tc = TraversalContext(obj_get_color, "", item)
assign_display_properties(self, feature_new, f_base, obj_get_color_tc) assign_display_properties(self, feature_new, f_base, obj_get_color_tc)
feature_new["max_height"] = max([c[2] for c in coords]) feature_new["max_height"] = max([c[2] for c in coords])
@@ -169,13 +169,10 @@ def initialize_features(self: "SpeckleProvider", all_coords, all_coord_counts, d
######################## ########################
if len(data["features"])==0 and len(data["comments"])==0: if len(data["features"])==0 and len(data["comments"])==0:
raise ValueError(f"No supported features of type '{self.requested_data_type}' found. Make sure correct type is requested by adding a URL parameter (e.g. '&dataType=points').") raise ValueError("No supported features found")
time2 = datetime.now() time2 = datetime.now()
print(f"Creating features time: {(time2-time1).total_seconds()}")
time_operation = (time2-time1).total_seconds()
self.times["time_creating_features"] = time_operation
# print(f"Creating features time: {time_operation}")
def get_feature_bbox(coords) -> List[float]: def get_feature_bbox(coords) -> List[float]:
"""Get min max coordinates of the feature.""" """Get min max coordinates of the feature."""
-3
View File
@@ -1,3 +0,0 @@
COUNTRY_CODES = ["ru"]
STATES = ['Автономна Республіка Крим', 'Севастополь', 'Донецька область', 'Луганська область']
POSTCODES = [str(i) for i in range(95000,99999)]
@@ -31,7 +31,10 @@ def safe_json_loads(obj: str, obj_id=None) -> Any:
f" int error - falling back to json. \nError: {err}", f" int error - falling back to json. \nError: {err}",
SpeckleWarning, SpeckleWarning,
) )
return json.loads(obj) try:
return ujson.loads(obj[:-2])
except:
return json.loads(obj)
class BaseObjectSerializer: class BaseObjectSerializer:
@@ -324,6 +327,7 @@ class BaseObjectSerializer:
# make sure an obj was passed and create dict if string was somehow passed # make sure an obj was passed and create dict if string was somehow passed
if not obj: if not obj:
return return
if isinstance(obj, str): if isinstance(obj, str):
obj = safe_json_loads(obj) obj = safe_json_loads(obj)
+10 -13
View File
@@ -85,7 +85,7 @@ class ServerTransport(AbstractTransport):
self.url = url self.url = url
self.session = requests.Session() self.session = requests.Session()
if self.account.token is not None: if self.account.token is not None:
self._batch_sender = BatchSender( self._batch_sender = BatchSender(
self.url, self.stream_id, self.account.token, max_batch_size_mb=1 self.url, self.stream_id, self.account.token, max_batch_size_mb=1
@@ -157,28 +157,25 @@ class ServerTransport(AbstractTransport):
id for id in children_found_map if not children_found_map[id] id for id in children_found_map if not children_found_map[id]
] ]
# save headers and assign them back later
headers = self.session.headers
self.session.headers.update(
{
"Accept": "text/plain",
}
)
# Get the new children # Get the new children
endpoint = f"{self.url}/api/getobjects/{self.stream_id}" endpoint = f"{self.url}/api/getobjects/{self.stream_id}"
r = self.session.post( r = self.session.post(
endpoint, data={"objects": json.dumps(new_children_ids)}, stream=True endpoint, data={"objects": json.dumps(new_children_ids)}, stream=True
) )
r.encoding = "utf-8" r.encoding = "utf-8"
lines = r.iter_lines(decode_unicode=True) lines = r.iter_lines(decode_unicode=True, delimiter="},{")
self.session.headers = headers # return previous headers
# iter through returned objects saving them as we go # iter through returned objects saving them as we go
target_transport.begin_write() target_transport.begin_write()
for line in lines: all_lines = [line for _,line in enumerate(lines)]
for i, line in enumerate(all_lines):
if line: if line:
hash, obj = line.split("\t") hash = line.split('"id": "')[1].split('"')[0]
obj = "{" + line + "}"
if i==0:
obj = obj[2:]
elif i==len(all_lines)-1:
obj = obj[:-2]
target_transport.save_object(hash, obj) target_transport.save_object(hash, obj)
target_transport.save_object(id, root_obj_serialized) target_transport.save_object(id, root_obj_serialized)
@@ -169,7 +169,7 @@ def get_info_from_comment(comment: Dict, project_id: str, model_id: str) -> Tupl
res_id = model_id res_id = model_id
viewer_state = comment["viewerState"] viewer_state = comment["viewerState"]
if viewer_state is not None: # can be None for Replies if viewer_state is not None: # can be None for Replies
position: List[float] = viewer_state["ui"]["selection"] position: List[float] = viewer_state["ui"]["camera"]["target"]
try: try:
res_id = viewer_state["resources"]["request"]["resourceIdString"] res_id = viewer_state["resources"]["request"]["resourceIdString"]
except: except:
@@ -216,19 +216,4 @@ def get_attachment(project_id: str, attachment_id: str, attachment_name: str) ->
raise Exception( raise Exception(
f"Request not successful: Response code {r.status_code}" f"Request not successful: Response code {r.status_code}"
) )
def set_actions(self: "SpeckleProvider", client: "SpeckleClient", action: str = "GEO receive"):
from specklepy.logging.metrics import track
try:
full_dict = {**self.url_params, **self.times}
full_dict["GIS commit"] = self.commit_gis
full_dict["project_id"] = f"{self.project_id}"
full_dict["sourceHostApp"] = self.sourceApp
full_dict["model"] = f"{self.project_name}, {self.model_name}"
full_dict["time_TOTAL"] = sum([x[1] for x in self.times.items()])
full_dict["model_url"] = self.speckle_url
full_dict["model_country_code"] = self.country_code
track(action, client.account, full_dict)
except Exception as ex:
print(f"_Cannot set action '{action}': {ex}")
pass
+2 -17
View File
@@ -31,7 +31,6 @@ def get_set_url_parameters(self: "SpeckleProvider"):
requested_data_type = item.split("datatype=")[1] requested_data_type = item.split("datatype=")[1]
if requested_data_type in ["points", "lines", "polygons", "projectcomments"]: if requested_data_type in ["points", "lines", "polygons", "projectcomments"]:
self.requested_data_type = requested_data_type self.requested_data_type = requested_data_type
self.url_params["url_data_type"] = requested_data_type
except: except:
raise ValueError(f"Provide valid dataType parameter (points/lines/polygons/projectcomments): {item}") raise ValueError(f"Provide valid dataType parameter (points/lines/polygons/projectcomments): {item}")
@@ -40,7 +39,6 @@ def get_set_url_parameters(self: "SpeckleProvider"):
preserve_attributes = item.split("preserveattributes=")[1] preserve_attributes = item.split("preserveattributes=")[1]
if preserve_attributes in ["true", "false"]: if preserve_attributes in ["true", "false"]:
self.preserve_attributes = preserve_attributes self.preserve_attributes = preserve_attributes
self.url_params["url_preserve_attributes"] = preserve_attributes
except: except:
ValueError(f"Provide valid preserverAttributes parameter (true/false): {item}") ValueError(f"Provide valid preserverAttributes parameter (true/false): {item}")
@@ -49,27 +47,23 @@ def get_set_url_parameters(self: "SpeckleProvider"):
if isinstance(crs_authid, str) and len(crs_authid)>3: if isinstance(crs_authid, str) and len(crs_authid)>3:
crsauthid = True crsauthid = True
self.crs_authid = crs_authid self.crs_authid = crs_authid
self.url_params["url_crs_authid"] = crs_authid
elif "lat=" in item: elif "lat=" in item:
try: try:
lat = float(item.split("lat=")[1]) lat = float(item.split("lat=")[1])
self.lat = lat self.lat = lat
self.url_params["url_lat"] = lat
except: except:
raise ValueError(f"Invalid Lat input, must be numeric: {item}") raise ValueError(f"Invalid Lat input, must be numeric: {item}")
elif "lon=" in item: elif "lon=" in item:
try: try:
lon = float(item.split("lon=")[1]) lon = float(item.split("lon=")[1])
self.lon = lon self.lon = lon
self.url_params["url_lon"] = lon
except: except:
raise ValueError(f"Invalid Lon input, must be numeric: {item}") raise ValueError(f"Invalid Lon input, must be numeric: {item}")
elif "northdegrees=" in item: elif "northdegrees=" in item:
try: try:
north_degrees = float(item.split("northdegrees=")[1]) north_degrees = float(item.split("northdegrees=")[1])
self.north_degrees = north_degrees self.north_degrees = north_degrees
self.url_params["url_north_degrees"] = north_degrees
except: except:
raise ValueError(f"Invalid northDegrees input, must be numeric: {item}") raise ValueError(f"Invalid northDegrees input, must be numeric: {item}")
elif "limit=" in item: elif "limit=" in item:
@@ -77,15 +71,6 @@ def get_set_url_parameters(self: "SpeckleProvider"):
limit = int(item.split("limit=")[1]) limit = int(item.split("limit=")[1])
if limit>0: if limit>0:
self.limit = limit self.limit = limit
self.url_params["url_limit"] = limit
except:
ValueError(f"Invalid limit input, must be a positive integer: {item}")
elif "useragent=" in item:
try:
agent = item.split("useragent=")[1]
self.user_agent = agent
self.url_params["user_agent"] = agent
except: except:
ValueError(f"Invalid limit input, must be a positive integer: {item}") ValueError(f"Invalid limit input, must be a positive integer: {item}")
@@ -97,8 +82,8 @@ def get_set_url_parameters(self: "SpeckleProvider"):
if crsauthid: if crsauthid:
self.lat = str(self.lat) + " (not applied)" self.lat = str(self.lat) + " (not applied)"
self.lon = str(self.lon) + " (not applied)" self.lon = str(self.lon) + " (not applied)"
self.north_degrees = 0 # default to 0: rotation ignored when AuthId is used #str(self.north_degrees) + " (not applied)" self.north_degrees = str(self.north_degrees) + " (not applied)"
# if CRS parameter present, create and assign CRS: # if CRS parameter present, create and assign CRS:
if len(self.crs_authid)>3: if len(self.crs_authid)>3:
create_crs_from_authid(self, self.crs_authid) create_crs_from_authid(self)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

+5 -11
View File
@@ -71,7 +71,7 @@
<meta name="language" content="{{ config['server']['language'] }}"> <meta name="language" content="{{ config['server']['language'] }}">
<meta name="description" content="{{ config['metadata']['identification']['title'] }}"> <meta name="description" content="{{ config['metadata']['identification']['title'] }}">
<meta name="keywords" content="{{ config['metadata']['identification']['keywords']|join(',') }}"> <meta name="keywords" content="{{ config['metadata']['identification']['keywords']|join(',') }}">
<link rel="shortcut icon" href="https://github.com/specklesystems/pygeoapi/blob/dev/pygeoapi/static/img/speckle_geo.png" type="image/x-icon"> <link rel="shortcut icon" href="{{ config['server']['url'] }}/static/img/speckle_geo.png" type="image/x-icon">
<link rel="stylesheet" href="https://unpkg.com/bootstrap@5.1.3/dist/css/bootstrap.min.css"> <link rel="stylesheet" href="https://unpkg.com/bootstrap@5.1.3/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="{{ config['server']['url'] }}/static/css/default.css"> <link rel="stylesheet" href="{{ config['server']['url'] }}/static/css/default.css">
<!--[if lt IE 9]> <!--[if lt IE 9]>
@@ -109,9 +109,11 @@
title="{{ config['metadata']['identification']['title'] }}" style="height:30px;vertical-align: middle;" /> title="{{ config['metadata']['identification']['title'] }}" style="height:30px;vertical-align: middle;" />
<b style="text-align:left;padding-left: 10px;">Speckle</b> <b style="text-align:left;padding-left: 10px;">Speckle</b>
</a> </a>
<a href="https://geo.speckle.systems/" target="_blank" style="text-align:left;padding-left: 10px;" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-dark text-decoration-none"> <p style="text-align:left;padding-left: 10px;" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-dark text-decoration-none">
<a href="https://geo.speckle.systems/" target="_blank" style="text-align:left;padding-left: 10px;" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-dark text-decoration-none">
> Geolocating your data > Geolocating your data
</a> </a>
</p>
{% if (data["model"] and data["model"]!="") %} {% if (data["model"] and data["model"]!="") %}
<a href="{{data['speckle_project_url']}}" target="_blank" style="text-align:left;padding-left: 10px;" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-dark text-decoration-none"> <a href="{{data['speckle_project_url']}}" target="_blank" style="text-align:left;padding-left: 10px;" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-dark text-decoration-none">
> {{data["project"]}} > > {{data["project"]}} >
@@ -131,14 +133,6 @@
<ul class="nav nav-pills"> </ul> <ul class="nav nav-pills"> </ul>
</header> </header>
</div> </div>
<div style="max-height:fit-content;margin:0px;padding:0px;background-color: rgb(10,132,255);">
<p style="text-align: center; margin:0px;padding:5px;">
<a href = "https://docs.google.com/forms/d/e/1FAIpQLScKW2pkcWll3deXEwoV_G5ozLtuU06_prw8rf8HFuCk4tmOPQ/viewform?usp=sf_link"
style="color:rgb(255, 255, 255)" target="_blank">We would love to hear your feedback!</a>
</p>
</div>
</div> </div>
<div class="crumbs"> <div class="crumbs">
+10 -41
View File
@@ -202,7 +202,7 @@
<tr> <tr>
{% set title_field = data.title_field %} {% set title_field = data.title_field %}
<td data-label="{{ title_field }}"> <td data-label="{{ title_field }}">
<a title="{{ ft.properties.get(title_field) }}" href="{{data['speckle_url'].split('/models')[0]}}/models/{{ft.id.split('_')[0]}}" target="_blank"> <a title="{{ ft.properties.get(title_field) }}" href="{{ data['speckle_project_url'] }}/models/{{ft.id.split('_')[0]}}" target="_blank">
{{ ft.properties.get(title_field) | string | truncate( 35 ) }} {{ ft.properties.get(title_field) | string | truncate( 35 ) }}
</a> </a>
</td> </td>
@@ -335,11 +335,7 @@
{% block extrafoot %} {% block extrafoot %}
<script> <script>
try { document.getElementById("loading_screen").remove();
document.getElementById("loading_screen").remove();
document.getElementById("loading_screen_band").remove();
}
catch(err) {}
// attach even to modeSwitch btn // attach even to modeSwitch btn
document.getElementById("modeSwitch").onclick = switchMode; document.getElementById("modeSwitch").onclick = switchMode;
@@ -396,21 +392,14 @@
L.control.zoom({ L.control.zoom({
position: 'topright' position: 'topright'
}).addTo(map); }).addTo(map);
var tileLayer = new L.TileLayer( map.addLayer(new L.TileLayer(
'{{ config['server']['map']['url'] }}', { '{{ config['server']['map']['url'] }}', {
maxZoom: 22, maxZoom: 22,
minZoom: 12,
attribution: '{{ config['server']['map']['attribution'] | safe }} &copy; Data: <a href="https://speckle.systems/">Speckle Systems</a>' attribution: '{{ config['server']['map']['attribution'] | safe }} &copy; Data: <a href="https://speckle.systems/">Speckle Systems</a>'
} }
); ));
geojson_data = split_polygons(geojson_data_original); geojson_data = split_polygons(geojson_data_original);
project_url = ""
try {
project_url = data['speckle_url'].split("/models")[0]
}
catch(err) {}
var items = new L.GeoJSON(geojson_data, { var items = new L.GeoJSON(geojson_data, {
filter: (feature) => { filter: (feature) => {
@@ -420,7 +409,7 @@
return new L.circleMarker(latlng) return new L.circleMarker(latlng)
}, },
onEachFeature: function (feature, layer) { onEachFeature: function (feature, layer) {
var url = project_url + '/models/' + feature.id.split("_")[0] var url = '{{ data['speckle_project_url'] }}/models/' + feature.id.split("_")[0]
var html = '<span><td><p>' + feature['properties']['speckle_type'] + '</p></td><a href="' + url + '" target="_blank">' + feature['properties']['id'].split("_")[0] + '</a></span>'; var html = '<span><td><p>' + feature['properties']['speckle_type'] + '</p></td><a href="' + url + '" target="_blank">' + feature['properties']['id'].split("_")[0] + '</a></span>';
layer.bindPopup(html); layer.bindPopup(html);
@@ -446,37 +435,18 @@
return new L.marker(latlng) return new L.marker(latlng)
}, },
onEachFeature: function (feature, layer) { onEachFeature: function (feature, layer) {
var url = project_url + '/models/' + feature.properties.resource_id + '#threadId=' + feature.id; var url = '{{ data['speckle_project_url'] }}/models/' + feature.properties.resource_id + '#threadId=' + feature.id;
var html = '<span><td><a href="' + url + '" target="_blank">Go to thread</a></td> <td><p>' + feature['properties']['text_html'] + '</p></td> </span>'; var html = '<span><td><a href="' + url + '" target="_blank">Go to thread</a></td> <td><p>' + feature['properties']['text_html'] + '</p></td> </span>';
layer.bindPopup(html); layer.bindPopup(html);
} }
}); //.addTo(map); }); //.addTo(map);
var group = L.featureGroup([items, comments]);
// load proper basemap for Speckle models; but only zoomed-out one for empty data
try
{
bounds = group.getBounds();
map.fitBounds(bounds);
tileLayer.addTo(map); var group = L.featureGroup([items, comments])
group.addTo(map); .addTo(map);
}
catch (err){
tileLayer = new L.TileLayer(
'{{ config['server']['map']['url'] }}', {
maxZoom: 2,
minZoom: 2,
attribution: '{{ config['server']['map']['attribution'] | safe }} &copy; Data: <a href="https://speckle.systems/">Speckle Systems</a>'
}
);
tileLayer.addTo(map);
}
//map.addLayer(lines); //map.addLayer(lines);
map.fitBounds(group.getBounds());
// map.setZoom(19); // in order for the tiles to load // map.setZoom(19); // in order for the tiles to load
}; };
@@ -705,7 +675,6 @@
longitude: extent[0] + (extent[2]-extent[0])/2, longitude: extent[0] + (extent[2]-extent[0])/2,
latitude: extent[1] + (extent[3]-extent[1])/2, latitude: extent[1] + (extent[3]-extent[1])/2,
zoom: 22, zoom: 22,
minZoom: 12,
pitch: 60, pitch: 60,
bearing: 1.469387755102039 bearing: 1.469387755102039
}, },
+1 -4
View File
@@ -9,10 +9,7 @@
</body> </body>
<script> <script>
try { document.getElementById("loading_screen").remove();
document.getElementById("loading_screen").remove();
}
catch(err) {}
</script> </script>
</html> </html>
+1 -4
View File
@@ -6,9 +6,6 @@
<p>{{ data['description'] }}</p> <p>{{ data['description'] }}</p>
</section> </section>
<script> <script>
try { document.getElementById("loading_screen").remove();
document.getElementById("loading_screen").remove();
}
catch(err) {}
</script> </script>
{% endblock %} {% endblock %}
+3 -13
View File
@@ -1,21 +1,11 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head>
<link rel="stylesheet" href="https://unpkg.com/bootstrap@5.1.3/dist/css/bootstrap.min.css">
</head>
<body> <body>
<div id="loading_screen_band" style="position:absolute;z-index:-1;width:100%;max-height:fit-content;margin:0px;padding:0px;background-color: rgb(10,132,255);">
<p style="text-align: center; margin:0px;padding:15px;">
<a href = "https://docs.google.com/forms/d/e/1FAIpQLScKW2pkcWll3deXEwoV_G5ozLtuU06_prw8rf8HFuCk4tmOPQ/viewform?usp=sf_link"
style="color:rgb(255, 255, 255)" target="_blank">Why not share a feedback while waiting?</a>
</p>
</div>
<div id="loading_screen" style="position: absolute;top:100px;left:0;right:0;width: fit-content;margin-inline: auto;height:200px;"> <div id="loading_screen" style="position: absolute;top:100px;left:0;right:0;width: fit-content;margin-inline: auto;height:200px;">
<img style="height:200px;width:218.6px" src="https://raw.githubusercontent.com/specklesystems/pygeoapi/dev/pygeoapi/static/img/speckle_cube_loading_winter.gif" alt="Loading data.." > <img style="height:200px;width:218.6px" src="https://raw.githubusercontent.com/specklesystems/pygeoapi/dev/pygeoapi/static/img/speckle_cube_loading.gif" alt="Loading data.." >
<h3 style="margin-bottom: 0px;text-align: center; color:rgb(40, 127, 209);font-size: x-large;">"I'm on my way!"</h3> <h3 style="margin-bottom: 0px;font-family: 'Verdana'; text-align: center; color:rgb(40, 127, 209);font-size: x-large;">"I'm on my way!"</h3>
<p style="text-align: right; color:rgb(40, 127, 209)">- your data </p> <p style="font-family: 'Verdana'; text-align: right; color:rgb(40, 127, 209)">- your data </p>
</div> </div>
</body> </body>
-2
View File
@@ -2,7 +2,6 @@ Babel
click click
filelock filelock
Flask Flask
geopy==2.4.1
jinja2 jinja2
jsonschema jsonschema
pydantic<2.0 pydantic<2.0
@@ -18,4 +17,3 @@ shapely
SQLAlchemy<2.0.0 SQLAlchemy<2.0.0
tinydb tinydb
unicodecsv unicodecsv
specklepy==2.19.6
+1 -1
View File
@@ -86,7 +86,7 @@
}); });
// construnt data URL // construnt data URL
var link = "https://geo.speckle.systems/speckle/?speckleUrl="; var link = "https://geo.speckle.systems/?speckleUrl=";
if (document.getElementById("speckle_model").value!=""){ if (document.getElementById("speckle_model").value!=""){
link += document.getElementById("speckle_model").value.replace(" ", "") link += document.getElementById("speckle_model").value.replace(" ", "")
} }
+1 -1
View File
@@ -34,7 +34,7 @@
)); ));
(async () => { (async () => {
const speckle_data = await fetch('https://geo.speckle.systems/speckle/?speckleUrl=https://app.speckle.systems/projects/344f803f81/models/5582ab673e&datatype=projectcomments', { const speckle_data = await fetch('https://geo.speckle.systems/?speckleUrl=https://app.speckle.systems/projects/344f803f81/models/5582ab673e&datatype=projectcomments', {
headers: { headers: {
'Accept': 'application/geo+json' 'Accept': 'application/geo+json'
} }
+1 -1
View File
@@ -34,7 +34,7 @@
)); ));
(async () => { (async () => {
const speckle_data = await fetch('https://geo.speckle.systems/speckle/?speckleUrl=https://app.speckle.systems/projects/344f803f81/models/5582ab673e&datatype=polygons', { const speckle_data = await fetch('https://geo.speckle.systems/?speckleUrl=https://app.speckle.systems/projects/344f803f81/models/5582ab673e&datatype=polygons', {
headers: { headers: {
'Accept': 'application/geo+json' 'Accept': 'application/geo+json'
} }
+2 -2
View File
@@ -32,7 +32,7 @@
(async () => { (async () => {
const speckle_data2 = await fetch('https://geo.speckle.systems/speckle/?speckleUrl=https://app.speckle.systems/projects/344f803f81/models/37d93c5d32&preserveAttributes=true', { const speckle_data2 = await fetch('https://geo.speckle.systems/?speckleUrl=https://app.speckle.systems/projects/344f803f81/models/37d93c5d32&preserveAttributes=true', {
//const speckle_data = await fetch('http://localhost:5000/?speckleUrl=https://app.speckle.systems/projects/64753f52b7/models/338b386787&limit=1000000&lat=-0.031405&lon=109.335828&preserveAttributes=true', { //const speckle_data = await fetch('http://localhost:5000/?speckleUrl=https://app.speckle.systems/projects/64753f52b7/models/338b386787&limit=1000000&lat=-0.031405&lon=109.335828&preserveAttributes=true', {
headers: { headers: {
'Accept': 'application/geo+json' 'Accept': 'application/geo+json'
@@ -155,7 +155,7 @@
//map.fitBounds(speckle_layer.getBounds()) //map.fitBounds(speckle_layer.getBounds())
const speckle_data = await fetch('https://geo.speckle.systems/speckle/?speckleUrl=https://app.speckle.systems/projects/344f803f81/models/5582ab673e&datatype=projectcomments', { const speckle_data = await fetch('https://geo.speckle.systems/?speckleUrl=https://app.speckle.systems/projects/344f803f81/models/5582ab673e&datatype=projectcomments', {
//const speckle_data = await fetch('http://localhost:5000/?speckleUrl=https://app.speckle.systems/projects/64753f52b7/models/338b386787&limit=1000000&lat=-0.031405&lon=109.335828&preserveAttributes=true', { //const speckle_data = await fetch('http://localhost:5000/?speckleUrl=https://app.speckle.systems/projects/64753f52b7/models/338b386787&limit=1000000&lat=-0.031405&lon=109.335828&preserveAttributes=true', {
headers: { headers: {
'Accept': 'application/geo+json' 'Accept': 'application/geo+json'
+4 -4
View File
@@ -30,12 +30,12 @@
}); });
(async () => { (async () => {
//const speckle_data = await fetch('https://geo.speckle.systems/speckle/?speckleUrl=https://app.speckle.systems/projects/344f803f81/models/5582ab673e&datatype=projectcomments', { //const speckle_data = await fetch('https://geo.speckle.systems/?speckleUrl=https://app.speckle.systems/projects/344f803f81/models/5582ab673e&datatype=projectcomments', {
//var speckle_url = 'http://localhost:5000/speckle/?speckleUrl=https://app.speckle.systems/projects/5feae56049/models/9c43d7569c&limit=1000000&datatype=polygons&preserveattributes=false'; //var speckle_url = 'http://localhost:5000/?speckleUrl=https://app.speckle.systems/projects/5feae56049/models/9c43d7569c&limit=1000000&datatype=polygons&preserveattributes=false';
// https://app.speckle.systems/projects/5feae56049/models/01c4183677 // https://app.speckle.systems/projects/5feae56049/models/01c4183677
var speckle_url = 'https://geo.speckle.systems/speckle/?speckleUrl=https://app.speckle.systems/projects/5feae56049/models/01c4183677&limit=1000000&datatype=polygons&preserveattributes=true'; var speckle_url = 'http://localhost:5000/?speckleUrl=https://app.speckle.systems/projects/5feae56049/models/01c4183677&limit=1000000&datatype=polygons&preserveattributes=true';
//var speckle_url = 'https://geo.speckle.systems/speckle/?speckleUrl=https://app.speckle.systems/projects/5feae56049/models/9c43d7569c&northDegrees=-30&preserveAttributes=true'; //var speckle_url = 'https://geo.speckle.systems/?speckleUrl=https://app.speckle.systems/projects/5feae56049/models/9c43d7569c&northDegrees=-30&preserveAttributes=true';
const speckle_data = await fetch(speckle_url, { const speckle_data = await fetch(speckle_url, {
headers: { headers: {
'Accept': 'application/geo+json' 'Accept': 'application/geo+json'
@@ -65,7 +65,7 @@
//////// add Speckle layer //////// add Speckle layer
(async () => { (async () => {
const geojson = await fetch('https://geo.speckle.systems/speckle/?speckleUrl=https://app.speckle.systems/projects/344f803f81/models/5582ab673e&datatype=polygons', { const geojson = await fetch('https://geo.speckle.systems/?speckleUrl=https://app.speckle.systems/projects/344f803f81/models/5582ab673e&datatype=polygons', {
headers: { headers: {
'Accept': 'application/geo+json' 'Accept': 'application/geo+json'
} }
-8
View File
@@ -1,8 +0,0 @@
source .venv/bin/activate
export PYGEOAPI_CONFIG="example-config.yml"
export PYGEOAPI_OPENAPI="example-openapi.yml"
export MAPTILER_KEY_SPECKLE="qam9vwl7bVk5tW1oZu46"
export PORT=8000
gunicorn pygeoapi.flask_app:APP --timeout 100000 --access-logfile access_log --error-logfile error_log --capture-output