Skip to content

Commit

Permalink
Merge branch 'main' into gergo/abstract_transport_no_pydantic
Browse files Browse the repository at this point in the history
  • Loading branch information
gjedlicska authored Sep 7, 2023
2 parents 52d53db + 65048cd commit b5fb684
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 166 deletions.
28 changes: 7 additions & 21 deletions src/specklepy/objects/GIS/CRS.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,12 @@
class CRS(Base, speckle_type="Objects.GIS.CRS"):
"""A Coordinate Reference System stored in wkt format"""

def __init__(
self,
name: Optional[str] = None,
authority_id: Optional[str] = None,
wkt: Optional[str] = None,
units: Optional[str] = None,
units_native: Optional[str] = None,
offset_x: Optional[float] = None,
offset_y: Optional[float] = None,
rotation: Optional[float] = None,
**kwargs
) -> None:
super().__init__(**kwargs)
name: Optional[str] = None
authority_id: Optional[str] = None
wkt: Optional[str] = None
units_native: Optional[str] = None
offset_x: Optional[float] = None
offset_y: Optional[float] = None
rotation: Optional[float] = None

self.name = name
self.authority_id = authority_id
self.wkt = wkt
self.units = units or "m"
self.units_native = units_native
self.offset_x = offset_x
self.offset_y = offset_y
self.rotation = rotation

109 changes: 29 additions & 80 deletions src/specklepy/objects/GIS/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,99 +6,48 @@

class GisPolygonGeometry(Base, speckle_type="Objects.GIS.PolygonGeometry", detachable={"displayValue"}):
"""GIS Polygon Geometry"""

def __init__(
self,
boundary: Optional[Union[Polyline, Arc, Line, Circle, Polycurve]] = None,
voids: Optional[List[Union[Polyline, Arc, Line, Circle, Polycurve]] ] = None,
displayValue: Optional[List[Mesh]] = None,
units: Optional[str] = None,
**kwargs
) -> None:
super().__init__(**kwargs)

self.boundary = boundary
self.voids = voids
self.displayValue = displayValue
self.units = units or "m"
boundary: Optional[Union[Polyline, Arc, Line, Circle, Polycurve]] = None
voids: Optional[List[Union[Polyline, Arc, Line, Circle, Polycurve]] ] = None
displayValue: Optional[List[Mesh]] = None

class GisPolygonElement(Base, speckle_type="Objects.GIS.PolygonElement"):
"""GIS Polygon element"""

def __init__(
self,
geometry: Optional[List[GisPolygonGeometry]] = None,
attributes: Optional[Base] = None,
units: Optional[str] = None,
**kwargs
) -> None:
super().__init__(**kwargs)

self.geometry = geometry
self.attributes = attributes
self.units = units or "m"
geometry: Optional[List[GisPolygonGeometry]] = None
attributes: Optional[Base] = None

class GisLineElement(Base, speckle_type="Objects.GIS.LineElement"):
"""GIS Polyline element"""

def __init__(
self,
geometry: Optional[List[Union[Polyline, Arc, Line, Circle, Polycurve]]] = None,
attributes: Optional[Base] = None,
units: Optional[str] = None,
**kwargs
) -> None:
super().__init__(**kwargs)

self.geometry = geometry
self.attributes = attributes
self.units = units or "m"

geometry: Optional[List[Union[Polyline, Arc, Line, Circle, Polycurve]]] = None,
attributes: Optional[Base] = None,

class GisPointElement(Base, speckle_type="Objects.GIS.PointElement"):
"""GIS Point element"""

def __init__(
self,
geometry: Optional[List[Point]] = None,
attributes: Optional[Base] = None,
units: Optional[str] = None,
**kwargs
) -> None:
super().__init__(**kwargs)

self.geometry = geometry
self.attributes = attributes
self.units = units or "m"

geometry: Optional[List[Point]] = None,
attributes: Optional[Base] = None,

class GisRasterElement(Base, speckle_type="Objects.GIS.RasterElement", detachable={"displayValue"}):
"""GIS Raster element"""

def __init__(
self,
band_count: Optional[int] = None,
band_names: Optional[List[str]] = None,
x_origin: Optional[float] = None,
y_origin: Optional[float] = None,
x_size: Optional[int] = None,
y_size: Optional[int] = None,
x_resolution: Optional[float] = None,
y_resolution: Optional[float] = None,
noDataValue: Optional[List[float]] = None,
displayValue: Optional[List[Mesh]] = None,
units: Optional[str] = None,
**kwargs
) -> None:
super().__init__(**kwargs)

self.band_count = band_count
self.band_names = band_names
self.x_origin = x_origin
self.y_origin = y_origin
self.x_size = x_size
self.y_size = y_size
self.x_resolution = x_resolution
self.y_resolution = y_resolution
self.noDataValue = noDataValue
self.displayValue = displayValue
self.units = units or "m"
band_count: Optional[int] = None
band_names: Optional[List[str]] = None
x_origin: Optional[float] = None
y_origin: Optional[float] = None
x_size: Optional[int] = None
y_size: Optional[int] = None
x_resolution: Optional[float] = None
y_resolution: Optional[float] = None
noDataValue: Optional[List[float]] = None
displayValue: Optional[List[Mesh]] = None

class GisTopography(GisRasterElement, speckle_type="Objects.GIS.GisTopography", detachable={"displayValue"}):
"""GIS Raster element with 3d Topography representation"""

class GisNonGeometryElement(Base, speckle_type="Objects.GIS.NonGeometryElement"):
"""GIS Table feature"""

attributes: Optional[Base] = None

71 changes: 29 additions & 42 deletions src/specklepy/objects/GIS/layers.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,29 +28,22 @@ def __init__(
self.geomType = geomType
self.renderer = renderer or {}

class VectorLayer(Collection, detachable={"elements"}, speckle_type="Objects.GIS.VectorLayer", serialize_ignore={"features"}):
class VectorLayer(
Collection,
detachable={"elements"},
speckle_type="Objects.GIS.VectorLayer",
serialize_ignore={"features"}):

"""GIS Vector Layer"""

def __init__(
self,
name: Optional[str]=None,
crs: Optional[CRS]=None,
units: Optional[str] = None,
elements: Optional[List[Base]] = None,
attributes: Optional[Base] = None,
geomType: Optional[str] = None,
renderer: Optional[Dict[str, Any]] = None,
**kwargs
) -> None:
super().__init__(**kwargs)
self.name = name or ""
self.crs = crs
self.units = units
self.elements = elements or []
self.attributes = attributes
self.geomType = geomType or "None"
self.renderer = renderer or {}
self.collectionType = "VectorLayer"
name: Optional[str]=None
crs: Optional[CRS]=None
units: Optional[str] = None
elements: Optional[List[Base]] = None
attributes: Optional[Base] = None
geomType: Optional[str] = "None"
renderer: Optional[Dict[str, Any]] = None
collectionType = "VectorLayer"

@property
@deprecated(version="2.14", reason="Use elements")
Expand All @@ -61,29 +54,23 @@ def features(self) -> Optional[List[Base]]:
def features(self, value: Optional[List[Base]]) -> None:
self.elements = value

class RasterLayer(Collection, detachable={"elements"}, speckle_type="Objects.GIS.RasterLayer", serialize_ignore={"features"}):
class RasterLayer(
Collection,
detachable={"elements"},
speckle_type="Objects.GIS.RasterLayer",
serialize_ignore={"features"}):

"""GIS Raster Layer"""

def __init__(
self,
name: Optional[str] = None,
crs: Optional[CRS]=None,
units: Optional[str] = None,
rasterCrs: Optional[CRS]=None,
elements: Optional[List[Base]] = None,
geomType: Optional[str] = None,
renderer: Optional[Dict[str, Any]] = None,
**kwargs
) -> None:
super().__init__(**kwargs)
self.name = name or ""
self.crs = crs
self.units = units
self.rasterCrs = rasterCrs
self.elements = elements or []
self.geomType = geomType or "None"
self.renderer = renderer or {}
self.collectionType = "RasterLayer"
name: Optional[str] = None
crs: Optional[CRS]=None
units: Optional[str] = None
rasterCrs: Optional[CRS]=None
elements: Optional[List[Base]] = None
geomType: Optional[str] = "None"
renderer: Optional[Dict[str, Any]] = None
collectionType = "RasterLayer"


@property
@deprecated(version="2.14", reason="Use elements")
Expand Down
23 changes: 10 additions & 13 deletions src/specklepy/objects/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

from stringcase import pascalcase

from specklepy.logging.exceptions import SpeckleException
from specklepy.logging.exceptions import SpeckleException, SpeckleInvalidUnitException
from specklepy.objects.units import Units, get_units_from_string
from specklepy.transports.memory import MemoryTransport

Expand Down Expand Up @@ -322,7 +322,7 @@ class Base(_RegisteringBase):
id: Union[str, None] = None
totalChildrenCount: Union[int, None] = None
applicationId: Union[str, None] = None
_units: Union[Units, None] = None
_units: Union[None, str] = None

def __init__(self, **kwargs) -> None:
super().__init__()
Expand Down Expand Up @@ -463,22 +463,19 @@ def add_detachable_attrs(self, names: Set[str]) -> None:

@property
def units(self) -> Union[str, None]:
if self._units:
return self._units.value
return None
return self._units

@units.setter
def units(self, value: Union[str, Units, None]):
if value is None:
units = value
"""While this property accepts any string value, geometry expects units to be specific strings (see Units enum)"""
if isinstance(value, str) or value is None:
self._units = value
elif isinstance(value, Units):
units: Units = value
self._units = value.value
else:
units = get_units_from_string(value)
self._units = units
# except SpeckleInvalidUnitException as ex:
# warn(f"Units are reset to None. Reason {ex.message}")
# self._units = None
raise SpeckleInvalidUnitException(
f"Unknown type {type(value)} received for units"
)

def get_member_names(self) -> List[str]:
"""Get all of the property names on this object, dynamic or not"""
Expand Down
48 changes: 43 additions & 5 deletions src/specklepy/objects/units.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class Units(Enum):
Units.none: ["none", "null"],
}


UNITS_ENCODINGS = {
Units.none: 0,
None: 0,
Expand All @@ -49,6 +50,20 @@ class Units(Enum):
}


UNIT_SCALE = {
Units.none: 1,
Units.mm: 0.001,
Units.cm: 0.01,
Units.m: 1.0,
Units.km: 1000.0,
Units.inches: 0.0254,
Units.feet: 0.3048,
Units.yards: 0.9144,
Units.miles: 1609.340,
}
"""Unit scaling factor to meters"""


def get_units_from_string(unit: str) -> Units:
if not isinstance(unit, str):
raise SpeckleInvalidUnitException(unit)
Expand All @@ -59,10 +74,10 @@ def get_units_from_string(unit: str) -> Units:
raise SpeckleInvalidUnitException(unit)


def get_units_from_encoding(unit: int):
def get_units_from_encoding(unit: int) -> Units:
for name, encoding in UNITS_ENCODINGS.items():
if unit == encoding:
return name
return name or Units.none

raise SpeckleException(
message=(
Expand All @@ -72,13 +87,36 @@ def get_units_from_encoding(unit: int):
)


def get_encoding_from_units(unit: Union[Units, None]):
def get_encoding_from_units(unit: Union[Units, str, None]):
maybe_sanitized_unit = unit
if isinstance(unit, str):
for unit_enum, aliases in UNITS_STRINGS.items():
if unit in aliases:
maybe_sanitized_unit = unit_enum
try:
return UNITS_ENCODINGS[unit]
return UNITS_ENCODINGS[maybe_sanitized_unit]
except KeyError as e:
raise SpeckleException(
message=(
f"No encoding exists for unit {unit}."
f"No encoding exists for unit {maybe_sanitized_unit}."
f"Please enter a valid unit to encode (eg {UNITS_ENCODINGS})."
)
) from e


def get_scale_factor_from_string(fromUnits: str, toUnits: str) -> float:
"""Returns a scalar to convert distance values from one unit system to another"""
return get_scale_factor(get_units_from_string(fromUnits), get_units_from_string(toUnits))


def get_scale_factor(fromUnits: Units, toUnits: Units) -> float:
"""Returns a scalar to convert distance values from one unit system to another"""
return get_scale_factor_to_meters(fromUnits) / get_scale_factor_to_meters(toUnits)


def get_scale_factor_to_meters(fromUnits: Units) -> float:
"""Returns a scalar to convert distance values from one unit system to meters"""
if fromUnits not in UNIT_SCALE:
raise ValueError(f"Invalid units provided: {fromUnits}")

return UNIT_SCALE[fromUnits]
2 changes: 1 addition & 1 deletion tests/intergration/test_serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def test_serialize(self, base):
deserialized = operations.deserialize(serialized)

assert base.get_id() == deserialized.get_id()
assert base.units == "mm"
assert base.units == "millimetres"
assert isinstance(base.test_bases[0], Base)
assert base["@revit_thing"].speckle_type == "SpecialRevitFamily"
assert base["@detach"].name == deserialized["@detach"].name
Expand Down
Loading

0 comments on commit b5fb684

Please sign in to comment.