more refactor
This commit is contained in:
+20
-128
@@ -346,8 +346,11 @@ class SpeckleProvider(BaseProvider):
|
||||
def __repr__(self):
|
||||
return f"<SpeckleProvider> {self.data}"
|
||||
|
||||
def load_speckle_data(self: str):
|
||||
|
||||
def load_speckle_data(self: str) -> Dict:
|
||||
"""Receive and process Speckle data, return geojson."""
|
||||
|
||||
from pygeoapi.provider.speckle_utils.server_utils import get_stream_branch, get_client
|
||||
|
||||
from specklepy.logging.exceptions import SpeckleException
|
||||
from specklepy.api import operations
|
||||
from specklepy.core.api.wrapper import StreamWrapper
|
||||
@@ -364,22 +367,9 @@ class SpeckleProvider(BaseProvider):
|
||||
# set actual branch
|
||||
wrapper.model_id = self.speckle_url.split("models/")[1].split("/")[0].split("&")[0]
|
||||
|
||||
# get client by URL, no authentication
|
||||
client = SpeckleClient(host=wrapper.host, use_ssl=wrapper.host.startswith("https"))
|
||||
client.account.serverInfo.url = url_proj.split("/projects")[0]
|
||||
|
||||
# get branch data
|
||||
stream = client.stream.get(
|
||||
id = wrapper.stream_id, branch_limit=100
|
||||
)
|
||||
|
||||
if isinstance(stream, Exception):
|
||||
raise SpeckleException(stream.message+ ", "+ self.speckle_url)
|
||||
|
||||
for br in stream['branches']['items']:
|
||||
if br['id'] == wrapper.model_id:
|
||||
branch = br
|
||||
break
|
||||
# get stream and branch data
|
||||
client = get_client(wrapper, url_proj)
|
||||
stream, branch = get_stream_branch(self, client, wrapper)
|
||||
|
||||
# set the Model name
|
||||
self.model_name = branch['name']
|
||||
@@ -391,7 +381,7 @@ class SpeckleProvider(BaseProvider):
|
||||
if transport == None:
|
||||
raise SpeckleException("Transport not found")
|
||||
|
||||
# data transfer
|
||||
# receive commit
|
||||
try:
|
||||
commit_obj = operations.receive(objId, transport, None)
|
||||
except Exception as ex:
|
||||
@@ -404,18 +394,19 @@ class SpeckleProvider(BaseProvider):
|
||||
source_application="pygeoapi",
|
||||
message="Received commit in pygeoapi",
|
||||
)
|
||||
print(f"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)
|
||||
|
||||
speckle_data["project"] = stream['name']
|
||||
speckle_data["model"] = branch['name']
|
||||
|
||||
return speckle_data
|
||||
|
||||
def traverse_data(self, commit_obj):
|
||||
def traverse_data(self, commit_obj) -> Dict:
|
||||
"""Traverse Speckle commit and return geojson with features."""
|
||||
|
||||
from specklepy.objects.geometry import Point, Line, Polyline, Curve, Mesh, Brep
|
||||
from specklepy.objects.GIS.CRS import CRS
|
||||
from specklepy.objects.GIS.layers import VectorLayer
|
||||
from specklepy.objects.GIS.geometry import GisPolygonElement
|
||||
from specklepy.objects.GIS.GisFeature import GisFeature
|
||||
@@ -423,11 +414,9 @@ class SpeckleProvider(BaseProvider):
|
||||
GraphTraversal,
|
||||
TraversalRule,
|
||||
)
|
||||
from pygeoapi.provider.speckle_utils.crs_utils import create_crs_from_wkt, create_crs_default, create_crs_dict
|
||||
from pygeoapi.provider.speckle_utils.coords_utils import reproject_bulk
|
||||
from pygeoapi.provider.speckle_utils.props_utils import assign_props, assign_missing_props
|
||||
from pygeoapi.provider.speckle_utils.converter_utils import assign_geometry
|
||||
from pygeoapi.provider.speckle_utils.display_utils import find_display_obj, set_default_color, assign_display_properties, get_display_units
|
||||
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.display_utils import set_default_color
|
||||
|
||||
supported_classes = [GisFeature, GisPolygonElement, Mesh, Brep, Point, Line, Polyline, Curve]
|
||||
supported_types = [y().speckle_type for y in supported_classes]
|
||||
@@ -447,7 +436,6 @@ class SpeckleProvider(BaseProvider):
|
||||
"features": [],
|
||||
"model_crs": "-",
|
||||
}
|
||||
self.assign_coordinate_system_to_geojson(data)
|
||||
rule = TraversalRule(
|
||||
[lambda _: True],
|
||||
lambda x: [
|
||||
@@ -459,111 +447,15 @@ class SpeckleProvider(BaseProvider):
|
||||
)
|
||||
context_list = [x for x in GraphTraversal([rule]).traverse(commit_obj)]
|
||||
|
||||
# iterate Speckle objects to get CRS, DisplayUnits, offsets, rotation
|
||||
crs = None
|
||||
displayUnits = None
|
||||
offset_x = 0
|
||||
offset_y = 0
|
||||
try:
|
||||
for item in [commit_obj] + commit_obj.elements:
|
||||
if (
|
||||
crs is None
|
||||
and hasattr(item, "crs")
|
||||
and isinstance(item["crs"], CRS)
|
||||
):
|
||||
crs = item["crs"]
|
||||
displayUnits = crs["units_native"]
|
||||
offset_x = crs["offset_x"]
|
||||
offset_y = crs["offset_y"]
|
||||
self.north_degrees = crs["rotation"]
|
||||
create_crs_from_wkt(self, crs["wkt"])
|
||||
|
||||
if self.crs.to_authority() is not None:
|
||||
data["model_crs"] = f"{self.crs.to_authority()}, {self.crs.name} "
|
||||
else:
|
||||
data["model_crs"] = f"{self.crs.to_proj4()}"
|
||||
|
||||
break
|
||||
except AttributeError as ex:
|
||||
pass # old commit structure
|
||||
|
||||
# if CRS not found, create default one and get model units for scaling
|
||||
if self.crs is None:
|
||||
create_crs_default(self)
|
||||
# if displayUnits not found, get from displayable object
|
||||
if displayUnits is None:
|
||||
displayUnits = get_display_units(context_list)
|
||||
|
||||
create_crs_dict(self, offset_x, offset_y, displayUnits)
|
||||
|
||||
# get coordinates in bulk
|
||||
all_coords = []
|
||||
all_coord_counts = []
|
||||
|
||||
|
||||
all_props = []
|
||||
get_set_crs_settings(self, commit_obj, context_list, data)
|
||||
set_default_color(context_list)
|
||||
|
||||
print(f"Loading features..")
|
||||
time1 = datetime.now()
|
||||
for item in context_list:
|
||||
|
||||
f_base = item.current
|
||||
f_id = item.current.id
|
||||
f_fid = len(data["features"]) + 1
|
||||
|
||||
# initialize feature
|
||||
feature: Dict = {
|
||||
"type": "Feature",
|
||||
# "bbox": [-180.0, -90.0, 180.0, 90.0],
|
||||
"geometry": {},
|
||||
"properties": {
|
||||
"id": f_id,
|
||||
"FID": f_fid,
|
||||
"speckle_type": item.current.speckle_type.split(":")[-1],
|
||||
},
|
||||
}
|
||||
|
||||
# feature geometry, props and displayProps
|
||||
obj_display, obj_get_color = find_display_obj(f_base)
|
||||
coords, coord_counts = assign_geometry(feature, obj_display)
|
||||
if len(coords)!=0:
|
||||
all_coords.extend(coords)
|
||||
all_coord_counts.append(coord_counts)
|
||||
|
||||
assign_props(f_base, feature["properties"])
|
||||
# update list of all properties
|
||||
for prop in feature["properties"]:
|
||||
if prop not in all_props:
|
||||
all_props.append(prop)
|
||||
|
||||
assign_display_properties(feature, f_base, obj_get_color)
|
||||
data["features"].append(feature)
|
||||
|
||||
assign_missing_props(data["features"], all_props)
|
||||
|
||||
if len(data["features"])==0:
|
||||
raise ValueError("No supported features found")
|
||||
|
||||
time2 = datetime.now()
|
||||
print(f"Loading features before reprojecting time: {(time2-time1).total_seconds()}")
|
||||
|
||||
reproject_bulk(self, all_coords, all_coord_counts, [f["geometry"] for f in data["features"]])
|
||||
create_features(self, context_list, data)
|
||||
|
||||
return data
|
||||
|
||||
def assign_coordinate_system_to_geojson(self, data: Dict):
|
||||
def get_python_path(self) -> str:
|
||||
"""Get current Python executable path."""
|
||||
|
||||
crs = {
|
||||
"crs": {
|
||||
"type": "name",
|
||||
"properties": {"name": "urn:ogc:def:crs:OGC:1.3:CRS84"},
|
||||
}
|
||||
}
|
||||
|
||||
data["crs"] = crs
|
||||
|
||||
def get_python_path(self):
|
||||
if sys.platform.startswith("linux"):
|
||||
return sys.executable
|
||||
pythonExec = os.path.dirname(sys.executable)
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
|
||||
from typing import Dict, List
|
||||
|
||||
|
||||
def create_crs_from_wkt(self: "SpeckleProvider", wkt: str | None) -> None:
|
||||
"""Create and assign CRS object from WKT string."""
|
||||
|
||||
@@ -25,7 +28,7 @@ def create_crs_default(self: "SpeckleProvider") -> None:
|
||||
self.crs = crs_obj
|
||||
|
||||
def create_crs_dict(self: "SpeckleProvider", offset_x, offset_y, displayUnits: str | None) -> None:
|
||||
"""Create and assign CRS object from WKT string."""
|
||||
"""Create and assign CRS_dict of SpeckleProvider."""
|
||||
|
||||
if self.crs is not None:
|
||||
self.crs_dict = {
|
||||
@@ -37,3 +40,62 @@ def create_crs_dict(self: "SpeckleProvider", offset_x, offset_y, displayUnits: s
|
||||
"obj": self.crs,
|
||||
}
|
||||
|
||||
|
||||
def get_set_crs_settings(self: "SpeckleProvider", commit_obj: "Base", context_list: List["TraversalContext"], data: Dict) -> None:
|
||||
"""Assign CRS object and Dict to SpeckleProvider."""
|
||||
|
||||
from pygeoapi.provider.speckle_utils.display_utils import get_display_units
|
||||
from specklepy.objects.GIS.CRS import CRS
|
||||
|
||||
assign_coordinate_system_to_geojson(data)
|
||||
|
||||
root_objects = []
|
||||
try:
|
||||
root_objects = [commit_obj] + commit_obj.elements
|
||||
except AttributeError as ex:
|
||||
pass # old commit structure
|
||||
|
||||
# iterate Speckle objects to get CRS, DisplayUnits, offsets, rotation
|
||||
crs = None
|
||||
displayUnits = None
|
||||
offset_x = 0
|
||||
offset_y = 0
|
||||
|
||||
for item in root_objects:
|
||||
if (
|
||||
crs is None
|
||||
and hasattr(item, "crs")
|
||||
and isinstance(item["crs"], CRS)
|
||||
):
|
||||
crs = item["crs"]
|
||||
displayUnits = crs["units_native"]
|
||||
offset_x = crs["offset_x"]
|
||||
offset_y = crs["offset_y"]
|
||||
self.north_degrees = crs["rotation"]
|
||||
create_crs_from_wkt(self, crs["wkt"])
|
||||
|
||||
if self.crs.to_authority() is not None:
|
||||
data["model_crs"] = f"{self.crs.to_authority()}, {self.crs.name} "
|
||||
else:
|
||||
data["model_crs"] = f"{self.crs.to_proj4()}"
|
||||
break
|
||||
|
||||
# if CRS not found, create default one and get model units for scaling
|
||||
if self.crs is None:
|
||||
create_crs_default(self)
|
||||
if displayUnits is None:
|
||||
displayUnits = get_display_units(context_list)
|
||||
|
||||
create_crs_dict(self, offset_x, offset_y, displayUnits)
|
||||
|
||||
|
||||
|
||||
def assign_coordinate_system_to_geojson(data: Dict):
|
||||
|
||||
crs = {
|
||||
"crs": {
|
||||
"type": "name",
|
||||
"properties": {"name": "urn:ogc:def:crs:OGC:1.3:CRS84"},
|
||||
}
|
||||
}
|
||||
data["crs"] = crs
|
||||
|
||||
@@ -51,7 +51,6 @@ def find_display_obj(obj) -> Tuple["Base", "Base"]:
|
||||
displayValForColor = mesh
|
||||
|
||||
displayVal = displayValForColor
|
||||
print(displayValForColor)
|
||||
|
||||
# if not searching for colored object, return GisFeatures as is
|
||||
if obj.speckle_type.endswith(".GisFeature"):
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Dict, List
|
||||
|
||||
|
||||
def initialize_features(all_coords, all_coord_counts, data, context_list) -> None:
|
||||
"""Create features with props and displayProps, and assign flat list of coordinates."""
|
||||
|
||||
from pygeoapi.provider.speckle_utils.props_utils import assign_props, assign_missing_props
|
||||
from pygeoapi.provider.speckle_utils.converter_utils import assign_geometry
|
||||
from pygeoapi.provider.speckle_utils.display_utils import find_display_obj, assign_display_properties
|
||||
|
||||
print(f"Creating features..")
|
||||
time1 = datetime.now()
|
||||
|
||||
all_props = []
|
||||
|
||||
for item in context_list:
|
||||
|
||||
f_base = item.current
|
||||
f_id = item.current.id
|
||||
f_fid = len(data["features"]) + 1
|
||||
|
||||
# initialize feature
|
||||
feature: Dict = {
|
||||
"type": "Feature",
|
||||
# "bbox": [-180.0, -90.0, 180.0, 90.0],
|
||||
"geometry": {},
|
||||
"properties": {
|
||||
"id": f_id,
|
||||
"FID": f_fid,
|
||||
"speckle_type": item.current.speckle_type.split(":")[-1],
|
||||
},
|
||||
}
|
||||
|
||||
# feature geometry, props and displayProps
|
||||
obj_display, obj_get_color = find_display_obj(f_base)
|
||||
coords, coord_counts = assign_geometry(feature, obj_display)
|
||||
if len(coords)!=0:
|
||||
all_coords.extend(coords)
|
||||
all_coord_counts.append(coord_counts)
|
||||
|
||||
assign_props(f_base, feature["properties"])
|
||||
# update list of all properties
|
||||
for prop in feature["properties"]:
|
||||
if prop not in all_props:
|
||||
all_props.append(prop)
|
||||
|
||||
assign_display_properties(feature, f_base, obj_get_color)
|
||||
data["features"].append(feature)
|
||||
|
||||
assign_missing_props(data["features"], all_props)
|
||||
|
||||
if len(data["features"])==0:
|
||||
raise ValueError("No supported features found")
|
||||
|
||||
time2 = datetime.now()
|
||||
print(f"Creating features time: {(time2-time1).total_seconds()}")
|
||||
|
||||
def create_features(self: "SpeckleProvider", context_list: List["TraversalContext"], data: Dict) -> None:
|
||||
"""Create features from the list of traversal context."""
|
||||
|
||||
from pygeoapi.provider.speckle_utils.coords_utils import reproject_bulk
|
||||
|
||||
all_coords = []
|
||||
all_coord_counts = []
|
||||
initialize_features(all_coords, all_coord_counts, data, context_list)
|
||||
reproject_bulk(self, all_coords, all_coord_counts, [f["geometry"] for f in data["features"]])
|
||||
@@ -0,0 +1,31 @@
|
||||
from typing import Tuple
|
||||
|
||||
|
||||
def get_stream_branch(self: "SpeckleProvider", client: "SpeckleClient", wrapper: "StreamWrapper") -> Tuple:
|
||||
"""Get stream and branch from the server."""
|
||||
|
||||
from specklepy.logging.exceptions import SpeckleException
|
||||
|
||||
branch = None
|
||||
stream = client.stream.get(
|
||||
id = wrapper.stream_id, branch_limit=100
|
||||
)
|
||||
|
||||
if isinstance(stream, Exception):
|
||||
raise SpeckleException(stream.message+ ", "+ self.speckle_url)
|
||||
|
||||
for br in stream['branches']['items']:
|
||||
if br['id'] == wrapper.model_id:
|
||||
branch = br
|
||||
break
|
||||
return stream, branch
|
||||
|
||||
def get_client(wrapper: "StreamWrapper", url_proj: str) -> "SpeckleClient":
|
||||
"""Get unauthenticated SpeckleClient."""
|
||||
|
||||
from specklepy.core.api.client import SpeckleClient
|
||||
|
||||
# get client by URL, no authentication
|
||||
client = SpeckleClient(host=wrapper.host, use_ssl=wrapper.host.startswith("https"))
|
||||
client.account.serverInfo.url = url_proj.split("/projects")[0]
|
||||
return client
|
||||
Reference in New Issue
Block a user