syntax
@@ -1,3 +1,3 @@
|
||||
specklepy==2.9.1
|
||||
specklepy==2.17.17
|
||||
panda3d==1.10.11
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import os
|
||||
|
||||
try:
|
||||
from speckle.speckle.converter.layers.CRS import CRS
|
||||
from speckle.speckle.converter.layers.Layer import Layer, VectorLayer, RasterLayer
|
||||
from specklepy.objects.GIS.layers import Layer, VectorLayer, RasterLayer
|
||||
except:
|
||||
from speckle_toolbox.esri.toolboxes.speckle.converter.layers.CRS import CRS
|
||||
from speckle_toolbox.esri.toolboxes.speckle.converter.layers.Layer import Layer, VectorLayer, RasterLayer
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
import inspect
|
||||
import random
|
||||
from typing import Any, Union
|
||||
from speckle.speckle.converter.layers.utils import getVariantFromValue, traverseDict
|
||||
|
||||
from speckle.speckle.utils.panel_logging import logToUser
|
||||
|
||||
from specklepy.objects import Base
|
||||
|
||||
|
||||
def addFeatVariant(key, variant, value, f: "QgsFeature") -> "QgsFeature":
|
||||
try:
|
||||
feat = f
|
||||
if variant == 10:
|
||||
value = str(value) # string
|
||||
|
||||
if value != "NULL" and value != "None":
|
||||
if variant == getVariantFromValue(value):
|
||||
feat[key] = value
|
||||
elif (
|
||||
isinstance(value, float) and variant == 4
|
||||
): # float, but expecting Long (integer)
|
||||
feat[key] = int(value)
|
||||
elif (
|
||||
isinstance(value, int) and variant == 6
|
||||
): # int (longlong), but expecting float
|
||||
feat[key] = float(value)
|
||||
else:
|
||||
feat[key] = None
|
||||
# print(key); print(value); print(type(value)); print(variant); print(getVariantFromValue(value))
|
||||
elif isinstance(variant, int):
|
||||
feat[key] = None
|
||||
return feat
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3])
|
||||
return feat
|
||||
|
||||
|
||||
def updateFeat(feat: "QgsFeature", fields: "QgsFields", feature: Base) -> "QgsFeature":
|
||||
try:
|
||||
# print("__updateFeat")
|
||||
all_field_names = fields.names()
|
||||
for i, key in enumerate(all_field_names):
|
||||
variant = fields.at(i).type()
|
||||
try:
|
||||
if key == "Speckle_ID":
|
||||
value = str(feature["id"])
|
||||
# if key != "parameters": print(value)
|
||||
feat[key] = value
|
||||
|
||||
feat = addFeatVariant(key, variant, value, feat)
|
||||
|
||||
else:
|
||||
try:
|
||||
value = feature[key]
|
||||
feat = addFeatVariant(key, variant, value, feat)
|
||||
|
||||
except:
|
||||
value = None
|
||||
rootName = key.split("_")[0]
|
||||
# try: # if the root category exists
|
||||
# if its'a list
|
||||
if isinstance(feature[rootName], list):
|
||||
for i in range(len(feature[rootName])):
|
||||
try:
|
||||
newF, newVals = traverseDict(
|
||||
{},
|
||||
{},
|
||||
rootName + "_" + str(i),
|
||||
feature[rootName][i],
|
||||
1,
|
||||
)
|
||||
for i, (key, value) in enumerate(newVals.items()):
|
||||
for k, (x, y) in enumerate(newF.items()):
|
||||
if key == x:
|
||||
variant = y
|
||||
break
|
||||
feat = addFeatVariant(key, variant, value, feat)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
# except: # if not a list
|
||||
else:
|
||||
try:
|
||||
newF, newVals = traverseDict(
|
||||
{}, {}, rootName, feature[rootName], 1
|
||||
)
|
||||
for i, (key, value) in enumerate(newVals.items()):
|
||||
for k, (x, y) in enumerate(newF.items()):
|
||||
if key == x:
|
||||
variant = y
|
||||
break
|
||||
feat = addFeatVariant(key, variant, value, feat)
|
||||
except Exception as e:
|
||||
feat.update({key: None})
|
||||
except Exception as e:
|
||||
feat[key] = None
|
||||
# feat_sorted = {k: v for k, v in sorted(feat.items(), key=lambda item: item[0])}
|
||||
# print("_________________end of updating a feature_________________________")
|
||||
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3])
|
||||
|
||||
return feat
|
||||
|
||||
|
||||
def getPolygonFeatureHeight(
|
||||
feature: "QgsFeature", layer: "QgsVectorLayer", dataStorage: "DataStorage"
|
||||
) -> Union[int, float, None]:
|
||||
height = None
|
||||
ignore = False
|
||||
if dataStorage.savedTransforms is not None:
|
||||
for item in dataStorage.savedTransforms:
|
||||
layer_name = item.split(" -> ")[0].split(" ('")[0]
|
||||
transform_name = item.split(" -> ")[1].lower()
|
||||
if "ignore" in transform_name:
|
||||
ignore = True
|
||||
|
||||
if layer_name == layer.name():
|
||||
attribute = None
|
||||
if " ('" in item:
|
||||
attribute = item.split(" ('")[1].split("') ")[0]
|
||||
|
||||
if attribute is None and ignore is False:
|
||||
logToUser(
|
||||
"Attribute for extrusion not selected",
|
||||
level=1,
|
||||
func=inspect.stack()[0][3],
|
||||
)
|
||||
return None
|
||||
|
||||
# print("Apply transform: " + transform_name)
|
||||
if "extrude" in transform_name and "polygon" in transform_name:
|
||||
# additional check:
|
||||
try:
|
||||
if dataStorage.project.crs().isGeographic():
|
||||
return None
|
||||
except:
|
||||
return None
|
||||
|
||||
try:
|
||||
existing_height = float(feature[attribute])
|
||||
if (
|
||||
existing_height is None or str(feature[attribute]) == "NULL"
|
||||
): # if attribute value invalid
|
||||
if ignore is True:
|
||||
return None
|
||||
else: # find approximate value
|
||||
all_existing_vals = [
|
||||
f[attribute]
|
||||
for f in layer.getFeatures()
|
||||
if (
|
||||
f[attribute] is not None
|
||||
and (
|
||||
isinstance(f[attribute], float)
|
||||
or isinstance(f[attribute], int)
|
||||
)
|
||||
)
|
||||
]
|
||||
try:
|
||||
if len(all_existing_vals) > 5:
|
||||
height_average = all_existing_vals[
|
||||
int(len(all_existing_vals) / 2)
|
||||
]
|
||||
height = random.randint(
|
||||
height_average - 5, height_average + 5
|
||||
)
|
||||
else:
|
||||
height = random.randint(10, 20)
|
||||
except:
|
||||
height = random.randint(10, 20)
|
||||
else: # if acceptable value: reading from existing attribute
|
||||
height = existing_height
|
||||
|
||||
except: # if no Height attribute
|
||||
if ignore is True:
|
||||
height = None
|
||||
else:
|
||||
height = random.randint(10, 20)
|
||||
|
||||
return height
|
||||
@@ -1,222 +0,0 @@
|
||||
|
||||
from regex import F
|
||||
from specklepy.objects import Base
|
||||
from specklepy.objects.geometry import Line, Mesh, Point, Polyline, Curve, Arc, Circle, Polycurve, Ellipse
|
||||
|
||||
import arcpy
|
||||
from typing import Any, List, Union, Sequence
|
||||
|
||||
import inspect
|
||||
|
||||
try:
|
||||
from speckle.speckle.converter.geometry.polygon import polygonToNative, polygonToSpeckle, multiPolygonToSpeckle, polygonToSpeckleMesh
|
||||
from speckle.speckle.converter.geometry.polyline import arcToNative, ellipseToNative, circleToNative, curveToNative, lineToNative, polycurveToNative, polylineFromVerticesToSpeckle, polylineToNative, polylineToSpeckle
|
||||
from speckle.speckle.converter.geometry.point import pointToCoord, pointToNative, pointToSpeckle, multiPointToSpeckle
|
||||
from speckle.speckle.converter.geometry.polyline import speckleArcCircleToPoints, specklePolycurveToPoints, multiPolylineToSpeckle
|
||||
from speckle.speckle.ui.logger import logToUser
|
||||
from speckle.speckle.converter.geometry.mesh import meshToNative
|
||||
except:
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.geometry.polygon import polygonToNative, polygonToSpeckle, multiPolygonToSpeckle, polygonToSpeckleMesh
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.geometry.polyline import arcToNative, ellipseToNative, circleToNative, curveToNative, lineToNative, polycurveToNative, polylineFromVerticesToSpeckle, polylineToNative, polylineToSpeckle
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.geometry.point import pointToCoord, pointToNative, pointToSpeckle, multiPointToSpeckle
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.geometry.polyline import speckleArcCircleToPoints, specklePolycurveToPoints, multiPolylineToSpeckle
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.geometry.mesh import meshToNative
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.ui.logger import logToUser
|
||||
|
||||
import numpy as np
|
||||
|
||||
def convertToSpeckle(feature, index: str, layer, geomType, featureType) -> Union[Base, Sequence[Base], None]:
|
||||
"""Converts the provided layer feature to Speckle objects"""
|
||||
print("___convertToSpeckle____________")
|
||||
try:
|
||||
geom = feature
|
||||
print(geom.isMultipart) # e.g. False
|
||||
print(geom.partCount)
|
||||
geomMultiType = geom.isMultipart
|
||||
hasCurves = feature.hasCurves
|
||||
|
||||
# feature is <geoprocessing describe geometry object object at 0x000002A75D6A4BD0>
|
||||
|
||||
#print(featureType) # e.g. Simple
|
||||
#print(geomType) # e.g. Polygon
|
||||
#geomSingleType = (featureType=="Simple") # Simple,SimpleJunction,SimpleJunction,ComplexEdge,Annotation,CoverageAnnotation,Dimension,RasterCatalogItem
|
||||
|
||||
if geomType == "Point": #Polygon, Point, Polyline, Multipoint, MultiPatch
|
||||
for pt in geom:
|
||||
return pointToSpeckle(pt, feature, layer)
|
||||
elif geomType == "Polyline":
|
||||
#if geom.hasCurves:
|
||||
# geom, feature = curvesToSegments(geom, feature, layer, geomMultiType)
|
||||
# geomMultiType = geom.isMultipart
|
||||
# return polylineToSpeckle(geom, feature, layer, geomMultiType)
|
||||
#else:
|
||||
if geom.partCount > 1: return multiPolylineToSpeckle(geom, feature, layer, geomMultiType)
|
||||
else: return polylineToSpeckle(geom, feature, layer, geomMultiType)
|
||||
elif geomType == "Polygon":
|
||||
if geom.partCount > 1: return multiPolygonToSpeckle(geom, index, layer, geomMultiType)
|
||||
else: return polygonToSpeckle(geom, index, layer, geomMultiType)
|
||||
elif geomType == "Multipoint":
|
||||
return multiPointToSpeckle(geom, feature, layer, geomMultiType)
|
||||
elif geomType == "MultiPatch":
|
||||
return polygonToSpeckleMesh(geom, index, layer, False)
|
||||
else:
|
||||
logToUser("Unsupported or invalid geometry in layer " + layer.name, level=1, func = inspect.stack()[0][3])
|
||||
return None
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
return None
|
||||
|
||||
|
||||
def convertToNative(base: Base, sr: arcpy.SpatialReference) -> Union[Any, None]:
|
||||
"""Converts any given base object to QgsGeometry."""
|
||||
print("___Convert to Native SingleType___")
|
||||
converted = None
|
||||
try:
|
||||
#print(base)
|
||||
conversions = [
|
||||
(Point, pointToNative),
|
||||
(Line, lineToNative),
|
||||
(Polyline, polylineToNative),
|
||||
(Curve, curveToNative),
|
||||
(Arc, arcToNative),
|
||||
(Circle, circleToNative),
|
||||
(Ellipse, ellipseToNative),
|
||||
#(Mesh, meshToNative),
|
||||
(Polycurve, polycurveToNative),
|
||||
(Base, multiPolygonToNative), # temporary solution for polygons (Speckle has no type Polygon yet)
|
||||
]
|
||||
|
||||
for conversion in conversions:
|
||||
if isinstance(base, conversion[0]):
|
||||
#print(conversion[0])
|
||||
converted = conversion[1](base, sr)
|
||||
break
|
||||
#print(converted)
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
return converted
|
||||
|
||||
def multiPointToNative(items: List[Point], sr: arcpy.SpatialReference):
|
||||
print("___Create MultiPoint")
|
||||
features = None
|
||||
try:
|
||||
all_pts = []
|
||||
# example https://pro.arcgis.com/en/pro-app/2.8/arcpy/classes/multipoint.htm
|
||||
for item in items:
|
||||
pt = pointToCoord(item) # [x, y, z]
|
||||
all_pts.append( arcpy.Point(pt[0], pt[1], pt[2]) )
|
||||
#print(all_pts)
|
||||
features = arcpy.Multipoint( arcpy.Array(all_pts) )
|
||||
#if len(features)==0: features = None
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
return features
|
||||
|
||||
def multiPolylineToNative(items: List[Polyline], sr: arcpy.SpatialReference):
|
||||
print("_______Drawing Multipolylines____")
|
||||
poly = None
|
||||
try:
|
||||
#print(items)
|
||||
poly = None
|
||||
full_array_list = []
|
||||
for item in items: # will be 1 item
|
||||
pointsSpeckle = []
|
||||
try: pointsSpeckle = item.as_points()
|
||||
except: continue
|
||||
pts = [pointToCoord(pt) for pt in pointsSpeckle]
|
||||
|
||||
if item.closed is True:
|
||||
pts.append( pointToCoord(item.as_points()[0]) )
|
||||
|
||||
arr = [arcpy.Point(*coords) for coords in pts]
|
||||
full_array_list.append(arr)
|
||||
|
||||
poly = arcpy.Polyline( arcpy.Array(full_array_list), sr, has_z=True )
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
return poly
|
||||
|
||||
def multiPolygonToNative(items: List[Base], sr: arcpy.SpatialReference): #TODO fix multi features
|
||||
|
||||
print("_______Drawing Multipolygons____")
|
||||
polygon = None
|
||||
if not isinstance(items, List): items = [items]
|
||||
try:
|
||||
print(items)
|
||||
full_array_list = []
|
||||
|
||||
for item_geom in items: # will be 1 item
|
||||
print(item_geom)
|
||||
try: item_geom = item_geom["geometry"]
|
||||
except: item_geom = [item_geom]
|
||||
for item in item_geom:
|
||||
#print(item)
|
||||
#pts = [pointToCoord(pt) for pt in item["boundary"].as_points()]
|
||||
pointsSpeckle = []
|
||||
if isinstance(item["boundary"], Circle) or isinstance(item["boundary"], Arc):
|
||||
pointsSpeckle = speckleArcCircleToPoints(item["boundary"])
|
||||
elif isinstance(item["boundary"], Polycurve):
|
||||
pointsSpeckle = specklePolycurveToPoints(item["boundary"])
|
||||
elif isinstance(item["boundary"], Line): pass
|
||||
else:
|
||||
try: pointsSpeckle = item["boundary"].as_points()
|
||||
except Exception as e: print(e) # if Line
|
||||
#print(pointsSpeckle)
|
||||
pts = [pointToCoord(pt) for pt in pointsSpeckle]
|
||||
#print(pts)
|
||||
|
||||
outer_arr = [arcpy.Point(*coords) for coords in pts]
|
||||
outer_arr.append(outer_arr[0])
|
||||
#print(outer_arr)
|
||||
geomPart = []
|
||||
try:
|
||||
for void in item["voids"]:
|
||||
#print(void)
|
||||
#pts = [pointToCoord(pt) for pt in void.as_points()]
|
||||
pointsSpeckle = []
|
||||
if isinstance(void, Circle) or isinstance(void, Arc):
|
||||
pointsSpeckle = speckleArcCircleToPoints(void)
|
||||
elif isinstance(void, Polycurve):
|
||||
pointsSpeckle = specklePolycurveToPoints(void)
|
||||
elif isinstance(void, Line): pass
|
||||
else:
|
||||
try: pointsSpeckle = void.as_points()
|
||||
except: pass # if Line
|
||||
pts = [pointToCoord(pt) for pt in pointsSpeckle]
|
||||
|
||||
inner_arr = [arcpy.Point(*coords) for coords in pts]
|
||||
inner_arr.append(inner_arr[0])
|
||||
geomPart.append(arcpy.Array(inner_arr))
|
||||
except Exception as e: print(e)
|
||||
geomPart.insert(0, arcpy.Array(outer_arr))
|
||||
|
||||
#print(geomPart)
|
||||
full_array_list.extend(geomPart) # outlines are written one by one, with no separation to "parts"
|
||||
#print("end of loop1")
|
||||
print("end of loop2")
|
||||
geomPartArray = arcpy.Array(full_array_list)
|
||||
polygon = arcpy.Polygon(geomPartArray, sr, has_z=True)
|
||||
|
||||
print(polygon)
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
|
||||
return polygon
|
||||
|
||||
def convertToNativeMulti(items: List[Base], sr: arcpy.SpatialReference):
|
||||
print("___Convert to Native MultiType___")
|
||||
try:
|
||||
first = items[0]
|
||||
if isinstance(first, Point):
|
||||
return multiPointToNative(items, sr)
|
||||
elif isinstance(first, Line) or isinstance(first, Polyline):
|
||||
return multiPolylineToNative(items, sr)
|
||||
elif isinstance(first, Base):
|
||||
try:
|
||||
if first["boundary"] is not None and first["voids"] is not None:
|
||||
return multiPolygonToNative(items, sr)
|
||||
except: return None
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
return None
|
||||
|
||||
|
||||
@@ -0,0 +1,279 @@
|
||||
from regex import F
|
||||
from specklepy.objects import Base
|
||||
from specklepy.objects.geometry import (
|
||||
Line,
|
||||
Mesh,
|
||||
Point,
|
||||
Polyline,
|
||||
Curve,
|
||||
Arc,
|
||||
Circle,
|
||||
Polycurve,
|
||||
Ellipse,
|
||||
)
|
||||
|
||||
import arcpy
|
||||
from typing import Any, List, Union, Sequence
|
||||
|
||||
import inspect
|
||||
|
||||
from speckle.speckle.converter.geometry.polygon import (
|
||||
polygonToNative,
|
||||
polygonToSpeckle,
|
||||
multiPolygonToSpeckle,
|
||||
polygonToSpeckleMesh,
|
||||
)
|
||||
from speckle.speckle.converter.geometry.utils import specklePolycurveToPoints
|
||||
from speckle.speckle.converter.geometry.polyline import (
|
||||
arcToNative,
|
||||
ellipseToNative,
|
||||
circleToNative,
|
||||
curveToNative,
|
||||
lineToNative,
|
||||
polycurveToNative,
|
||||
polylineToNative,
|
||||
polylineToSpeckle,
|
||||
speckleArcCircleToPoints,
|
||||
multiPolylineToSpeckle,
|
||||
)
|
||||
from speckle.speckle.converter.geometry.point import (
|
||||
pointToCoord,
|
||||
pointToNative,
|
||||
pointToSpeckle,
|
||||
multiPointToSpeckle,
|
||||
)
|
||||
from speckle.speckle.utils.panel_logging import logToUser
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
def convertToSpeckle(
|
||||
feature, index: str, layer, geomType, featureType
|
||||
) -> Union[Base, Sequence[Base], None]:
|
||||
"""Converts the provided layer feature to Speckle objects"""
|
||||
print("___convertToSpeckle____________")
|
||||
try:
|
||||
geom = feature
|
||||
print(geom.isMultipart) # e.g. False
|
||||
print(geom.partCount)
|
||||
geomMultiType = geom.isMultipart
|
||||
hasCurves = feature.hasCurves
|
||||
|
||||
# feature is <geoprocessing describe geometry object object at 0x000002A75D6A4BD0>
|
||||
|
||||
# print(featureType) # e.g. Simple
|
||||
# print(geomType) # e.g. Polygon
|
||||
# geomSingleType = (featureType=="Simple") # Simple,SimpleJunction,SimpleJunction,ComplexEdge,Annotation,CoverageAnnotation,Dimension,RasterCatalogItem
|
||||
|
||||
if geomType == "Point": # Polygon, Point, Polyline, Multipoint, MultiPatch
|
||||
for pt in geom:
|
||||
return pointToSpeckle(pt, feature, layer)
|
||||
elif geomType == "Polyline":
|
||||
# if geom.hasCurves:
|
||||
# geom, feature = curvesToSegments(geom, feature, layer, geomMultiType)
|
||||
# geomMultiType = geom.isMultipart
|
||||
# return polylineToSpeckle(geom, feature, layer, geomMultiType)
|
||||
# else:
|
||||
if geom.partCount > 1:
|
||||
return multiPolylineToSpeckle(geom, feature, layer, geomMultiType)
|
||||
else:
|
||||
return polylineToSpeckle(geom, feature, layer, geomMultiType)
|
||||
elif geomType == "Polygon":
|
||||
if geom.partCount > 1:
|
||||
return multiPolygonToSpeckle(geom, index, layer, geomMultiType)
|
||||
else:
|
||||
return polygonToSpeckle(geom, index, layer, geomMultiType)
|
||||
elif geomType == "Multipoint":
|
||||
return multiPointToSpeckle(geom, feature, layer, geomMultiType)
|
||||
elif geomType == "MultiPatch":
|
||||
return polygonToSpeckleMesh(geom, index, layer, False)
|
||||
else:
|
||||
logToUser(
|
||||
"Unsupported or invalid geometry in layer " + layer.name,
|
||||
level=1,
|
||||
func=inspect.stack()[0][3],
|
||||
)
|
||||
return None
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
return None
|
||||
|
||||
|
||||
def convertToNative(base: Base, sr: arcpy.SpatialReference) -> Union[Any, None]:
|
||||
"""Converts any given base object to QgsGeometry."""
|
||||
print("___Convert to Native SingleType___")
|
||||
converted = None
|
||||
try:
|
||||
# print(base)
|
||||
conversions = [
|
||||
(Point, pointToNative),
|
||||
(Line, lineToNative),
|
||||
(Polyline, polylineToNative),
|
||||
(Curve, curveToNative),
|
||||
(Arc, arcToNative),
|
||||
(Circle, circleToNative),
|
||||
(Ellipse, ellipseToNative),
|
||||
# (Mesh, meshToNative),
|
||||
(Polycurve, polycurveToNative),
|
||||
(
|
||||
Base,
|
||||
multiPolygonToNative,
|
||||
), # temporary solution for polygons (Speckle has no type Polygon yet)
|
||||
]
|
||||
|
||||
for conversion in conversions:
|
||||
if isinstance(base, conversion[0]):
|
||||
# print(conversion[0])
|
||||
converted = conversion[1](base, sr)
|
||||
break
|
||||
# print(converted)
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
return converted
|
||||
|
||||
|
||||
def multiPointToNative(items: List[Point], sr: arcpy.SpatialReference):
|
||||
print("___Create MultiPoint")
|
||||
features = None
|
||||
try:
|
||||
all_pts = []
|
||||
# example https://pro.arcgis.com/en/pro-app/2.8/arcpy/classes/multipoint.htm
|
||||
for item in items:
|
||||
pt = pointToCoord(item) # [x, y, z]
|
||||
all_pts.append(arcpy.Point(pt[0], pt[1], pt[2]))
|
||||
# print(all_pts)
|
||||
features = arcpy.Multipoint(arcpy.Array(all_pts))
|
||||
# if len(features)==0: features = None
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
return features
|
||||
|
||||
|
||||
def multiPolylineToNative(items: List[Polyline], sr: arcpy.SpatialReference):
|
||||
print("_______Drawing Multipolylines____")
|
||||
poly = None
|
||||
try:
|
||||
# print(items)
|
||||
poly = None
|
||||
full_array_list = []
|
||||
for item in items: # will be 1 item
|
||||
pointsSpeckle = []
|
||||
try:
|
||||
pointsSpeckle = item.as_points()
|
||||
except:
|
||||
continue
|
||||
pts = [pointToCoord(pt) for pt in pointsSpeckle]
|
||||
|
||||
if item.closed is True:
|
||||
pts.append(pointToCoord(item.as_points()[0]))
|
||||
|
||||
arr = [arcpy.Point(*coords) for coords in pts]
|
||||
full_array_list.append(arr)
|
||||
|
||||
poly = arcpy.Polyline(arcpy.Array(full_array_list), sr, has_z=True)
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
return poly
|
||||
|
||||
|
||||
def multiPolygonToNative(
|
||||
items: List[Base], sr: arcpy.SpatialReference
|
||||
): # TODO fix multi features
|
||||
|
||||
print("_______Drawing Multipolygons____")
|
||||
polygon = None
|
||||
if not isinstance(items, List):
|
||||
items = [items]
|
||||
try:
|
||||
print(items)
|
||||
full_array_list = []
|
||||
|
||||
for item_geom in items: # will be 1 item
|
||||
print(item_geom)
|
||||
try:
|
||||
item_geom = item_geom["geometry"]
|
||||
except:
|
||||
item_geom = [item_geom]
|
||||
for item in item_geom:
|
||||
# print(item)
|
||||
# pts = [pointToCoord(pt) for pt in item["boundary"].as_points()]
|
||||
pointsSpeckle = []
|
||||
if isinstance(item["boundary"], Circle) or isinstance(
|
||||
item["boundary"], Arc
|
||||
):
|
||||
pointsSpeckle = speckleArcCircleToPoints(item["boundary"])
|
||||
elif isinstance(item["boundary"], Polycurve):
|
||||
pointsSpeckle = specklePolycurveToPoints(item["boundary"])
|
||||
elif isinstance(item["boundary"], Line):
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
pointsSpeckle = item["boundary"].as_points()
|
||||
except Exception as e:
|
||||
print(e) # if Line
|
||||
# print(pointsSpeckle)
|
||||
pts = [pointToCoord(pt) for pt in pointsSpeckle]
|
||||
# print(pts)
|
||||
|
||||
outer_arr = [arcpy.Point(*coords) for coords in pts]
|
||||
outer_arr.append(outer_arr[0])
|
||||
# print(outer_arr)
|
||||
geomPart = []
|
||||
try:
|
||||
for void in item["voids"]:
|
||||
# print(void)
|
||||
# pts = [pointToCoord(pt) for pt in void.as_points()]
|
||||
pointsSpeckle = []
|
||||
if isinstance(void, Circle) or isinstance(void, Arc):
|
||||
pointsSpeckle = speckleArcCircleToPoints(void)
|
||||
elif isinstance(void, Polycurve):
|
||||
pointsSpeckle = specklePolycurveToPoints(void)
|
||||
elif isinstance(void, Line):
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
pointsSpeckle = void.as_points()
|
||||
except:
|
||||
pass # if Line
|
||||
pts = [pointToCoord(pt) for pt in pointsSpeckle]
|
||||
|
||||
inner_arr = [arcpy.Point(*coords) for coords in pts]
|
||||
inner_arr.append(inner_arr[0])
|
||||
geomPart.append(arcpy.Array(inner_arr))
|
||||
except Exception as e:
|
||||
print(e)
|
||||
geomPart.insert(0, arcpy.Array(outer_arr))
|
||||
|
||||
# print(geomPart)
|
||||
full_array_list.extend(
|
||||
geomPart
|
||||
) # outlines are written one by one, with no separation to "parts"
|
||||
# print("end of loop1")
|
||||
print("end of loop2")
|
||||
geomPartArray = arcpy.Array(full_array_list)
|
||||
polygon = arcpy.Polygon(geomPartArray, sr, has_z=True)
|
||||
|
||||
print(polygon)
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
|
||||
return polygon
|
||||
|
||||
|
||||
def convertToNativeMulti(items: List[Base], sr: arcpy.SpatialReference):
|
||||
print("___Convert to Native MultiType___")
|
||||
try:
|
||||
first = items[0]
|
||||
if isinstance(first, Point):
|
||||
return multiPointToNative(items, sr)
|
||||
elif isinstance(first, Line) or isinstance(first, Polyline):
|
||||
return multiPolylineToNative(items, sr)
|
||||
elif isinstance(first, Base):
|
||||
try:
|
||||
if first["boundary"] is not None and first["voids"] is not None:
|
||||
return multiPolygonToNative(items, sr)
|
||||
except:
|
||||
return None
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
return None
|
||||
@@ -17,14 +17,14 @@ try:
|
||||
from speckle.speckle.converter.geometry.point import pointToNative
|
||||
from speckle.speckle.converter.layers.symbology import featureColorfromNativeRenderer
|
||||
from speckle.speckle.converter.layers.utils import get_scale_factor
|
||||
from speckle.speckle.ui.logger import logToUser
|
||||
from speckle.speckle.utils.panel_logging import logToUser
|
||||
from speckle.speckle.plugin_utils.helpers import findOrCreatePath
|
||||
except:
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.layers.utils import get_scale_factor
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.geometry.point import pointToNative
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.layers.symbology import featureColorfromNativeRenderer
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.layers.utils import get_scale_factor
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.ui.logger import logToUser
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.utils.panel_logging import logToUser
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.plugin_utils.helpers import findOrCreatePath
|
||||
|
||||
from panda3d.core import Triangulator
|
||||
|
||||
@@ -4,13 +4,13 @@ from specklepy.objects.geometry import Point
|
||||
import arcpy
|
||||
|
||||
import inspect
|
||||
from speckle.speckle.converter.geometry.utils import (
|
||||
transform_speckle_pt_on_receive,
|
||||
apply_pt_transform_matrix,
|
||||
)
|
||||
|
||||
try:
|
||||
from speckle.speckle.converter.layers.utils import get_scale_factor
|
||||
from speckle.speckle.ui.logger import logToUser
|
||||
except:
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.layers.utils import get_scale_factor
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.ui.logger import logToUser
|
||||
from speckle.speckle.converter.layers.utils import get_scale_factor
|
||||
from speckle.speckle.utils.panel_logging import logToUser
|
||||
|
||||
|
||||
def multiPointToSpeckle(geom, feature, layer, multiType: bool):
|
||||
@@ -56,10 +56,13 @@ def pointToSpeckle(pt, feature, layer):
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
return None
|
||||
|
||||
def pointToNative(pt: Point, sr: arcpy.SpatialReference) -> arcpy.PointGeometry:
|
||||
def pointToNative(pt: Point, sr: arcpy.SpatialReference, dataStorage) -> arcpy.PointGeometry:
|
||||
"""Converts a Speckle Point to QgsPoint"""
|
||||
try:
|
||||
pt = scalePointToNative(pt, pt.units)
|
||||
pt = scalePointToNative(pt, pt.units)
|
||||
new_pt = apply_pt_transform_matrix(new_pt, dataStorage)
|
||||
newPt = transform_speckle_pt_on_receive(new_pt, dataStorage)
|
||||
|
||||
geom = arcpy.PointGeometry(arcpy.Point(pt.x, pt.y, pt.z), sr, has_z = True)
|
||||
#print(geom)
|
||||
return geom
|
||||
@@ -68,6 +71,20 @@ def pointToNative(pt: Point, sr: arcpy.SpatialReference) -> arcpy.PointGeometry:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
return None
|
||||
|
||||
def pointToNativeWithoutTransforms(pt: Point, sr: arcpy.SpatialReference, dataStorage):
|
||||
"""Converts a Speckle Point to QgsPoint"""
|
||||
try:
|
||||
new_pt = scalePointToNative(pt, pt.units, dataStorage)
|
||||
new_pt = apply_pt_transform_matrix(new_pt, dataStorage)
|
||||
|
||||
geom = arcpy.PointGeometry(arcpy.Point(pt.x, pt.y, pt.z), sr, has_z = True)
|
||||
#print(geom)
|
||||
return geom
|
||||
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3])
|
||||
return None
|
||||
|
||||
def pointToCoord(point: Point) -> List[float]:
|
||||
"""Converts a Speckle Point to QgsPoint"""
|
||||
try:
|
||||
|
||||
@@ -1,39 +1,30 @@
|
||||
from typing import List, Sequence, Union
|
||||
import arcpy
|
||||
import arcpy
|
||||
import json
|
||||
from arcpy.arcobjects.arcobjects import SpatialReference
|
||||
from arcpy.arcobjects.arcobjects import SpatialReference
|
||||
|
||||
from specklepy.objects import Base
|
||||
from specklepy.objects.geometry import Point, Arc, Circle, Polycurve, Polyline, Line
|
||||
|
||||
import inspect
|
||||
|
||||
try:
|
||||
from speckle.speckle.converter.geometry.mesh import constructMesh, constructMeshFromRaster, meshPartsFromPolygon
|
||||
from speckle.speckle.converter.geometry.point import pointToCoord, pointToNative
|
||||
from speckle.speckle.converter.layers.symbology import featureColorfromNativeRenderer
|
||||
from speckle.speckle.converter.geometry.polyline import (polylineFromVerticesToSpeckle,
|
||||
circleToSpeckle,
|
||||
speckleArcCircleToPoints,
|
||||
curveToSpeckle,
|
||||
specklePolycurveToPoints
|
||||
)
|
||||
from speckle.speckle.converter.geometry.utils import speckleBoundaryToSpecklePts
|
||||
from speckle.speckle.ui.logger import logToUser
|
||||
|
||||
except:
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.geometry.mesh import constructMeshFromRaster, constructMesh, meshPartsFromPolygon
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.geometry.point import pointToCoord, pointToNative
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.layers.symbology import featureColorfromNativeRenderer
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.geometry.polyline import (polylineFromVerticesToSpeckle,
|
||||
circleToSpeckle,
|
||||
speckleArcCircleToPoints,
|
||||
curveToSpeckle,
|
||||
specklePolycurveToPoints
|
||||
)
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.geometry.utils import speckleBoundaryToSpecklePts
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.ui.logger import logToUser
|
||||
import inspect
|
||||
|
||||
from speckle.speckle.converter.geometry.mesh import (
|
||||
constructMesh,
|
||||
constructMeshFromRaster,
|
||||
meshPartsFromPolygon,
|
||||
)
|
||||
from speckle.speckle.converter.geometry.point import pointToCoord, pointToNative
|
||||
from speckle.speckle.converter.layers.symbology import featureColorfromNativeRenderer
|
||||
from speckle.speckle.converter.geometry.polyline import (
|
||||
polylineFromVerticesToSpeckle,
|
||||
speckleArcCircleToPoints,
|
||||
curveToSpeckle,
|
||||
)
|
||||
from speckle.speckle.converter.geometry.utils import (
|
||||
speckleBoundaryToSpecklePts,
|
||||
specklePolycurveToPoints,
|
||||
)
|
||||
from speckle.speckle.utils.panel_logging import logToUser
|
||||
|
||||
import math
|
||||
from panda3d.core import Triangulator
|
||||
@@ -42,146 +33,166 @@ from panda3d.core import Triangulator
|
||||
def polygonToSpeckleMesh(geom, index: int, layer, multitype: bool):
|
||||
print("________polygonToSpeckleMesh_____")
|
||||
print(geom)
|
||||
polygon = Base(units = "m")
|
||||
polygon = Base(units="m")
|
||||
try:
|
||||
|
||||
vertices = []
|
||||
faces = []
|
||||
faces = []
|
||||
colors = []
|
||||
existing_vert = 0
|
||||
|
||||
for i, p in enumerate(geom):
|
||||
#print("____start enumerate feature")
|
||||
#print(p) #<geoprocessing array object object at 0x0000026796C77110>
|
||||
|
||||
for i, p in enumerate(geom):
|
||||
# print("____start enumerate feature")
|
||||
# print(p) #<geoprocessing array object object at 0x0000026796C77110>
|
||||
print(p)
|
||||
boundary, voids = getPolyBoundaryVoids(p, layer, multitype)
|
||||
#print(boundary)
|
||||
#print(voids)
|
||||
# print(boundary)
|
||||
# print(voids)
|
||||
polyBorder = speckleBoundaryToSpecklePts(boundary)
|
||||
#print(polyBorder)
|
||||
# print(polyBorder)
|
||||
voidsAsPts = []
|
||||
for v in voids:
|
||||
pts = speckleBoundaryToSpecklePts(v)
|
||||
voidsAsPts.append(pts)
|
||||
#print(voidsAsPts)
|
||||
#print("__to start meshPartsFromPolygon")
|
||||
total_vert, vertices_x, faces_x, colors_x = meshPartsFromPolygon(polyBorder, voidsAsPts, existing_vert, index, layer)
|
||||
# print(voidsAsPts)
|
||||
# print("__to start meshPartsFromPolygon")
|
||||
total_vert, vertices_x, faces_x, colors_x = meshPartsFromPolygon(
|
||||
polyBorder, voidsAsPts, existing_vert, index, layer
|
||||
)
|
||||
|
||||
existing_vert += total_vert
|
||||
vertices.extend(vertices_x)
|
||||
faces.extend(faces_x)
|
||||
colors.extend(colors_x)
|
||||
|
||||
#print("Colors: ")
|
||||
#print(colors)
|
||||
|
||||
# print("Colors: ")
|
||||
# print(colors)
|
||||
mesh = constructMesh(vertices, faces, colors)
|
||||
if mesh is not None:
|
||||
polygon.displayValue = [ mesh ]
|
||||
else:
|
||||
logToUser("Mesh creation from Polygon failed. Boundaries will be used as displayValue", level = 1, func = inspect.stack()[0][3])
|
||||
return polygon
|
||||
if mesh is not None:
|
||||
polygon.displayValue = [mesh]
|
||||
else:
|
||||
logToUser(
|
||||
"Mesh creation from Polygon failed. Boundaries will be used as displayValue",
|
||||
level=1,
|
||||
func=inspect.stack()[0][3],
|
||||
)
|
||||
return polygon
|
||||
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
return None
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
return None
|
||||
|
||||
|
||||
def getPolyBoundaryVoids(geom, layer, multiType: bool):
|
||||
#print("__getPolyBoundaryVoids__")
|
||||
# print("__getPolyBoundaryVoids__")
|
||||
voids: List[Union[None, Polyline, Arc, Line, Polycurve]] = []
|
||||
#print(voids)
|
||||
# print(voids)
|
||||
boundary = None
|
||||
pointList = []
|
||||
try:
|
||||
#partsBoundaries = []
|
||||
#partsVoids = []
|
||||
if multiType is False: # Multipolygon
|
||||
try: # might be no property "has curves"
|
||||
if geom.hasCurves:
|
||||
# partsBoundaries = []
|
||||
# partsVoids = []
|
||||
if multiType is False: # Multipolygon
|
||||
try: # might be no property "has curves"
|
||||
if geom.hasCurves:
|
||||
print("has curves")
|
||||
# geometry SHAPE@ tokens: https://pro.arcgis.com/en/pro-app/latest/arcpy/get-started/reading-geometries.htm
|
||||
print(geom.JSON)
|
||||
print(geom.JSON)
|
||||
boundary = curveToSpeckle(geom, "Polygon", geom, layer)
|
||||
else:
|
||||
else:
|
||||
print("no curves")
|
||||
for p in geom:
|
||||
for pt in p:
|
||||
#print(pt)
|
||||
if pt != None: pointList.append(pt)
|
||||
boundary = polylineFromVerticesToSpeckle(pointList, True, geom, layer)
|
||||
for pt in p:
|
||||
# print(pt)
|
||||
if pt != None:
|
||||
pointList.append(pt)
|
||||
boundary = polylineFromVerticesToSpeckle(
|
||||
pointList, True, geom, layer
|
||||
)
|
||||
print(boundary)
|
||||
except: # for multipatches, no property "has curves"
|
||||
#print("multipatch")
|
||||
for pt in geom:
|
||||
#print(pt)
|
||||
if pt != None: pointList.append(pt)
|
||||
boundary = polylineFromVerticesToSpeckle(pointList, True, geom, layer)
|
||||
#print(boundary)
|
||||
#partsBoundaries.append(boundary)
|
||||
#partsVoids.append([])
|
||||
|
||||
else:
|
||||
except: # for multipatches, no property "has curves"
|
||||
# print("multipatch")
|
||||
for pt in geom:
|
||||
# print(pt)
|
||||
if pt != None:
|
||||
pointList.append(pt)
|
||||
boundary = polylineFromVerticesToSpeckle(pointList, True, geom, layer)
|
||||
# print(boundary)
|
||||
# partsBoundaries.append(boundary)
|
||||
# partsVoids.append([])
|
||||
|
||||
else:
|
||||
print("multi type")
|
||||
for i, p in enumerate(geom):
|
||||
print(p)
|
||||
for pt in p:
|
||||
#print(pt) # 284394.58100903 5710688.11602606 NaN NaN
|
||||
if pt == None and boundary == None: # first break
|
||||
boundary = polylineFromVerticesToSpeckle(pointList, True, geom, layer)
|
||||
for pt in p:
|
||||
# print(pt) # 284394.58100903 5710688.11602606 NaN NaN
|
||||
if pt == None and boundary == None: # first break
|
||||
boundary = polylineFromVerticesToSpeckle(
|
||||
pointList, True, geom, layer
|
||||
)
|
||||
pointList = []
|
||||
elif pt == None and boundary != None: # breaks btw voids
|
||||
void = polylineFromVerticesToSpeckle(pointList, True, geom, layer)
|
||||
elif pt == None and boundary != None: # breaks btw voids
|
||||
void = polylineFromVerticesToSpeckle(
|
||||
pointList, True, geom, layer
|
||||
)
|
||||
voids.append(void)
|
||||
pointList = []
|
||||
elif pt != None: # add points to whatever list (boundary or void)
|
||||
elif pt != None: # add points to whatever list (boundary or void)
|
||||
pointList.append(pt)
|
||||
|
||||
if boundary != None and len(pointList)>0: # remaining polyline
|
||||
if boundary != None and len(pointList) > 0: # remaining polyline
|
||||
void = polylineFromVerticesToSpeckle(pointList, True, geom, layer)
|
||||
voids.append(void)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
return boundary, voids
|
||||
|
||||
|
||||
def multiPolygonToSpeckle(geom, index: str, layer, multiType: bool):
|
||||
|
||||
print("___MultiPolygon to Speckle____")
|
||||
polygon = []
|
||||
try:
|
||||
#print(enumerate(geom.getPart())) # this method ignores curvature and voids
|
||||
#print(json.loads(geom.JSON))
|
||||
#js = json.loads(geom.JSON)['rings']
|
||||
#https://desktop.arcgis.com/en/arcmap/latest/analyze/python/reading-geometries.htm
|
||||
for i,x in enumerate(geom): # [[x,x,x]
|
||||
print("Part # " + str(i+1))
|
||||
try:
|
||||
# print(enumerate(geom.getPart())) # this method ignores curvature and voids
|
||||
# print(json.loads(geom.JSON))
|
||||
# js = json.loads(geom.JSON)['rings']
|
||||
# https://desktop.arcgis.com/en/arcmap/latest/analyze/python/reading-geometries.htm
|
||||
for i, x in enumerate(geom): # [[x,x,x]
|
||||
print("Part # " + str(i + 1))
|
||||
print(x)
|
||||
boundaryFinished = 0
|
||||
arrBoundary = []
|
||||
arrInnerRings = []
|
||||
for ptn in x: # arcpy.Point
|
||||
if ptn is None:
|
||||
for ptn in x: # arcpy.Point
|
||||
if ptn is None:
|
||||
boundaryFinished += 1
|
||||
arrInnerRings.append([]) # start of new Inner Ring
|
||||
elif boundaryFinished == 0 and ptn is not None:
|
||||
arrInnerRings.append([]) # start of new Inner Ring
|
||||
elif boundaryFinished == 0 and ptn is not None:
|
||||
arrBoundary.append(ptn)
|
||||
elif boundaryFinished == 1 and ptn is not None:
|
||||
arrInnerRings[len(arrInnerRings)-1].append(ptn)
|
||||
elif boundaryFinished == 1 and ptn is not None:
|
||||
arrInnerRings[len(arrInnerRings) - 1].append(ptn)
|
||||
|
||||
full_arr = [arrBoundary] + arrInnerRings
|
||||
#print(full_arr)
|
||||
poly = arcpy.Polygon(arcpy.Array(full_arr), arcpy.Describe(layer.dataSource).SpatialReference, has_z = True)
|
||||
#print(poly) #<geoprocessing describe geometry object object at 0x000002B2D3E338D0>
|
||||
# print(full_arr)
|
||||
poly = arcpy.Polygon(
|
||||
arcpy.Array(full_arr),
|
||||
arcpy.Describe(layer.dataSource).SpatialReference,
|
||||
has_z=True,
|
||||
)
|
||||
# print(poly) #<geoprocessing describe geometry object object at 0x000002B2D3E338D0>
|
||||
polygon.append(polygonToSpeckle(poly, index, layer, poly.isMultipart))
|
||||
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
return polygon
|
||||
|
||||
|
||||
def polygonToSpeckle(geom, index: int, layer, multitype: bool):
|
||||
"""Converts a Polygon to Speckle"""
|
||||
polygon = Base(units = "m")
|
||||
try:
|
||||
polygon = Base(units="m")
|
||||
try:
|
||||
print("___Polygon to Speckle____")
|
||||
print(geom)
|
||||
|
||||
@@ -190,87 +201,98 @@ def polygonToSpeckle(geom, index: int, layer, multitype: bool):
|
||||
data = arcpy.Describe(layer.dataSource)
|
||||
sr = data.spatialReference
|
||||
|
||||
if boundary is None: return None
|
||||
if boundary is None:
|
||||
return None
|
||||
polygon.boundary = boundary
|
||||
polygon.voids = voids
|
||||
polygon.displayValue = [ boundary ] + voids
|
||||
#print(boundary)
|
||||
polygon.displayValue = [boundary] + voids
|
||||
# print(boundary)
|
||||
|
||||
############# mesh
|
||||
############# mesh
|
||||
vertices = []
|
||||
polyBorder = []
|
||||
total_vertices = 0
|
||||
if isinstance(boundary, Circle) or isinstance(boundary, Arc):
|
||||
polyBorder = speckleArcCircleToPoints(boundary)
|
||||
elif isinstance(boundary, Polycurve):
|
||||
polyBorder = specklePolycurveToPoints(boundary)
|
||||
#polygon.boundary.displayValue.closed = True
|
||||
elif isinstance(boundary, Line): pass
|
||||
elif isinstance(boundary, Polyline):
|
||||
try: polyBorder = boundary.as_points()
|
||||
except: pass # if Line
|
||||
#print(polyBorder)
|
||||
|
||||
if isinstance(boundary, Circle) or isinstance(boundary, Arc):
|
||||
polyBorder = speckleArcCircleToPoints(boundary)
|
||||
elif isinstance(boundary, Polycurve):
|
||||
polyBorder = specklePolycurveToPoints(boundary)
|
||||
# polygon.boundary.displayValue.closed = True
|
||||
elif isinstance(boundary, Line):
|
||||
pass
|
||||
elif isinstance(boundary, Polyline):
|
||||
try:
|
||||
polyBorder = boundary.as_points()
|
||||
except:
|
||||
pass # if Line
|
||||
# print(polyBorder)
|
||||
|
||||
if len(polyBorder)>2: # at least 3 points
|
||||
if len(polyBorder) > 2: # at least 3 points
|
||||
print("make meshes from polygons")
|
||||
if len(voids) == 0: # if there is a mesh with no voids
|
||||
if len(voids) == 0: # if there is a mesh with no voids
|
||||
for pt in polyBorder:
|
||||
if isinstance(pt, Point): pt = pointToNative(pt, sr).getPart() # SR unknown
|
||||
if isinstance(pt, Point):
|
||||
pt = pointToNative(pt, sr).getPart() # SR unknown
|
||||
x = pt.X
|
||||
y = pt.Y
|
||||
z = 0 if math.isnan(pt.Z) else pt.Z
|
||||
vertices.extend([x, y, z])
|
||||
total_vertices += 1
|
||||
#print(vertices)
|
||||
# print(vertices)
|
||||
ran = range(0, total_vertices)
|
||||
faces = [total_vertices]
|
||||
faces.extend([i for i in ran])
|
||||
#print(faces)
|
||||
# print(faces)
|
||||
# else: https://docs.panda3d.org/1.10/python/reference/panda3d.core.Triangulator
|
||||
else:
|
||||
trianglator = Triangulator()
|
||||
faces = []
|
||||
|
||||
# add boundary points
|
||||
#polyBorder = boundary.as_points()
|
||||
# polyBorder = boundary.as_points()
|
||||
pt_count = 0
|
||||
# add extra middle point for border
|
||||
for pt in polyBorder:
|
||||
if pt_count < len(polyBorder)-1:
|
||||
pt2 = polyBorder[pt_count+1]
|
||||
else: pt2 = polyBorder[0]
|
||||
|
||||
if pt_count < len(polyBorder) - 1:
|
||||
pt2 = polyBorder[pt_count + 1]
|
||||
else:
|
||||
pt2 = polyBorder[0]
|
||||
|
||||
trianglator.addPolygonVertex(trianglator.addVertex(pt.x, pt.y))
|
||||
vertices.extend([pt.x, pt.y, pt.z])
|
||||
|
||||
#trianglator.addPolygonVertex(trianglator.addVertex((pt.x+pt2.x)/4*3, (pt.y+pt2.y)/4*3))
|
||||
#vertices.extend([(pt.x+pt2.x)/4*3, (pt.y+pt2.y)/4*3, (pt.z+pt2.z)/4*3])
|
||||
# trianglator.addPolygonVertex(trianglator.addVertex((pt.x+pt2.x)/4*3, (pt.y+pt2.y)/4*3))
|
||||
# vertices.extend([(pt.x+pt2.x)/4*3, (pt.y+pt2.y)/4*3, (pt.z+pt2.z)/4*3])
|
||||
|
||||
trianglator.addPolygonVertex(trianglator.addVertex((pt.x+pt2.x)/2, (pt.y+pt2.y)/2))
|
||||
vertices.extend([(pt.x+pt2.x)/2, (pt.y+pt2.y)/2, (pt.z+pt2.z)/2])
|
||||
|
||||
#trianglator.addPolygonVertex(trianglator.addVertex((pt.x+pt2.x)/4, (pt.y+pt2.y)/4))
|
||||
#vertices.extend([(pt.x+pt2.x)/4, (pt.y+pt2.y)/4, (pt.z+pt2.z)/4])
|
||||
trianglator.addPolygonVertex(
|
||||
trianglator.addVertex((pt.x + pt2.x) / 2, (pt.y + pt2.y) / 2)
|
||||
)
|
||||
vertices.extend(
|
||||
[(pt.x + pt2.x) / 2, (pt.y + pt2.y) / 2, (pt.z + pt2.z) / 2]
|
||||
)
|
||||
|
||||
# trianglator.addPolygonVertex(trianglator.addVertex((pt.x+pt2.x)/4, (pt.y+pt2.y)/4))
|
||||
# vertices.extend([(pt.x+pt2.x)/4, (pt.y+pt2.y)/4, (pt.z+pt2.z)/4])
|
||||
|
||||
total_vertices += 2
|
||||
pt_count += 1
|
||||
|
||||
#add void points
|
||||
# add void points
|
||||
for i in range(len(voids)):
|
||||
trianglator.beginHole()
|
||||
|
||||
|
||||
pts = []
|
||||
if isinstance(voids[i], Circle) or isinstance(voids[i], Arc):
|
||||
pts = speckleArcCircleToPoints(voids[i])
|
||||
elif isinstance(voids[i], Polycurve):
|
||||
pts = specklePolycurveToPoints(voids[i])
|
||||
elif isinstance(voids[i], Line): pass
|
||||
else:
|
||||
try: pts = voids[i].as_points()
|
||||
except: pass # if Line
|
||||
#pts = voids[i].as_points()
|
||||
if isinstance(voids[i], Circle) or isinstance(voids[i], Arc):
|
||||
pts = speckleArcCircleToPoints(voids[i])
|
||||
elif isinstance(voids[i], Polycurve):
|
||||
pts = specklePolycurveToPoints(voids[i])
|
||||
elif isinstance(voids[i], Line):
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
pts = voids[i].as_points()
|
||||
except:
|
||||
pass # if Line
|
||||
# pts = voids[i].as_points()
|
||||
for pt in pts:
|
||||
trianglator.addHoleVertex(trianglator.addVertex(pt.x, pt.y))
|
||||
vertices.extend([pt.x, pt.y, pt.z])
|
||||
@@ -279,29 +301,42 @@ def polygonToSpeckle(geom, index: int, layer, multitype: bool):
|
||||
trianglator.triangulate()
|
||||
i = 0
|
||||
while i < trianglator.getNumTriangles():
|
||||
tr = [trianglator.getTriangleV0(i),trianglator.getTriangleV1(i),trianglator.getTriangleV2(i)]
|
||||
tr = [
|
||||
trianglator.getTriangleV0(i),
|
||||
trianglator.getTriangleV1(i),
|
||||
trianglator.getTriangleV2(i),
|
||||
]
|
||||
faces.extend([3, tr[0], tr[1], tr[2]])
|
||||
i+=1
|
||||
i += 1
|
||||
ran = range(0, total_vertices)
|
||||
|
||||
#print(polygon)
|
||||
|
||||
# print(polygon)
|
||||
col = featureColorfromNativeRenderer(index, layer)
|
||||
colors = [col for i in ran] # apply same color for all vertices
|
||||
colors = [col for i in ran] # apply same color for all vertices
|
||||
mesh = constructMesh(vertices, faces, colors)
|
||||
|
||||
if mesh is not None:
|
||||
polygon.displayValue = [ mesh ]
|
||||
else:
|
||||
logToUser("Mesh creation from Polygon failed. Boundaries will be used as displayValue", level = 1, func = inspect.stack()[0][3])
|
||||
|
||||
if mesh is not None:
|
||||
polygon.displayValue = [mesh]
|
||||
else:
|
||||
logToUser(
|
||||
"Mesh creation from Polygon failed. Boundaries will be used as displayValue",
|
||||
level=1,
|
||||
func=inspect.stack()[0][3],
|
||||
)
|
||||
return polygon
|
||||
else:
|
||||
logToUser("Not enough points for Polygon boundary", level = 1, func = inspect.stack()[0][3])
|
||||
logToUser(
|
||||
"Not enough points for Polygon boundary",
|
||||
level=1,
|
||||
func=inspect.stack()[0][3],
|
||||
)
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
return None
|
||||
|
||||
|
||||
def polygonToNative(poly: Base, sr: arcpy.SpatialReference) -> arcpy.Polygon:
|
||||
"""Converts a Speckle Polygon base object to QgsPolygon.
|
||||
This object must have a 'boundary' and 'voids' properties.
|
||||
@@ -309,50 +344,58 @@ def polygonToNative(poly: Base, sr: arcpy.SpatialReference) -> arcpy.Polygon:
|
||||
|
||||
print("_______Drawing polygons____")
|
||||
polygon = None
|
||||
try:
|
||||
try:
|
||||
try:
|
||||
poly = poly["geometry"]
|
||||
except: pass
|
||||
#pts = [pointToCoord(pt) for pt in poly["boundary"].as_points()]
|
||||
except:
|
||||
pass
|
||||
# pts = [pointToCoord(pt) for pt in poly["boundary"].as_points()]
|
||||
pointsSpeckle = []
|
||||
if isinstance(poly["boundary"], Circle) or isinstance(poly["boundary"], Arc):
|
||||
pointsSpeckle = speckleArcCircleToPoints(poly["boundary"])
|
||||
elif isinstance(poly["boundary"], Polycurve):
|
||||
pointsSpeckle = specklePolycurveToPoints(poly["boundary"])
|
||||
elif isinstance(poly["boundary"], Line): pass
|
||||
else:
|
||||
try: pointsSpeckle = poly["boundary"].as_points()
|
||||
except: pass # if Line
|
||||
if isinstance(poly["boundary"], Circle) or isinstance(poly["boundary"], Arc):
|
||||
pointsSpeckle = speckleArcCircleToPoints(poly["boundary"])
|
||||
elif isinstance(poly["boundary"], Polycurve):
|
||||
pointsSpeckle = specklePolycurveToPoints(poly["boundary"])
|
||||
elif isinstance(poly["boundary"], Line):
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
pointsSpeckle = poly["boundary"].as_points()
|
||||
except:
|
||||
pass # if Line
|
||||
|
||||
pts = [pointToCoord(pt) for pt in pointsSpeckle]
|
||||
#print(pts)
|
||||
# print(pts)
|
||||
|
||||
outer_arr = [arcpy.Point(*coords) for coords in pts]
|
||||
outer_arr.append(outer_arr[0])
|
||||
geomPart = []
|
||||
try:
|
||||
for void in poly["voids"]:
|
||||
#print(void)
|
||||
#pts = [pointToCoord(pt) for pt in void.as_points()]
|
||||
for void in poly["voids"]:
|
||||
# print(void)
|
||||
# pts = [pointToCoord(pt) for pt in void.as_points()]
|
||||
pointsSpeckle = []
|
||||
if isinstance(void, Circle) or isinstance(void, Arc):
|
||||
pointsSpeckle = speckleArcCircleToPoints(void)
|
||||
elif isinstance(void, Polycurve):
|
||||
pointsSpeckle = specklePolycurveToPoints(void)
|
||||
elif isinstance(void, Line): pass
|
||||
else:
|
||||
try: pointsSpeckle = void.as_points()
|
||||
except: pass # if Line
|
||||
if isinstance(void, Circle) or isinstance(void, Arc):
|
||||
pointsSpeckle = speckleArcCircleToPoints(void)
|
||||
elif isinstance(void, Polycurve):
|
||||
pointsSpeckle = specklePolycurveToPoints(void)
|
||||
elif isinstance(void, Line):
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
pointsSpeckle = void.as_points()
|
||||
except:
|
||||
pass # if Line
|
||||
pts = [pointToCoord(pt) for pt in pointsSpeckle]
|
||||
|
||||
inner_arr = [arcpy.Point(*coords) for coords in pts]
|
||||
inner_arr.append(inner_arr[0])
|
||||
geomPart.append(arcpy.Array(inner_arr))
|
||||
except:pass
|
||||
except:
|
||||
pass
|
||||
geomPart.insert(0, outer_arr)
|
||||
geomPartArray = arcpy.Array(geomPart)
|
||||
polygon = arcpy.Polygon(geomPartArray, sr, has_z=True)
|
||||
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
return polygon
|
||||
|
||||
@@ -1,16 +1,132 @@
|
||||
|
||||
from specklepy.objects.geometry import Point, Line, Polyline, Circle, Arc, Polycurve
|
||||
import math
|
||||
from math import cos, sin, atan
|
||||
import numpy as np
|
||||
from specklepy.objects.geometry import Point, Line, Polyline, Circle, Arc, Polycurve, Vector
|
||||
from specklepy.objects import Base
|
||||
from typing import List, Union
|
||||
from typing import List, Tuple, Union
|
||||
|
||||
import inspect
|
||||
|
||||
try:
|
||||
from speckle.speckle.converter.geometry.polyline import speckleArcCircleToPoints, specklePolycurveToPoints
|
||||
from speckle.speckle.ui.logger import logToUser
|
||||
except:
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.geometry.polyline import speckleArcCircleToPoints, specklePolycurveToPoints
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.ui.logger import logToUser
|
||||
from speckle.speckle.utils.panel_logging import logToUser
|
||||
|
||||
|
||||
def apply_pt_offsets_rotation_on_send(
|
||||
x: float, y: float, dataStorage
|
||||
) -> Tuple[Union[float, None]]: # on Send
|
||||
try:
|
||||
offset_x = dataStorage.crs_offset_x
|
||||
offset_y = dataStorage.crs_offset_y
|
||||
rotation = dataStorage.crs_rotation
|
||||
if offset_x is not None and isinstance(offset_x, float):
|
||||
x -= offset_x
|
||||
if offset_y is not None and isinstance(offset_y, float):
|
||||
y -= offset_y
|
||||
if (
|
||||
rotation is not None
|
||||
and (isinstance(rotation, float) or isinstance(rotation, int))
|
||||
and -360 < rotation < 360
|
||||
):
|
||||
a = rotation * math.pi / 180
|
||||
x2 = x * math.cos(a) + y * math.sin(a)
|
||||
y2 = -x * math.sin(a) + y * math.cos(a)
|
||||
x = x2
|
||||
y = y2
|
||||
return x, y
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3])
|
||||
return None, None
|
||||
|
||||
|
||||
def transform_speckle_pt_on_receive(pt_original: Point, dataStorage) -> Point:
|
||||
offset_x = dataStorage.crs_offset_x
|
||||
offset_y = dataStorage.crs_offset_y
|
||||
rotation = dataStorage.crs_rotation
|
||||
|
||||
pt = Point(
|
||||
x=pt_original.x, y=pt_original.y, z=pt_original.z, units=pt_original.units
|
||||
)
|
||||
|
||||
gisLayer = None
|
||||
try:
|
||||
gisLayer = dataStorage.latestHostApp.lower().endswith("gis")
|
||||
applyTransforms = False if (gisLayer and gisLayer is True) else True
|
||||
except Exception as e:
|
||||
print(e)
|
||||
applyTransforms = True
|
||||
|
||||
# for non-GIS layers
|
||||
if applyTransforms is True:
|
||||
if (
|
||||
rotation is not None
|
||||
and (isinstance(rotation, float) or isinstance(rotation, int))
|
||||
and -360 < rotation < 360
|
||||
):
|
||||
a = rotation * math.pi / 180
|
||||
x2 = pt.x
|
||||
y2 = pt.y
|
||||
|
||||
# if a > 0: # turn counterclockwise on receive
|
||||
x2 = pt.x * math.cos(a) - pt.y * math.sin(a)
|
||||
y2 = pt.x * math.sin(a) + pt.y * math.cos(a)
|
||||
|
||||
pt.x = x2
|
||||
pt.y = y2
|
||||
if (
|
||||
offset_x is not None
|
||||
and isinstance(offset_x, float)
|
||||
and offset_y is not None
|
||||
and isinstance(offset_y, float)
|
||||
):
|
||||
pt.x += offset_x
|
||||
pt.y += offset_y
|
||||
|
||||
# for GIS layers
|
||||
if gisLayer is True:
|
||||
try:
|
||||
offset_x = dataStorage.current_layer_crs_offset_x
|
||||
offset_y = dataStorage.current_layer_crs_offset_y
|
||||
rotation = dataStorage.current_layer_crs_rotation
|
||||
|
||||
if (
|
||||
rotation is not None
|
||||
and isinstance(rotation, float)
|
||||
and -360 < rotation < 360
|
||||
):
|
||||
a = rotation * math.pi / 180
|
||||
x2 = pt.x
|
||||
y2 = pt.y
|
||||
|
||||
# if a > 0: # turn counterclockwise on receive
|
||||
x2 = pt.x * math.cos(a) - pt.y * math.sin(a)
|
||||
y2 = pt.x * math.sin(a) + pt.y * math.cos(a)
|
||||
|
||||
pt.x = x2
|
||||
pt.y = y2
|
||||
if (
|
||||
offset_x is not None
|
||||
and isinstance(offset_x, float)
|
||||
and offset_y is not None
|
||||
and isinstance(offset_y, float)
|
||||
):
|
||||
pt.x += offset_x
|
||||
pt.y += offset_y
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
return pt
|
||||
|
||||
|
||||
def apply_pt_transform_matrix(pt: Point, dataStorage) -> Point:
|
||||
try:
|
||||
if dataStorage.matrix is not None:
|
||||
b = np.matrix([pt.x, pt.y, pt.z, 1])
|
||||
res = b * dataStorage.matrix
|
||||
x, y, z = res.item(0), res.item(1), res.item(2)
|
||||
return Point(x=x, y=y, z=z, units=pt.units)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return pt
|
||||
|
||||
|
||||
def speckleBoundaryToSpecklePts(boundary: Union[None, Polyline, Arc, Line, Polycurve]) -> List[Point]:
|
||||
@@ -28,4 +144,176 @@ def speckleBoundaryToSpecklePts(boundary: Union[None, Polyline, Arc, Line, Polyc
|
||||
except: pass # if Line or None
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
return polyBorder
|
||||
return polyBorder
|
||||
|
||||
|
||||
def speckleArcCircleToPoints(poly: Union[Arc, Circle]) -> List[Point]:
|
||||
print("__Arc or Circle to Points___")
|
||||
points = []
|
||||
try:
|
||||
#print(poly.plane)
|
||||
#print(poly.plane.normal)
|
||||
if poly.plane is None or poly.plane.normal.z == 0: normal = 1
|
||||
else: normal = poly.plane.normal.z
|
||||
#print(poly.plane.origin)
|
||||
if isinstance(poly, Circle):
|
||||
interval = 2*math.pi
|
||||
range_start = 0
|
||||
angle1 = 0
|
||||
|
||||
else: # if Arc
|
||||
points.append(poly.startPoint)
|
||||
range_start = 0
|
||||
|
||||
#angle1, angle2 = getArcAngles(poly)
|
||||
|
||||
interval, angle1, angle2 = getArcRadianAngle(poly)
|
||||
interval = abs(angle2 - angle1)
|
||||
|
||||
#print(angle1)
|
||||
#print(angle2)
|
||||
|
||||
if (angle1 > angle2 and normal == -1) or (angle2 > angle1 and normal == 1): pass
|
||||
if angle1 > angle2 and normal == 1: interval = abs( (2*math.pi-angle1) + angle2)
|
||||
if angle2 > angle1 and normal == -1: interval = abs( (2*math.pi-angle2) + angle1)
|
||||
|
||||
#print(interval)
|
||||
#print(normal)
|
||||
|
||||
pointsNum = math.floor( abs(interval)) * 12
|
||||
if pointsNum <4: pointsNum = 4
|
||||
|
||||
for i in range(range_start, pointsNum + 1):
|
||||
k = i/pointsNum # to reset values from 1/10 to 1
|
||||
angle = angle1 + k * interval * normal
|
||||
#print(k)
|
||||
#print(angle)
|
||||
pt = Point( x = poly.plane.origin.x + poly.radius * cos(angle), y = poly.plane.origin.y + poly.radius * sin(angle), z = 0)
|
||||
|
||||
pt.units = poly.plane.origin.units
|
||||
points.append(pt)
|
||||
if isinstance(poly, Arc): points.append(poly.endPoint)
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
return points
|
||||
|
||||
|
||||
|
||||
def getArcRadianAngle(arc: Arc) -> List[float]:
|
||||
try:
|
||||
interval = None
|
||||
normal = arc.plane.normal.z
|
||||
angle1, angle2 = getArcAngles(arc)
|
||||
if angle1 is None or angle2 is None: return None
|
||||
interval = abs(angle2 - angle1)
|
||||
|
||||
if (angle1 > angle2 and normal == -1) or (angle2 > angle1 and normal == 1): pass
|
||||
if angle1 > angle2 and normal == 1: interval = abs( (2*math.pi-angle1) + angle2)
|
||||
if angle2 > angle1 and normal == -1: interval = abs( (2*math.pi-angle2) + angle1)
|
||||
return interval, angle1, angle2
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
return None, None, None
|
||||
|
||||
def getArcAngles(poly: Arc) -> Tuple[float]:
|
||||
try:
|
||||
if poly.startPoint.x == poly.plane.origin.x: angle1 = math.pi/2
|
||||
else: angle1 = atan( abs ((poly.startPoint.y - poly.plane.origin.y) / (poly.startPoint.x - poly.plane.origin.x) )) # between 0 and pi/2
|
||||
|
||||
if poly.plane.origin.x < poly.startPoint.x and poly.plane.origin.y > poly.startPoint.y: angle1 = 2*math.pi - angle1
|
||||
if poly.plane.origin.x > poly.startPoint.x and poly.plane.origin.y > poly.startPoint.y: angle1 = math.pi + angle1
|
||||
if poly.plane.origin.x > poly.startPoint.x and poly.plane.origin.y < poly.startPoint.y: angle1 = math.pi - angle1
|
||||
|
||||
if poly.endPoint.x == poly.plane.origin.x: angle2 = math.pi/2
|
||||
else: angle2 = atan( abs ((poly.endPoint.y - poly.plane.origin.y) / (poly.endPoint.x - poly.plane.origin.x) )) # between 0 and pi/2
|
||||
|
||||
if poly.plane.origin.x < poly.endPoint.x and poly.plane.origin.y > poly.endPoint.y: angle2 = 2*math.pi - angle2
|
||||
if poly.plane.origin.x > poly.endPoint.x and poly.plane.origin.y > poly.endPoint.y: angle2 = math.pi + angle2
|
||||
if poly.plane.origin.x > poly.endPoint.x and poly.plane.origin.y < poly.endPoint.y: angle2 = math.pi - angle2
|
||||
|
||||
return angle1, angle2
|
||||
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
return None, None
|
||||
|
||||
|
||||
def specklePolycurveToPoints(poly: Polycurve) -> List[Point]:
|
||||
print("_____Speckle Polycurve to points____")
|
||||
points = []
|
||||
try:
|
||||
for segm in poly.segments:
|
||||
#print(segm)
|
||||
pts = []
|
||||
if isinstance(segm, Arc) or isinstance(segm, Circle): # or isinstance(segm, Curve):
|
||||
print("Arc or Curve")
|
||||
pts: List[Point] = speckleArcCircleToPoints(segm)
|
||||
elif isinstance(segm, Line):
|
||||
print("Line")
|
||||
pts: List[Point] = [segm.start, segm.end]
|
||||
elif isinstance(segm, Polyline):
|
||||
print("Polyline")
|
||||
pts: List[Point] = segm.as_points()
|
||||
|
||||
points.extend(pts)
|
||||
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
return points
|
||||
|
||||
|
||||
def getArcNormal(poly: Arc, midPt: Point):
|
||||
print("____getArcNormal___")
|
||||
try:
|
||||
angle1, angle2 = getArcAngles(poly)
|
||||
|
||||
if midPt.x == poly.plane.origin.x: angle = math.pi/2
|
||||
else: angle = atan( abs ((midPt.y - poly.plane.origin.y) / (midPt.x - poly.plane.origin.x) )) # between 0 and pi/2
|
||||
|
||||
if poly.plane.origin.x < midPt.x and poly.plane.origin.y > midPt.y: angle = 2*math.pi - angle
|
||||
if poly.plane.origin.x > midPt.x and poly.plane.origin.y > midPt.y: angle = math.pi + angle
|
||||
if poly.plane.origin.x > midPt.x and poly.plane.origin.y < midPt.y: angle = math.pi - angle
|
||||
|
||||
normal = Vector()
|
||||
normal.x = normal.y = 0
|
||||
|
||||
if angle1 > angle > angle2: normal.z = -1
|
||||
if angle1 > angle2 > angle: normal.z = 1
|
||||
|
||||
if angle2 > angle1 > angle: normal.z = -1
|
||||
if angle > angle1 > angle2: normal.z = 1
|
||||
|
||||
if angle2 > angle > angle1: normal.z = 1
|
||||
if angle > angle2 > angle1: normal.z = -1
|
||||
|
||||
print(angle1)
|
||||
print(angle)
|
||||
print(angle2)
|
||||
print(normal)
|
||||
return normal
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
return None
|
||||
|
||||
|
||||
def getArcCenter(p1: Point, p2: Point, p3: Point) -> Tuple[List, float]:
|
||||
#print(p1)
|
||||
try:
|
||||
p1 = np.array(p1.to_list())
|
||||
p2 = np.array(p2.to_list())
|
||||
p3 = np.array(p3.to_list())
|
||||
a = np.linalg.norm(p3 - p2)
|
||||
b = np.linalg.norm(p3 - p1)
|
||||
c = np.linalg.norm(p2 - p1)
|
||||
s = (a + b + c) / 2
|
||||
radius = a*b*c / 4 / np.sqrt(s * (s - a) * (s - b) * (s - c))
|
||||
b1 = a*a * (b*b + c*c - a*a)
|
||||
b2 = b*b * (a*a + c*c - b*b)
|
||||
b3 = c*c * (a*a + b*b - c*c)
|
||||
center = np.column_stack((p1, p2, p3)).dot(np.hstack((b1, b2, b3)))
|
||||
center /= b1 + b2 + b3
|
||||
center = center.tolist()
|
||||
return center, radius
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
return None, None
|
||||
|
||||
@@ -11,32 +11,19 @@ from typing import Any, List, Tuple, Union
|
||||
#from regex import D
|
||||
|
||||
import inspect
|
||||
from specklepy.objects.GIS.CRS import CRS
|
||||
from specklepy.objects.GIS.layers import VectorLayer, RasterLayer, Layer
|
||||
|
||||
try:
|
||||
from speckle.speckle.converter.layers.CRS import CRS
|
||||
from speckle.speckle.converter.layers.Layer import Layer, VectorLayer, RasterLayer
|
||||
from speckle.speckle.converter.layers.symbology import vectorRendererToNative, rasterRendererToNative, rendererToSpeckle, cadBimRendererToNative
|
||||
from speckle.speckle.converter.layers.feature import featureToNative, featureToSpeckle, cadFeatureToNative, bimFeatureToNative, rasterFeatureToSpeckle
|
||||
from speckle.speckle.plugin_utils.helpers import findOrCreatePath, findFeatColors
|
||||
from speckle.speckle.converter.layers.symbology import vectorRendererToNative, rasterRendererToNative, rendererToSpeckle, cadBimRendererToNative
|
||||
from speckle.speckle.converter.layers.feature import featureToNative, featureToSpeckle, cadFeatureToNative, bimFeatureToNative, rasterFeatureToSpeckle
|
||||
from speckle.speckle.plugin_utils.helpers import findOrCreatePath, findFeatColors
|
||||
|
||||
from speckle.speckle.converter.geometry.mesh import constructMeshFromRaster, meshToNative, writeMeshToShp
|
||||
from speckle.speckle.converter.layers.utils import findTransformation
|
||||
from speckle.speckle.converter.layers.utils import getLayerAttributes, newLayerGroupAndName, validate_path
|
||||
from speckle.speckle.plugin_utils.helpers import validateNewFclassName, removeSpecialCharacters
|
||||
from speckle.speckle.ui.logger import logToUser
|
||||
from speckle.speckle.converter.geometry.mesh import constructMeshFromRaster, meshToNative, writeMeshToShp
|
||||
from speckle.speckle.converter.layers.utils import findTransformation
|
||||
from speckle.speckle.converter.layers.utils import getLayerAttributes, newLayerGroupAndName, validate_path
|
||||
from speckle.speckle.plugin_utils.helpers import validateNewFclassName, removeSpecialCharacters
|
||||
from speckle.speckle.utils.panel_logging import logToUser
|
||||
|
||||
except:
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.layers.CRS import CRS
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.layers.Layer import Layer, VectorLayer, RasterLayer
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.layers.symbology import vectorRendererToNative, rasterRendererToNative, rendererToSpeckle, cadBimRendererToNative
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.layers.feature import featureToNative, featureToSpeckle, cadFeatureToNative, bimFeatureToNative, rasterFeatureToSpeckle
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.plugin_utils.helpers import findOrCreatePath, findFeatColors
|
||||
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.geometry.mesh import constructMeshFromRaster, meshToNative, writeMeshToShp
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.layers.utils import findTransformation
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.layers.utils import getLayerAttributes, newLayerGroupAndName, validate_path
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.plugin_utils.helpers import validateNewFclassName, removeSpecialCharacters
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.ui.logger import logToUser
|
||||
|
||||
from specklepy.objects import Base
|
||||
from specklepy.objects.geometry import Mesh
|
||||
@@ -84,7 +71,7 @@ def getLayers(plugin, bySelection = False ) -> List[arcLayer]:
|
||||
# issue with getting selected layers: https://community.esri.com/t5/python-questions/determining-selected-layers-in-the-table-of/td-p/252098
|
||||
|
||||
self = plugin.dockwidget
|
||||
project = plugin.gis_project
|
||||
project = plugin.project
|
||||
all_layers = getAllProjLayers(project)
|
||||
|
||||
if bySelection is True: # by selection
|
||||
@@ -167,6 +154,7 @@ def layerToSpeckle(layer: arcLayer, project: ArcGISProject) -> Union[VectorLayer
|
||||
try:
|
||||
|
||||
projectCRS = project.activeMap.spatialReference
|
||||
logToUser(str(projectCRS.xy_units()), level=2, func = inspect.stack()[0][3])
|
||||
try: data = arcpy.Describe(layer.dataSource)
|
||||
except OSError as e:
|
||||
logToUser(str(e.args[0]), level=2, func = inspect.stack()[0][3])
|
||||
@@ -192,8 +180,6 @@ def layerToSpeckle(layer: arcLayer, project: ArcGISProject) -> Union[VectorLayer
|
||||
speckleLayer.name = layerName
|
||||
speckleLayer.crs = speckleReprojectedCrs
|
||||
speckleLayer.renderer = rendererToSpeckle(project, project.activeMap, layer, None)
|
||||
#speckleLayer.datum = datum
|
||||
|
||||
|
||||
try: # https://pro.arcgis.com/en/pro-app/2.8/arcpy/get-started/the-spatial-reference-object.htm
|
||||
|
||||
@@ -283,7 +269,7 @@ def layerToSpeckle(layer: arcLayer, project: ArcGISProject) -> Union[VectorLayer
|
||||
def layerToNative(layer: Any, streamBranch: str, plugin=None) -> arcLayer:
|
||||
print("________________________________________Layer to Native")
|
||||
try:
|
||||
project = plugin.gis_project
|
||||
project = plugin.project
|
||||
|
||||
layer_elements = layer.elements
|
||||
if layer_elements is None or len(layer_elements)==0:
|
||||
@@ -379,7 +365,7 @@ def bimLayerToNative(layerContentList: List[Base], layerName: str, streamBranch:
|
||||
|
||||
layerName = removeSpecialCharacters(layerName)
|
||||
|
||||
project = plugin.gis_project
|
||||
project = plugin.project
|
||||
geom_meshes = []
|
||||
layer_meshes = None
|
||||
#filter speckle objects by type within each layer, create sub-layer for each type (points, lines, polygons, mesh?)
|
||||
@@ -391,7 +377,6 @@ def bimLayerToNative(layerContentList: List[Base], layerName: str, streamBranch:
|
||||
for p in geom_old.get_dynamic_member_names():
|
||||
if p not in fields_to_ignore:
|
||||
geom[p] = geom_old[p]
|
||||
|
||||
except: geom = geom_old
|
||||
|
||||
if isinstance(geom, List):
|
||||
@@ -682,7 +667,7 @@ def cadLayerToNative(layerContentList: List[Base], layerName: str, streamBranch:
|
||||
try:
|
||||
geom_points = []
|
||||
geom_polylines = []
|
||||
project = plugin.gis_project
|
||||
project = plugin.project
|
||||
print(layerName)
|
||||
geom_polygones = []
|
||||
geom_meshes = []
|
||||
|
||||
@@ -14,22 +14,22 @@ from arcpy._mp import ArcGISProject, Map, Layer as arcLayer
|
||||
import inspect
|
||||
|
||||
try:
|
||||
from speckle.speckle.converter.geometry import convertToSpeckle, convertToNative, convertToNativeMulti
|
||||
from speckle.speckle.converter.geometry.conversions import convertToSpeckle, convertToNative, convertToNativeMulti
|
||||
from speckle.speckle.converter.layers.utils import (findTransformation, getVariantFromValue, traverseDict,
|
||||
traverseDictByKey, hsv_to_rgb)
|
||||
from speckle.speckle.converter.geometry.point import pointToSpeckle
|
||||
from speckle.speckle.converter.geometry.mesh import constructMeshFromRaster, meshToNative
|
||||
from speckle.speckle.converter.layers.symbology import jsonFromLayerStyle
|
||||
from speckle.speckle.ui.logger import logToUser
|
||||
from speckle.speckle.utils.panel_logging import logToUser
|
||||
from speckle.speckle.plugin_utils.helpers import findOrCreatePath
|
||||
except:
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.geometry import convertToSpeckle, convertToNative, convertToNativeMulti
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.geometry.conversions import convertToSpeckle, convertToNative, convertToNativeMulti
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.layers.utils import (findTransformation, getVariantFromValue, traverseDict,
|
||||
traverseDictByKey, hsv_to_rgb)
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.geometry.point import pointToSpeckle
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.geometry.mesh import constructMeshFromRaster, meshToNative
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.layers.symbology import jsonFromLayerStyle
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.ui.logger import logToUser
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.utils.panel_logging import logToUser
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.plugin_utils.helpers import findOrCreatePath
|
||||
|
||||
import numpy as np
|
||||
|
||||
@@ -16,14 +16,9 @@ from arcpy.management import (CreateFeatureclass, MakeFeatureLayer,
|
||||
from specklepy.objects import Base
|
||||
from specklepy.objects.other import RenderMaterial
|
||||
|
||||
try:
|
||||
from speckle.speckle.converter.layers.Layer import Layer, VectorLayer, RasterLayer
|
||||
from speckle.speckle.ui.logger import logToUser
|
||||
from speckle.speckle.plugin_utils.helpers import findOrCreatePath
|
||||
except:
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.layers.Layer import Layer, VectorLayer, RasterLayer
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.ui.logger import logToUser
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.plugin_utils.helpers import findOrCreatePath
|
||||
from specklepy.objects.GIS.layers import Layer, VectorLayer, RasterLayer
|
||||
from speckle.speckle.utils.panel_logging import logToUser
|
||||
from speckle.speckle.plugin_utils.helpers import findOrCreatePath
|
||||
|
||||
def jsonFromLayerStyle(layerArcgis, path_style):
|
||||
# write updated renderer to file and get layerStyle variable
|
||||
|
||||
@@ -1,64 +1,165 @@
|
||||
from datetime import datetime
|
||||
from typing import Dict, Any, List, Union
|
||||
import json
|
||||
import json
|
||||
import hashlib
|
||||
from specklepy.objects import Base
|
||||
import arcpy
|
||||
from specklepy.objects.geometry import Mesh
|
||||
from specklepy.objects.other import Collection
|
||||
|
||||
import arcpy
|
||||
from arcpy._mp import ArcGISProject, Map, Layer as arcLayer
|
||||
import os
|
||||
|
||||
import inspect
|
||||
|
||||
from PyQt5.QtGui import QColor
|
||||
|
||||
try:
|
||||
from speckle.speckle.converter.layers.emptyLayerTemplates import createGroupLayer
|
||||
from speckle.speckle.plugin_utils.helpers import findOrCreatePath
|
||||
from speckle.speckle.ui.logger import logToUser
|
||||
from speckle.speckle.plugin_utils.helpers import validateNewFclassName
|
||||
from speckle.speckle.converter.layers.emptyLayerTemplates import createGroupLayer
|
||||
from speckle.speckle.plugin_utils.helpers import findOrCreatePath, SYMBOL
|
||||
from speckle.speckle.utils.panel_logging import logToUser
|
||||
from speckle.speckle.plugin_utils.helpers import validateNewFclassName
|
||||
|
||||
except:
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.layers.emptyLayerTemplates import createGroupLayer
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.plugin_utils.helpers import findOrCreatePath
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.ui.logger import logToUser
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.plugin_utils.helpers import validateNewFclassName
|
||||
|
||||
#ATTRS_REMOVE = ['geometry','applicationId','bbox','displayStyle', 'id', 'renderMaterial', 'displayMesh', 'displayValue']
|
||||
ATTRS_REMOVE = ['speckleTyp','speckle_id','geometry','applicationId','bbox','displayStyle', 'id', 'renderMaterial', 'displayMesh', 'displayValue']
|
||||
# ATTRS_REMOVE = ['geometry','applicationId','bbox','displayStyle', 'id', 'renderMaterial', 'displayMesh', 'displayValue']
|
||||
ATTRS_REMOVE = [
|
||||
"speckleTyp",
|
||||
"speckle_id",
|
||||
"geometry",
|
||||
"applicationId",
|
||||
"bbox",
|
||||
"displayStyle",
|
||||
"id",
|
||||
"renderMaterial",
|
||||
"displayMesh",
|
||||
"displayValue",
|
||||
]
|
||||
|
||||
|
||||
def findAndClearLayerGroup(gis_project: ArcGISProject, newGroupName: str = ""):
|
||||
|
||||
def generate_qgis_app_id(
|
||||
base: Base,
|
||||
layer,
|
||||
f,
|
||||
):
|
||||
"""Generate unique ID for Vector feature."""
|
||||
return ""
|
||||
try:
|
||||
fieldnames = [str(field.name()) for field in layer.fields()]
|
||||
props = [str(f[prop]) for prop in fieldnames]
|
||||
try:
|
||||
geoms = f.geometry()
|
||||
except Exception as e:
|
||||
geoms = ""
|
||||
|
||||
id_data: str = (
|
||||
layer.id()
|
||||
+ str(layer.wkbType())
|
||||
+ str(fieldnames)
|
||||
+ str(props)
|
||||
+ str(geoms)
|
||||
)
|
||||
return hashlib.md5(id_data.encode("utf-8")).hexdigest()
|
||||
|
||||
except Exception as e:
|
||||
logToUser(
|
||||
f"Application ID not generated for feature in layer {layer.name()}: {e}",
|
||||
level=1,
|
||||
)
|
||||
return ""
|
||||
|
||||
|
||||
def generate_qgis_raster_app_id(rasterLayer):
|
||||
"""Generate unique ID for Raster layer."""
|
||||
return ""
|
||||
try:
|
||||
id_data = str(get_raster_stats(rasterLayer))
|
||||
file_ds = gdal.Open(rasterLayer.source(), gdal.GA_ReadOnly)
|
||||
for i in range(rasterLayer.bandCount()):
|
||||
band = file_ds.GetRasterBand(i + 1)
|
||||
id_data += str(band.ReadAsArray())
|
||||
return hashlib.md5(id_data.encode("utf-8")).hexdigest()
|
||||
|
||||
except Exception as e:
|
||||
logToUser(
|
||||
f"Application ID not generated for layer {rasterLayer.name()}: {e}",
|
||||
level=1,
|
||||
)
|
||||
return ""
|
||||
|
||||
|
||||
def collectionsFromJson(
|
||||
jsonObj: dict, levels: list, layerConverted, baseCollection: Collection
|
||||
):
|
||||
if jsonObj == {} or len(levels) == 0:
|
||||
# print("RETURN")
|
||||
baseCollection.elements.append(layerConverted)
|
||||
return baseCollection
|
||||
|
||||
lastLevel = baseCollection
|
||||
for i, l in enumerate(levels):
|
||||
sub_collection_found = 0
|
||||
for item in lastLevel.elements:
|
||||
# print("___ITEM")
|
||||
# print(l)
|
||||
if item.name == l:
|
||||
# print("___ITEM FOUND")
|
||||
# print(l)
|
||||
lastLevel = item
|
||||
sub_collection_found = 1
|
||||
break
|
||||
if sub_collection_found == 0:
|
||||
# print("___ SUB COLLECTION NOT FOUND")
|
||||
subCollection = Collection(
|
||||
units="m", collectionType="QGIS Layer Group", name=l, elements=[]
|
||||
)
|
||||
lastLevel.elements.append(subCollection)
|
||||
lastLevel = lastLevel.elements[
|
||||
len(lastLevel.elements) - 1
|
||||
] # reassign last element
|
||||
|
||||
if i == len(levels) - 1: # if last level
|
||||
lastLevel.elements.append(layerConverted)
|
||||
|
||||
return baseCollection
|
||||
|
||||
|
||||
def findAndClearLayerGroup(project: ArcGISProject, newGroupName: str = ""):
|
||||
print("find And Clear LayerGroup")
|
||||
try:
|
||||
groupExists = 0
|
||||
print(newGroupName)
|
||||
for l in gis_project.activeMap.listLayers():
|
||||
#print(l.longName)
|
||||
for l in project.activeMap.listLayers():
|
||||
# print(l.longName)
|
||||
if l.longName.startswith(newGroupName + "\\"):
|
||||
#print(l.longName)
|
||||
# print(l.longName)
|
||||
if l.isFeatureLayer:
|
||||
# condition for feature layers:
|
||||
fields = [f.name for f in arcpy.ListFields(l.dataSource)]
|
||||
fields = [f.name for f in arcpy.ListFields(l.dataSource)]
|
||||
print(fields)
|
||||
if "Speckle_ID" in fields or "speckle_id" in fields:
|
||||
gis_project.activeMap.removeLayer(l)
|
||||
groupExists+=1
|
||||
project.activeMap.removeLayer(l)
|
||||
groupExists += 1
|
||||
elif l.isRasterLayer:
|
||||
# condition for raster layers:
|
||||
# condition for raster layers:
|
||||
if "_Speckle" in l.name:
|
||||
gis_project.activeMap.removeLayer(l)
|
||||
groupExists+=1
|
||||
project.activeMap.removeLayer(l)
|
||||
groupExists += 1
|
||||
|
||||
elif l.longName == newGroupName:
|
||||
groupExists+=1
|
||||
elif l.longName == newGroupName:
|
||||
groupExists += 1
|
||||
print(newGroupName)
|
||||
if groupExists == 0:
|
||||
# create empty group layer file "\\Layers_Speckle\\
|
||||
|
||||
path: str = os.path.expandvars(r'%LOCALAPPDATA%') + "\\Temp\\Speckle_ArcGIS_temp\\" + datetime.now().strftime("%Y-%m-%d %H-%M")
|
||||
|
||||
path: str = (
|
||||
os.path.expandvars(r"%LOCALAPPDATA%")
|
||||
+ "\\Temp\\Speckle_ArcGIS_temp\\"
|
||||
+ datetime.now().strftime("%Y-%m-%d %H-%M")
|
||||
)
|
||||
path += "\\Layers_Speckle\\"
|
||||
findOrCreatePath(path)
|
||||
|
||||
#path = "\\".join(gis_project.filePath.split("\\")[:-1]) + "\\Layers_Speckle\\"
|
||||
#findOrCreatePath(path)
|
||||
# path = "\\".join(project.filePath.split("\\")[:-1]) + "\\Layers_Speckle\\"
|
||||
# findOrCreatePath(path)
|
||||
lyr_path = path + newGroupName + ".lyrx"
|
||||
print(lyr_path)
|
||||
try:
|
||||
@@ -67,207 +168,375 @@ def findAndClearLayerGroup(gis_project: ArcGISProject, newGroupName: str = ""):
|
||||
f.write(content)
|
||||
f.close()
|
||||
newGroupLayer = arcpy.mp.LayerFile(lyr_path)
|
||||
layerGroup = gis_project.activeMap.addLayer(newGroupLayer)[0]
|
||||
layerGroup = project.activeMap.addLayer(newGroupLayer)[0]
|
||||
print(layerGroup)
|
||||
except: # for 3.0.0
|
||||
if gis_project.active_map is not None:
|
||||
except: # for 3.0.0
|
||||
if project.active_map is not None:
|
||||
print("try creating the group")
|
||||
layerGroup = gis_project.activeMap.createGroupLayer(newGroupName)
|
||||
layerGroup = project.activeMap.createGroupLayer(newGroupName)
|
||||
print(layerGroup)
|
||||
else:
|
||||
logToUser("The map didn't fully load, try selecting the project Map or/and refreshing the plugin.", level=1, func = inspect.stack()[0][3])
|
||||
logToUser(
|
||||
"The map didn't fully load, try selecting the project Map or/and refreshing the plugin.",
|
||||
level=1,
|
||||
func=inspect.stack()[0][3],
|
||||
)
|
||||
return
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
|
||||
|
||||
def getVariantFromValue(value: Any) -> Union[str, None]:
|
||||
#print("_________get variant from value_______")
|
||||
# print("_________get variant from value_______")
|
||||
# TODO add Base object
|
||||
res = None
|
||||
try:
|
||||
pairs = [
|
||||
(str, "TEXT"), # 10
|
||||
(float, "FLOAT"),
|
||||
(int, "LONG"),
|
||||
(bool, "SHORT")
|
||||
]
|
||||
pairs = [(str, "TEXT"), (float, "FLOAT"), (int, "LONG"), (bool, "SHORT")] # 10
|
||||
for p in pairs:
|
||||
if isinstance(value, p[0]):
|
||||
if isinstance(value, p[0]):
|
||||
res = p[1]
|
||||
try:
|
||||
if res == "LONG" and (value>= 2147483647 or value<= -2147483647):
|
||||
#https://pro.arcgis.com/en/pro-app/latest/help/data/geodatabases/overview/arcgis-field-data-types.htm
|
||||
if res == "LONG" and (value >= 2147483647 or value <= -2147483647):
|
||||
# https://pro.arcgis.com/en/pro-app/latest/help/data/geodatabases/overview/arcgis-field-data-types.htm
|
||||
res = "FLOAT"
|
||||
except Exception as e: print(e)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
break
|
||||
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
|
||||
return res
|
||||
|
||||
def getLayerAttributes(featuresList: List[Base], attrsToRemove: List[str] = ATTRS_REMOVE ) -> Dict[str, str]:
|
||||
|
||||
def colorFromSpeckle(rgb):
|
||||
try:
|
||||
color = QColor.fromRgb(245, 245, 245)
|
||||
if isinstance(rgb, int):
|
||||
r = (rgb & 0xFF0000) >> 16
|
||||
g = (rgb & 0xFF00) >> 8
|
||||
b = rgb & 0xFF
|
||||
color = QColor.fromRgb(r, g, b)
|
||||
return color
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3])
|
||||
return QColor.fromRgb(245, 245, 245)
|
||||
|
||||
|
||||
def getDisplayValueList(geom: Any) -> List:
|
||||
try:
|
||||
# print("___getDisplayValueList")
|
||||
val = []
|
||||
# get list of display values for Meshes
|
||||
if isinstance(geom, Mesh):
|
||||
val = [geom]
|
||||
elif isinstance(geom, List) and len(geom) > 0:
|
||||
if isinstance(geom[0], Mesh):
|
||||
val = geom
|
||||
else:
|
||||
print("not an individual geometry")
|
||||
else:
|
||||
try:
|
||||
val = geom.displayValue # list
|
||||
except Exception as e:
|
||||
print(e)
|
||||
try:
|
||||
val = geom["@displayValue"] # list
|
||||
except Exception as e:
|
||||
print(e)
|
||||
try:
|
||||
val = geom.displayMesh
|
||||
except:
|
||||
pass
|
||||
return val
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return []
|
||||
|
||||
|
||||
def getLayerGeomType(layer) -> str:
|
||||
return
|
||||
|
||||
|
||||
def tryCreateGroupTree(root, fullGroupName, plugin=None):
|
||||
return
|
||||
# CREATE A GROUP "received blabla" with sublayers
|
||||
# print("_________CREATE GROUP TREE: " + fullGroupName)
|
||||
|
||||
# receive_layer_tree: dict = plugin.receive_layer_tree
|
||||
receive_layer_list = fullGroupName.split(SYMBOL)
|
||||
path_list = []
|
||||
for x in receive_layer_list:
|
||||
if len(x) > 0:
|
||||
path_list.append(x)
|
||||
group_to_create_name = path_list[0]
|
||||
|
||||
layerGroup = QgsLayerTreeGroup(group_to_create_name)
|
||||
if root.findGroup(group_to_create_name) is not None:
|
||||
layerGroup = root.findGroup(group_to_create_name) # -> QgsLayerTreeNode
|
||||
else:
|
||||
layerGroup = root.insertGroup(
|
||||
0, group_to_create_name
|
||||
) # root.addChildNode(layerGroup)
|
||||
layerGroup.setExpanded(True)
|
||||
layerGroup.setItemVisibilityChecked(True)
|
||||
|
||||
path_list.pop(0)
|
||||
|
||||
if len(path_list) > 0:
|
||||
layerGroup = tryCreateGroupTree(layerGroup, SYMBOL.join(path_list), plugin)
|
||||
|
||||
return layerGroup
|
||||
|
||||
|
||||
def validateAttributeName(name: str, fieldnames: List[str]) -> str:
|
||||
try:
|
||||
new_list = [x for x in fieldnames if x != name]
|
||||
|
||||
corrected = name.replace("/", "_").replace(".", "_")
|
||||
if corrected == "id":
|
||||
corrected = "applicationId"
|
||||
|
||||
for i, x in enumerate(corrected):
|
||||
if corrected[0] != "_" and corrected not in new_list:
|
||||
break
|
||||
else:
|
||||
corrected = corrected[1:]
|
||||
|
||||
if len(corrected) <= 1 and len(name) > 1:
|
||||
corrected = "0" + name # if the loop removed the property name completely
|
||||
|
||||
return corrected
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3])
|
||||
return
|
||||
|
||||
|
||||
def trySaveCRS(crs, streamBranch: str = ""):
|
||||
return
|
||||
try:
|
||||
authid = crs.authid()
|
||||
wkt = crs.toWkt()
|
||||
if authid == "":
|
||||
crs_id = crs.saveAsUserCrs("SpeckleCRS_" + streamBranch)
|
||||
return crs_id
|
||||
else:
|
||||
return crs.srsid()
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3])
|
||||
return
|
||||
|
||||
|
||||
def getLayerAttributes(
|
||||
featuresList: List[Base], attrsToRemove: List[str] = ATTRS_REMOVE
|
||||
) -> Dict[str, str]:
|
||||
print("03________ get layer attributes")
|
||||
fields = {}
|
||||
try:
|
||||
if not isinstance(featuresList, list): features = [featuresList]
|
||||
else: features = featuresList[:]
|
||||
|
||||
try:
|
||||
if not isinstance(featuresList, list):
|
||||
features = [featuresList]
|
||||
else:
|
||||
features = featuresList[:]
|
||||
|
||||
all_props = []
|
||||
for feature in features:
|
||||
#get object properties to add as attributes
|
||||
for feature in features:
|
||||
# get object properties to add as attributes
|
||||
dynamicProps = feature.get_dynamic_member_names()
|
||||
for att in ATTRS_REMOVE:
|
||||
try: dynamicProps.remove(att)
|
||||
except: pass
|
||||
|
||||
try:
|
||||
dynamicProps.remove(att)
|
||||
except:
|
||||
pass
|
||||
|
||||
dynamicProps.sort()
|
||||
|
||||
# add field names and variands
|
||||
# add field names and variands
|
||||
for name in dynamicProps:
|
||||
#if name not in all_props: all_props.append(name)
|
||||
# if name not in all_props: all_props.append(name)
|
||||
|
||||
value = feature[name]
|
||||
variant = getVariantFromValue(value)
|
||||
#if name == 'area': print(value); print(variant)
|
||||
if not variant: variant = None #LongLong #4
|
||||
# if name == 'area': print(value); print(variant)
|
||||
if not variant:
|
||||
variant = None # LongLong #4
|
||||
|
||||
# go thought the dictionary object
|
||||
if value and isinstance(value, list):
|
||||
#all_props.remove(name) # remove generic dict name
|
||||
# all_props.remove(name) # remove generic dict name
|
||||
for i, val_item in enumerate(value):
|
||||
newF, newVals = traverseDict( {}, {}, name+"_"+str(i), val_item)
|
||||
newF, newVals = traverseDict(
|
||||
{}, {}, name + "_" + str(i), val_item
|
||||
)
|
||||
|
||||
for i, (k,v) in enumerate(newF.items()):
|
||||
if k not in all_props: all_props.append(k)
|
||||
if k not in fields.keys(): fields.update({k: v})
|
||||
else: #check if the field was empty previously:
|
||||
for i, (k, v) in enumerate(newF.items()):
|
||||
if k not in all_props:
|
||||
all_props.append(k)
|
||||
if k not in fields.keys():
|
||||
fields.update({k: v})
|
||||
else: # check if the field was empty previously:
|
||||
oldVariant = fields[k]
|
||||
# replace if new one is NOT Float (too large integers)
|
||||
#if oldVariant != "FLOAT" and v == "FLOAT":
|
||||
# fields.update({k: v})
|
||||
# if oldVariant != "FLOAT" and v == "FLOAT":
|
||||
# fields.update({k: v})
|
||||
# replace if new one is NOT LongLong or IS String
|
||||
if oldVariant != "TEXT" and v == "TEXT":
|
||||
fields.update({k: v})
|
||||
|
||||
# add a field if not existing yet
|
||||
else: # if str, Base, etc
|
||||
newF, newVals = traverseDict( {}, {}, name, value)
|
||||
|
||||
for i, (k,v) in enumerate(newF.items()):
|
||||
if k not in all_props: all_props.append(k)
|
||||
if k not in fields.keys(): fields.update({k: v}) #if variant is known
|
||||
else: #check if the field was empty previously:
|
||||
if oldVariant != "TEXT" and v == "TEXT":
|
||||
fields.update({k: v})
|
||||
|
||||
# add a field if not existing yet
|
||||
else: # if str, Base, etc
|
||||
newF, newVals = traverseDict({}, {}, name, value)
|
||||
|
||||
for i, (k, v) in enumerate(newF.items()):
|
||||
if k not in all_props:
|
||||
all_props.append(k)
|
||||
if k not in fields.keys():
|
||||
fields.update({k: v}) # if variant is known
|
||||
else: # check if the field was empty previously:
|
||||
oldVariant = fields[k]
|
||||
# replace if new one is NOT Float (too large integers)
|
||||
#print(oldVariant, v)
|
||||
#if oldVariant == "LONG" and v == "FLOAT":
|
||||
# fields.update({k: v})
|
||||
# print(oldVariant, v)
|
||||
# if oldVariant == "LONG" and v == "FLOAT":
|
||||
# fields.update({k: v})
|
||||
# replace if new one is NOT LongLong or IS String
|
||||
if oldVariant != "TEXT" and v == "TEXT":
|
||||
fields.update({k: v})
|
||||
#print(fields)
|
||||
if oldVariant != "TEXT" and v == "TEXT":
|
||||
fields.update({k: v})
|
||||
# print(fields)
|
||||
# replace all empty ones wit String
|
||||
all_props.append("Speckle_ID")
|
||||
all_props.append("Speckle_ID")
|
||||
for name in all_props:
|
||||
if name not in fields.keys():
|
||||
fields.update({name: 'TEXT'})
|
||||
if name not in fields.keys():
|
||||
fields.update({name: "TEXT"})
|
||||
print(fields)
|
||||
#fields_sorted = {k: v for k, v in sorted(fields.items(), key=lambda item: item[0])}
|
||||
# fields_sorted = {k: v for k, v in sorted(fields.items(), key=lambda item: item[0])}
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
return fields
|
||||
|
||||
|
||||
def traverseDict(newF: dict, newVals: dict, nam: str, val: Any):
|
||||
try:
|
||||
if isinstance(val, dict):
|
||||
for i, (k,v) in enumerate(val.items()):
|
||||
newF, newVals = traverseDict( newF, newVals, nam+"_"+k, v)
|
||||
for i, (k, v) in enumerate(val.items()):
|
||||
newF, newVals = traverseDict(newF, newVals, nam + "_" + k, v)
|
||||
elif isinstance(val, Base):
|
||||
dynamicProps = val.get_dynamic_member_names()
|
||||
for att in ATTRS_REMOVE:
|
||||
try: dynamicProps.remove(att)
|
||||
except: pass
|
||||
try:
|
||||
dynamicProps.remove(att)
|
||||
except:
|
||||
pass
|
||||
dynamicProps.sort()
|
||||
|
||||
item_dict = {}
|
||||
item_dict = {}
|
||||
for prop in dynamicProps:
|
||||
item_dict.update({prop: val[prop]})
|
||||
|
||||
for i, (k,v) in enumerate(item_dict.items()):
|
||||
newF, newVals = traverseDict( newF, newVals, nam+"_"+k, v)
|
||||
else:
|
||||
for i, (k, v) in enumerate(item_dict.items()):
|
||||
newF, newVals = traverseDict(newF, newVals, nam + "_" + k, v)
|
||||
else:
|
||||
var = getVariantFromValue(val)
|
||||
if var is None:
|
||||
var = 'TEXT'
|
||||
if var is None:
|
||||
var = "TEXT"
|
||||
val = str(val)
|
||||
#print(var)
|
||||
# print(var)
|
||||
newF.update({nam: var})
|
||||
newVals.update({nam: val})
|
||||
newVals.update({nam: val})
|
||||
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
return newF, newVals
|
||||
|
||||
|
||||
def get_scale_factor(units: str) -> float:
|
||||
unit_scale = {
|
||||
"meters": 1.0,
|
||||
"centimeters": 0.01,
|
||||
"millimeters": 0.001,
|
||||
"inches": 0.0254,
|
||||
"feet": 0.3048,
|
||||
"kilometers": 1000.0,
|
||||
"mm": 0.001,
|
||||
"cm": 0.01,
|
||||
"m": 1.0,
|
||||
"km": 1000.0,
|
||||
"in": 0.0254,
|
||||
"ft": 0.3048,
|
||||
"yd": 0.9144,
|
||||
"mi": 1609.340,
|
||||
"meters": 1.0,
|
||||
"centimeters": 0.01,
|
||||
"millimeters": 0.001,
|
||||
"inches": 0.0254,
|
||||
"feet": 0.3048,
|
||||
"kilometers": 1000.0,
|
||||
"mm": 0.001,
|
||||
"cm": 0.01,
|
||||
"m": 1.0,
|
||||
"km": 1000.0,
|
||||
"in": 0.0254,
|
||||
"ft": 0.3048,
|
||||
"yd": 0.9144,
|
||||
"mi": 1609.340,
|
||||
}
|
||||
if units is not None and units.lower() in unit_scale.keys():
|
||||
return unit_scale[units]
|
||||
logToUser(f"Units {units} are not supported. Meters will be applied by default.", level=0, func = inspect.stack()[0][3])
|
||||
logToUser(
|
||||
f"Units {units} are not supported. Meters will be applied by default.",
|
||||
level=0,
|
||||
func=inspect.stack()[0][3],
|
||||
)
|
||||
return 1.0
|
||||
|
||||
def findTransformation(f_shape, geomType, layer_sr: arcpy.SpatialReference, projectCRS: arcpy.SpatialReference, selectedLayer: arcLayer):
|
||||
#apply transformation if needed
|
||||
|
||||
def findTransformation(
|
||||
f_shape,
|
||||
geomType,
|
||||
layer_sr: arcpy.SpatialReference,
|
||||
projectCRS: arcpy.SpatialReference,
|
||||
selectedLayer: arcLayer,
|
||||
):
|
||||
# apply transformation if needed
|
||||
try:
|
||||
if layer_sr.name != projectCRS.name:
|
||||
tr0 = tr1 = tr2 = tr_custom = None
|
||||
midSr = arcpy.SpatialReference("WGS 1984") # GCS_WGS_1984
|
||||
#print(layer_sr)
|
||||
midSr = arcpy.SpatialReference("WGS 1984") # GCS_WGS_1984
|
||||
# print(layer_sr)
|
||||
try:
|
||||
transformations = arcpy.ListTransformations(layer_sr, projectCRS)
|
||||
#print(transformations)
|
||||
customTransformName = "layer_sr.name"+"_To_"+ projectCRS.name
|
||||
# print(transformations)
|
||||
customTransformName = "layer_sr.name" + "_To_" + projectCRS.name
|
||||
if len(transformations) == 0:
|
||||
try:
|
||||
tr1 = arcpy.ListTransformations(layer_sr, midSr)[0]
|
||||
tr2 = arcpy.ListTransformations(midSr, projectCRS)[0]
|
||||
except:
|
||||
#customGeoTransfm = "GEOGTRAN[METHOD['Geocentric_Translation'],PARAMETER['X_Axis_Translation',''],PARAMETER['Y_Axis_Translation',''],PARAMETER['Z_Axis_Translation','']]"
|
||||
#CreateCustomGeoTransformation(customTransformName, layer_sr, projectCRS)
|
||||
except:
|
||||
# customGeoTransfm = "GEOGTRAN[METHOD['Geocentric_Translation'],PARAMETER['X_Axis_Translation',''],PARAMETER['Y_Axis_Translation',''],PARAMETER['Z_Axis_Translation','']]"
|
||||
# CreateCustomGeoTransformation(customTransformName, layer_sr, projectCRS)
|
||||
tr_custom = customTransformName
|
||||
else:
|
||||
#print("else")
|
||||
# choose equation based instead of file-based/grid-based method,
|
||||
else:
|
||||
# print("else")
|
||||
# choose equation based instead of file-based/grid-based method,
|
||||
# to be consistent with QGIS: https://desktop.arcgis.com/en/arcmap/latest/map/projections/choosing-an-appropriate-transformation.htm
|
||||
selecterTr = {}
|
||||
for tr in transformations:
|
||||
if "NTv2" not in tr and "NADCON" not in tr:
|
||||
set1 = set( layer_sr.name.split("_") + projectCRS.name.split("_") )
|
||||
set2 = set( tr.split("_") )
|
||||
diff = len( set(set1).symmetric_difference(set2) )
|
||||
if "NTv2" not in tr and "NADCON" not in tr:
|
||||
set1 = set(
|
||||
layer_sr.name.split("_") + projectCRS.name.split("_")
|
||||
)
|
||||
set2 = set(tr.split("_"))
|
||||
diff = len(set(set1).symmetric_difference(set2))
|
||||
selecterTr.update({tr: diff})
|
||||
selecterTr = dict(sorted(selecterTr.items(), key=lambda item: item[1]))
|
||||
selecterTr = dict(
|
||||
sorted(selecterTr.items(), key=lambda item: item[1])
|
||||
)
|
||||
tr0 = list(selecterTr.keys())[0]
|
||||
|
||||
if geomType != "Point" and geomType != "Polyline" and geomType != "Polygon" and geomType != "Multipoint" and geomType != "MultiPatch":
|
||||
try: logToUser("Unsupported or invalid geometry in layer " + selectedLayer.name, level=2, func = inspect.stack()[0][3])
|
||||
except: logToUser("Unsupported or invalid geometry", level=2, func = inspect.stack()[0][3])
|
||||
if (
|
||||
geomType != "Point"
|
||||
and geomType != "Polyline"
|
||||
and geomType != "Polygon"
|
||||
and geomType != "Multipoint"
|
||||
and geomType != "MultiPatch"
|
||||
):
|
||||
try:
|
||||
logToUser(
|
||||
"Unsupported or invalid geometry in layer "
|
||||
+ selectedLayer.name,
|
||||
level=2,
|
||||
func=inspect.stack()[0][3],
|
||||
)
|
||||
except:
|
||||
logToUser(
|
||||
"Unsupported or invalid geometry",
|
||||
level=2,
|
||||
func=inspect.stack()[0][3],
|
||||
)
|
||||
|
||||
# reproject geometry using chosen transformstion(s)
|
||||
if tr0 is not None:
|
||||
@@ -280,58 +549,87 @@ def findTransformation(f_shape, geomType, layer_sr: arcpy.SpatialReference, proj
|
||||
else:
|
||||
ptgeo1 = f_shape.projectAs(projectCRS)
|
||||
f_shape = ptgeo1
|
||||
|
||||
|
||||
except:
|
||||
logToUser(f"Spatial Transformation not found for layer {selectedLayer.name}", level=2, func = inspect.stack()[0][3])
|
||||
logToUser(
|
||||
f"Spatial Transformation not found for layer {selectedLayer.name}",
|
||||
level=2,
|
||||
func=inspect.stack()[0][3],
|
||||
)
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
return f_shape
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
return f_shape
|
||||
|
||||
def traverseDictByKey(d: Dict, key:str ="", result = None) -> Dict:
|
||||
|
||||
def traverseDictByKey(d: Dict, key: str = "", result=None) -> Dict:
|
||||
print("__traverse")
|
||||
try:
|
||||
result = None
|
||||
#print(d)
|
||||
# print(d)
|
||||
for k, v in d.items():
|
||||
|
||||
try: v = json.loads(v)
|
||||
except: pass
|
||||
|
||||
try:
|
||||
v = json.loads(v)
|
||||
except:
|
||||
pass
|
||||
if isinstance(v, dict):
|
||||
#print("__dict__")
|
||||
if k == key: print("__break loop"); result = v; return result
|
||||
else:
|
||||
# print("__dict__")
|
||||
if k == key:
|
||||
print("__break loop")
|
||||
result = v
|
||||
return result
|
||||
else:
|
||||
result = traverseDictByKey(v, key, result)
|
||||
if result is not None: return result
|
||||
if result is not None:
|
||||
return result
|
||||
if isinstance(v, list):
|
||||
for item in v:
|
||||
#print(item)
|
||||
if isinstance(item, dict):
|
||||
for item in v:
|
||||
# print(item)
|
||||
if isinstance(item, dict):
|
||||
result = traverseDictByKey(item, key, result)
|
||||
if result is not None: return result
|
||||
if result is not None:
|
||||
return result
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
return None
|
||||
#print("__result is: ____________")
|
||||
#return result
|
||||
# print("__result is: ____________")
|
||||
# return result
|
||||
|
||||
|
||||
def hsv_to_rgb(listHSV):
|
||||
try:
|
||||
h, s, v = listHSV[0], listHSV[1], listHSV[2]
|
||||
if s == 0.0: v*=255; return (v, v, v)
|
||||
i = int(h*6.) # XXX assume int() truncates!
|
||||
f = (h*6.)-i; p,q,t = int(255*(v*(1.-s))), int(255*(v*(1.-s*f))), int(255*(v*(1.-s*(1.-f)))); v*=255; i%=6
|
||||
if i == 0: return (v, t, p)
|
||||
if i == 1: return (q, v, p)
|
||||
if i == 2: return (p, v, t)
|
||||
if i == 3: return (p, q, v)
|
||||
if i == 4: return (t, p, v)
|
||||
if i == 5: return (v, p, q)
|
||||
|
||||
if s == 0.0:
|
||||
v *= 255
|
||||
return (v, v, v)
|
||||
i = int(h * 6.0) # XXX assume int() truncates!
|
||||
f = (h * 6.0) - i
|
||||
p, q, t = (
|
||||
int(255 * (v * (1.0 - s))),
|
||||
int(255 * (v * (1.0 - s * f))),
|
||||
int(255 * (v * (1.0 - s * (1.0 - f)))),
|
||||
)
|
||||
v *= 255
|
||||
i %= 6
|
||||
if i == 0:
|
||||
return (v, t, p)
|
||||
if i == 1:
|
||||
return (q, v, p)
|
||||
if i == 2:
|
||||
return (p, v, t)
|
||||
if i == 3:
|
||||
return (p, q, v)
|
||||
if i == 4:
|
||||
return (t, p, v)
|
||||
if i == 5:
|
||||
return (v, p, q)
|
||||
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
return (0,0,0)
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
return (0, 0, 0)
|
||||
|
||||
|
||||
def cmyk_to_rgb(c, m, y, k, cmyk_scale, rgb_scale=255):
|
||||
try:
|
||||
@@ -340,36 +638,43 @@ def cmyk_to_rgb(c, m, y, k, cmyk_scale, rgb_scale=255):
|
||||
b = rgb_scale * (1.0 - y / float(cmyk_scale)) * (1.0 - k / float(cmyk_scale))
|
||||
return r, g, b
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
return 0,0,0
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
return 0, 0, 0
|
||||
|
||||
def newLayerGroupAndName(layerName: str, streamBranch: str, project: ArcGISProject) -> str:
|
||||
|
||||
def newLayerGroupAndName(
|
||||
layerName: str, streamBranch: str, project: ArcGISProject
|
||||
) -> str:
|
||||
print("___new Layer Group and Name")
|
||||
layerGroup = None
|
||||
newGroupName = f'{streamBranch}'
|
||||
newGroupName = f"{streamBranch}"
|
||||
try:
|
||||
#CREATE A GROUP "received blabla" with sublayers
|
||||
# CREATE A GROUP "received blabla" with sublayers
|
||||
print(newGroupName)
|
||||
for l in project.activeMap.listLayers():
|
||||
if l.longName == newGroupName: layerGroup = l; break
|
||||
|
||||
#find a layer with a matching name in the "latest" group
|
||||
newName = f'{streamBranch.split("_")[len(streamBranch.split("_"))-1]}_{layerName}'
|
||||
if l.longName == newGroupName:
|
||||
layerGroup = l
|
||||
break
|
||||
|
||||
# find a layer with a matching name in the "latest" group
|
||||
newName = (
|
||||
f'{streamBranch.split("_")[len(streamBranch.split("_"))-1]}_{layerName}'
|
||||
)
|
||||
|
||||
all_layer_names = []
|
||||
layerExists = 0
|
||||
for l in project.activeMap.listLayers():
|
||||
for l in project.activeMap.listLayers():
|
||||
if l.longName.startswith(newGroupName + "\\"):
|
||||
all_layer_names.append(l.longName)
|
||||
#print(all_layer_names)
|
||||
# print(all_layer_names)
|
||||
print(newName)
|
||||
|
||||
newName = validateNewFclassName(newName, all_layer_names, streamBranch + "\\")
|
||||
|
||||
print(newName)
|
||||
return newName, layerGroup
|
||||
print(newName)
|
||||
return newName, layerGroup
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
return None, None
|
||||
|
||||
|
||||
@@ -379,36 +684,46 @@ def curvedFeatureClassToSegments(layer) -> str:
|
||||
data = arcpy.Describe(layer.dataSource)
|
||||
dataPath = data.catalogPath
|
||||
print(dataPath)
|
||||
newPath = dataPath+"_backup"
|
||||
newPath = dataPath + "_backup"
|
||||
|
||||
arcpy.management.CopyFeatures(dataPath, newPath) # features copied like this do not preserve curved segments
|
||||
arcpy.management.CopyFeatures(
|
||||
dataPath, newPath
|
||||
) # features copied like this do not preserve curved segments
|
||||
|
||||
arcpy.edit.Densify(in_features = newPath, densification_method = "ANGLE", max_angle = 0.01, max_vertex_per_segment = 100) # https://pro.arcgis.com/en/pro-app/latest/tool-reference/editing/densify.htm
|
||||
arcpy.edit.Densify(
|
||||
in_features=newPath,
|
||||
densification_method="ANGLE",
|
||||
max_angle=0.01,
|
||||
max_vertex_per_segment=100,
|
||||
) # https://pro.arcgis.com/en/pro-app/latest/tool-reference/editing/densify.htm
|
||||
print(newPath)
|
||||
return newPath
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
return None
|
||||
|
||||
|
||||
def validate_path(path: str):
|
||||
"""If our path contains a DB name, make sure we have a valid DB name and not a standard file name."""
|
||||
try:
|
||||
# https://github.com/EsriOceans/btm/commit/a9c0529485c9b0baa78c1f094372c0f9d83c0aaf
|
||||
dirname, file_name = os.path.split(path)
|
||||
#print(dirname)
|
||||
#print(file_name)
|
||||
# print(dirname)
|
||||
# print(file_name)
|
||||
file_base = os.path.splitext(file_name)[0]
|
||||
if dirname == '':
|
||||
if dirname == "":
|
||||
# a relative path only, relying on the workspace
|
||||
dirname = arcpy.env.workspace
|
||||
path_ext = os.path.splitext(dirname)[1].lower()
|
||||
if path_ext in ['.mdb', '.gdb', '.sde']:
|
||||
if path_ext in [".mdb", ".gdb", ".sde"]:
|
||||
# we're working in a database
|
||||
file_name = arcpy.ValidateTableName(file_base) # e.g. add a letter in front of the name
|
||||
file_name = arcpy.ValidateTableName(
|
||||
file_base
|
||||
) # e.g. add a letter in front of the name
|
||||
validated_path = os.path.join(dirname, file_name)
|
||||
#msg("validated path: %s; (from %s)" % (validated_path, path))
|
||||
# msg("validated path: %s; (from %s)" % (validated_path, path))
|
||||
return validated_path
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
return None
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
return None
|
||||
|
||||
@@ -1,99 +1,216 @@
|
||||
import os
|
||||
from typing import List
|
||||
import inspect
|
||||
import inspect
|
||||
|
||||
SYMBOL = "_x_x_"
|
||||
UNSUPPORTED_PROVIDERS = ["WFS", "wms", "wcs", "vectortile"]
|
||||
|
||||
|
||||
def get_scale_factor(units: str, dataStorage) -> float:
|
||||
scale_to_meter = get_scale_factor_to_meter(units)
|
||||
if dataStorage is not None:
|
||||
scale_back = scale_to_meter / get_scale_factor_to_meter(
|
||||
dataStorage.currentUnits
|
||||
)
|
||||
return scale_back
|
||||
else:
|
||||
return scale_to_meter
|
||||
|
||||
|
||||
def get_scale_factor_to_meter(units: str) -> float:
|
||||
try:
|
||||
unit_scale = {
|
||||
"meters": 1.0,
|
||||
"centimeters": 0.01,
|
||||
"millimeters": 0.001,
|
||||
"inches": 0.0254,
|
||||
"feet": 0.3048,
|
||||
"kilometers": 1000.0,
|
||||
"mm": 0.001,
|
||||
"cm": 0.01,
|
||||
"m": 1.0,
|
||||
"km": 1000.0,
|
||||
"in": 0.0254,
|
||||
"ft": 0.3048,
|
||||
"yd": 0.9144,
|
||||
"mi": 1609.340,
|
||||
}
|
||||
if (
|
||||
units is not None
|
||||
and isinstance(units, str)
|
||||
and units.lower() in unit_scale.keys()
|
||||
):
|
||||
return unit_scale[units]
|
||||
try:
|
||||
from speckle.speckle.utils.panel_logging import logToUser
|
||||
|
||||
logToUser(
|
||||
f"Units {units} are not supported. Meters will be applied by default.",
|
||||
level=1,
|
||||
func=inspect.stack()[0][3],
|
||||
)
|
||||
return 1.0
|
||||
except:
|
||||
print(
|
||||
f"Units {units} are not supported. Meters will be applied by default."
|
||||
)
|
||||
return 1.0
|
||||
except Exception as e:
|
||||
try:
|
||||
from speckle.speckle.utils.panel_logging import logToUser
|
||||
|
||||
logToUser(
|
||||
f"{e}. Meters will be applied by default.",
|
||||
level=2,
|
||||
func=inspect.stack()[0][3],
|
||||
)
|
||||
return 1.0
|
||||
except:
|
||||
print(f"{e}. Meters will be applied by default.")
|
||||
return 1.0
|
||||
|
||||
|
||||
def getAppName(name: str) -> str:
|
||||
new_name = ""
|
||||
for i, x in enumerate(str(name)):
|
||||
if x.lower() in [a for k,a in enumerate("abcdefghijklmnopqrstuvwxyz")]:
|
||||
if x.lower() in [a for k, a in enumerate("abcdefghijklmnopqrstuvwxyz")]:
|
||||
new_name += x
|
||||
else: break
|
||||
else:
|
||||
break
|
||||
return new_name
|
||||
|
||||
|
||||
def findOrCreatePath(path: str):
|
||||
if not os.path.exists(path):
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
|
||||
|
||||
def removeSpecialCharacters(text: str) -> str:
|
||||
new_text = text.replace("[","_").replace("]","_").replace(" ","_").replace("-","_").replace("(","_").replace(")","_").replace(":","_").replace("\\","_").replace("/","_").replace("\"","_").replace("&","_").replace("@","_").replace("$","_").replace("%","_").replace("^","_")
|
||||
#new_text = text.encode('iso-8859-1', errors='ignore').decode('utf-8')
|
||||
new_text = (
|
||||
text.replace("[", "_")
|
||||
.replace("]", "_")
|
||||
.replace(" ", "_")
|
||||
.replace("-", "_")
|
||||
.replace("(", "_")
|
||||
.replace(")", "_")
|
||||
.replace(":", "_")
|
||||
.replace("\\", "_")
|
||||
.replace("/", "_")
|
||||
.replace('"', "_")
|
||||
.replace("&", "_")
|
||||
.replace("@", "_")
|
||||
.replace("$", "_")
|
||||
.replace("%", "_")
|
||||
.replace("^", "_")
|
||||
)
|
||||
# new_text = text.encode('iso-8859-1', errors='ignore').decode('utf-8')
|
||||
return new_text
|
||||
|
||||
def splitTextIntoLines(text: str = "", number: int= 40) -> str:
|
||||
|
||||
def splitTextIntoLines(text: str = "", number: int = 40) -> str:
|
||||
print("__splitTextIntoLines")
|
||||
print(text)
|
||||
msg = ""
|
||||
try:
|
||||
if len(text)>number:
|
||||
if len(text) > number:
|
||||
try:
|
||||
for i, x in enumerate(text):
|
||||
msg += x
|
||||
if i!=0 and i%number == 0: msg += "\n"
|
||||
except Exception as e: print(e)
|
||||
else:
|
||||
if i != 0 and i % number == 0:
|
||||
msg += "\n"
|
||||
except Exception as e:
|
||||
print(e)
|
||||
else:
|
||||
msg = text
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print(text)
|
||||
|
||||
|
||||
return msg
|
||||
|
||||
def validateNewFclassName(newName: str, all_layer_names: List[str], prefix: str = "") -> str:
|
||||
|
||||
|
||||
def jsonFromList(jsonObj: dict, levels: list):
|
||||
# print("jsonFromList")
|
||||
if len(levels) == 0:
|
||||
return jsonObj
|
||||
lastLevel = jsonObj
|
||||
for l in levels:
|
||||
# print(lastLevel)
|
||||
try:
|
||||
lastLevel = lastLevel[l]
|
||||
except:
|
||||
lastLevel.update({l: {}})
|
||||
# print(jsonObj)
|
||||
return jsonObj
|
||||
|
||||
|
||||
def validateNewFclassName(
|
||||
newName: str, all_layer_names: List[str], prefix: str = ""
|
||||
) -> str:
|
||||
|
||||
fixed_name = newName
|
||||
|
||||
if (prefix + fixed_name) in all_layer_names:
|
||||
|
||||
if (prefix + fixed_name) in all_layer_names:
|
||||
|
||||
layerNameCreated = 0
|
||||
for index, letter in enumerate('234567890abcdefghijklmnopqrstuvwxyz'):
|
||||
if ((prefix + fixed_name) + "_" + letter) not in all_layer_names:
|
||||
fixed_name += "_"+letter
|
||||
layerNameCreated +=1
|
||||
break
|
||||
for index, letter in enumerate("234567890abcdefghijklmnopqrstuvwxyz"):
|
||||
if ((prefix + fixed_name) + "_" + letter) not in all_layer_names:
|
||||
fixed_name += "_" + letter
|
||||
layerNameCreated += 1
|
||||
break
|
||||
if layerNameCreated == 0:
|
||||
for index, letter in enumerate('234567890abcdefghijklmnopqrstuvwxyz'):
|
||||
test_fixed_name = validateNewFclassName((fixed_name + "_" + letter), all_layer_names, prefix)
|
||||
if (prefix + test_fixed_name) not in all_layer_names:
|
||||
fixed_name = test_fixed_name
|
||||
layerNameCreated +=1
|
||||
break
|
||||
#else: layerNameCreated +=1
|
||||
for index, letter in enumerate("234567890abcdefghijklmnopqrstuvwxyz"):
|
||||
test_fixed_name = validateNewFclassName(
|
||||
(fixed_name + "_" + letter), all_layer_names, prefix
|
||||
)
|
||||
if (prefix + test_fixed_name) not in all_layer_names:
|
||||
fixed_name = test_fixed_name
|
||||
layerNameCreated += 1
|
||||
break
|
||||
# else: layerNameCreated +=1
|
||||
|
||||
if layerNameCreated == 0:
|
||||
pass #logToUser('Feature class name already exists', level=2, func = inspect.stack()[0][3])
|
||||
#return fixed_name
|
||||
pass # logToUser('Feature class name already exists', level=2, func = inspect.stack()[0][3])
|
||||
# return fixed_name
|
||||
|
||||
return fixed_name
|
||||
|
||||
|
||||
|
||||
def findFeatColors(fetColors, f):
|
||||
|
||||
|
||||
colorFound = 0
|
||||
try: # get render material from any part of the mesh (list of items in displayValue)
|
||||
try: # get render material from any part of the mesh (list of items in displayValue)
|
||||
for k, item in enumerate(f.displayValue):
|
||||
try:
|
||||
fetColors.append(item.renderMaterial.diffuse)
|
||||
fetColors.append(item.renderMaterial.diffuse)
|
||||
colorFound += 1
|
||||
break
|
||||
except: pass
|
||||
if colorFound == 0: fetColors.append(f.renderMaterial.diffuse)
|
||||
except:
|
||||
except:
|
||||
pass
|
||||
if colorFound == 0:
|
||||
fetColors.append(f.renderMaterial.diffuse)
|
||||
except:
|
||||
try:
|
||||
for k, item in enumerate(f["@displayValue"]):
|
||||
try:
|
||||
fetColors.append(item.renderMaterial.diffuse)
|
||||
try:
|
||||
fetColors.append(item.renderMaterial.diffuse)
|
||||
colorFound += 1
|
||||
break
|
||||
except: pass
|
||||
if colorFound == 0: fetColors.append(f.renderMaterial.diffuse)
|
||||
except:
|
||||
# the Mesh itself has a renderer
|
||||
try: # get render material from any part of the mesh (list of items in displayValue)
|
||||
fetColors.append(f.renderMaterial.diffuse)
|
||||
except:
|
||||
pass
|
||||
if colorFound == 0:
|
||||
fetColors.append(f.renderMaterial.diffuse)
|
||||
except:
|
||||
# the Mesh itself has a renderer
|
||||
try: # get render material from any part of the mesh (list of items in displayValue)
|
||||
fetColors.append(f.renderMaterial.diffuse)
|
||||
colorFound += 1
|
||||
except:
|
||||
except:
|
||||
try:
|
||||
fetColors.append(f.displayStyle.color)
|
||||
fetColors.append(f.displayStyle.color)
|
||||
colorFound += 1
|
||||
except: pass
|
||||
if colorFound == 0: fetColors.append(None)
|
||||
except:
|
||||
pass
|
||||
if colorFound == 0:
|
||||
fetColors.append(None)
|
||||
return fetColors
|
||||
|
||||
@@ -1,22 +1,25 @@
|
||||
from typing import Any, Callable, List, Optional
|
||||
|
||||
from typing import Any, Callable, List, Optional
|
||||
|
||||
import inspect
|
||||
import inspect
|
||||
|
||||
from specklepy.objects import Base
|
||||
from specklepy.objects.GIS.layers import VectorLayer, RasterLayer, Layer
|
||||
|
||||
try:
|
||||
from speckle.speckle.ui.logger import logToUser
|
||||
from speckle.speckle.converter.layers.Layer import VectorLayer, RasterLayer, Layer
|
||||
from speckle.speckle.converter.layers import bimLayerToNative, cadLayerToNative, layerToNative
|
||||
except:
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.ui.logger import logToUser
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.layers.Layer import VectorLayer, RasterLayer, Layer
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.layers import bimLayerToNative, cadLayerToNative, layerToNative
|
||||
from speckle.speckle.utils.panel_logging import logToUser
|
||||
from speckle.speckle.converter.layers import (
|
||||
bimLayerToNative,
|
||||
cadLayerToNative,
|
||||
layerToNative,
|
||||
)
|
||||
|
||||
import arcpy
|
||||
|
||||
SPECKLE_TYPES_TO_READ = ["Objects.Geometry.", "Objects.BuiltElements.", "IFC"] # will properly traverse and check for displayValue
|
||||
SPECKLE_TYPES_TO_READ = [
|
||||
"Objects.Geometry.",
|
||||
"Objects.BuiltElements.",
|
||||
"IFC",
|
||||
] # will properly traverse and check for displayValue
|
||||
|
||||
|
||||
def traverseObject(
|
||||
base: Base,
|
||||
@@ -26,119 +29,175 @@ def traverseObject(
|
||||
plugin=None,
|
||||
):
|
||||
try:
|
||||
#print("traverse Object")
|
||||
#print(base)
|
||||
# print("traverse Object")
|
||||
# print(base)
|
||||
if check and check(base):
|
||||
res = callback(base, streamBranch, plugin) if callback else False
|
||||
#print(res)
|
||||
# print(res)
|
||||
if res:
|
||||
return
|
||||
memberNames = base.get_member_names()
|
||||
#print(base)
|
||||
#print(memberNames)
|
||||
# print(base)
|
||||
# print(memberNames)
|
||||
for name in memberNames:
|
||||
try:
|
||||
if ["id", "applicationId", "units", "speckle_type"].index(name):
|
||||
continue
|
||||
except:
|
||||
pass
|
||||
#print(name)
|
||||
# print(name)
|
||||
traverseValue(base[name], callback, check, streamBranch, plugin)
|
||||
logToUser("Data received", level=0)
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
|
||||
|
||||
def traverseValue(
|
||||
value: Any,
|
||||
callback: Optional[Callable[[Base, str, Any], bool]],
|
||||
check: Optional[Callable[[Base], bool]],
|
||||
streamBranch: str,
|
||||
plugin = None,
|
||||
plugin=None,
|
||||
):
|
||||
try:
|
||||
#print("traverse Value")
|
||||
#print(value)
|
||||
# print("traverse Value")
|
||||
# print(value)
|
||||
if isinstance(value, Base):
|
||||
traverseObject(value, callback, check, streamBranch, plugin)
|
||||
if isinstance(value, List):
|
||||
for item in value:
|
||||
traverseValue(item, callback, check, streamBranch, plugin)
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
|
||||
|
||||
def callback(base: Base, streamBranch: str, plugin=None) -> bool:
|
||||
try:
|
||||
#print("callback")
|
||||
if base.speckle_type.endswith("VectorLayer") or base.speckle_type.endswith("RasterLayer"):
|
||||
# print("callback")
|
||||
if base.speckle_type.endswith("VectorLayer") or base.speckle_type.endswith(
|
||||
"RasterLayer"
|
||||
):
|
||||
if isinstance(base, Layer):
|
||||
logToUser(f"Speckle class \"Layer\" will be deprecated in future updates in favour of \"VectorLayer\" or \"RasterLayer\"", level=0, func = inspect.stack()[0][3])
|
||||
logToUser(
|
||||
f'Speckle class "Layer" will be deprecated in future updates in favour of "VectorLayer" or "RasterLayer"',
|
||||
level=0,
|
||||
func=inspect.stack()[0][3],
|
||||
)
|
||||
layerToNative(base, streamBranch, plugin)
|
||||
#print(layer)
|
||||
#if layer is not None:
|
||||
# print(layer)
|
||||
# if layer is not None:
|
||||
# logToUser("Layer created: " + layer.name(), level=0)
|
||||
else:
|
||||
loopObj(base, "", streamBranch, plugin)
|
||||
return True
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
return False
|
||||
|
||||
|
||||
def loopObj(base: Base, baseName: str, streamBranch: str, plugin=None):
|
||||
try:
|
||||
memberNames = base.get_member_names()
|
||||
for name in memberNames:
|
||||
if name in ["id", "applicationId", "units", "speckle_type"]: continue
|
||||
if name in ["id", "applicationId", "units", "speckle_type"]:
|
||||
continue
|
||||
# skip if traversal goes to displayValue of an object, that will be readable anyway:
|
||||
if not isinstance(base, Base): logToUser("NOT BASE: "+type(base), level=1, func = inspect.stack()[0][3]); continue
|
||||
if (name == "displayValue" or name == "@displayValue") and base.speckle_type.startswith(tuple(SPECKLE_TYPES_TO_READ)): continue
|
||||
if not isinstance(base, Base):
|
||||
logToUser(
|
||||
"NOT BASE: " + type(base), level=1, func=inspect.stack()[0][3]
|
||||
)
|
||||
continue
|
||||
if (
|
||||
name == "displayValue" or name == "@displayValue"
|
||||
) and base.speckle_type.startswith(tuple(SPECKLE_TYPES_TO_READ)):
|
||||
continue
|
||||
|
||||
try:
|
||||
loopVal(base[name], baseName + "/" + name, streamBranch, plugin)
|
||||
except:
|
||||
pass
|
||||
|
||||
try: loopVal(base[name], baseName + "/" + name, streamBranch, plugin)
|
||||
except: pass
|
||||
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
|
||||
def loopVal(value: Any, name: str, streamBranch: str, plugin=None): # "name" is the parent object/property/layer name
|
||||
|
||||
def loopVal(
|
||||
value: Any, name: str, streamBranch: str, plugin=None
|
||||
): # "name" is the parent object/property/layer name
|
||||
try:
|
||||
if isinstance(value, Base):
|
||||
try: # loop through objects with Speckletype prop, but don't go through parts of Speckle Geometry object
|
||||
if not value.speckle_type.startswith("Objects.Geometry."):
|
||||
if isinstance(value, Base):
|
||||
try: # loop through objects with Speckletype prop, but don't go through parts of Speckle Geometry object
|
||||
if not value.speckle_type.startswith("Objects.Geometry."):
|
||||
loopObj(value, name, streamBranch, plugin)
|
||||
except:
|
||||
except:
|
||||
loopObj(value, name, streamBranch, plugin)
|
||||
|
||||
elif isinstance(value, List):
|
||||
streamBranch = streamBranch.replace("[","_").replace("]","_").replace(" ","_").replace("-","_").replace("(","_").replace(")","_").replace(":","_").replace("\\","_").replace("/","_").replace("\"","_").replace("&","_").replace("@","_").replace("$","_").replace("%","_").replace("^","_")
|
||||
streamBranch = (
|
||||
streamBranch.replace("[", "_")
|
||||
.replace("]", "_")
|
||||
.replace(" ", "_")
|
||||
.replace("-", "_")
|
||||
.replace("(", "_")
|
||||
.replace(")", "_")
|
||||
.replace(":", "_")
|
||||
.replace("\\", "_")
|
||||
.replace("/", "_")
|
||||
.replace('"', "_")
|
||||
.replace("&", "_")
|
||||
.replace("@", "_")
|
||||
.replace("$", "_")
|
||||
.replace("%", "_")
|
||||
.replace("^", "_")
|
||||
)
|
||||
|
||||
objectListConverted = 0
|
||||
#print("loop val - List")
|
||||
# print("loop val - List")
|
||||
for i, item in enumerate(value):
|
||||
loopVal(item, name, streamBranch, plugin)
|
||||
if not isinstance(item, Base): continue
|
||||
if item.speckle_type and item.speckle_type.startswith("IFC"):
|
||||
if not isinstance(item, Base):
|
||||
continue
|
||||
if item.speckle_type and item.speckle_type.startswith("IFC"):
|
||||
# keep traversing infinitely, just don't run repeated conversion for the same list of objects
|
||||
try:
|
||||
if item["displayValue"] is not None and objectListConverted == 0:
|
||||
try:
|
||||
if (
|
||||
item["displayValue"] is not None
|
||||
and objectListConverted == 0
|
||||
):
|
||||
bimLayerToNative(value, name, streamBranch, None, plugin)
|
||||
objectListConverted += 1
|
||||
except:
|
||||
try:
|
||||
if item["@displayValue"] is not None and objectListConverted == 0:
|
||||
bimLayerToNative(value, name, streamBranch, None, plugin)
|
||||
except:
|
||||
try:
|
||||
if (
|
||||
item["@displayValue"] is not None
|
||||
and objectListConverted == 0
|
||||
):
|
||||
bimLayerToNative(
|
||||
value, name, streamBranch, None, plugin
|
||||
)
|
||||
objectListConverted += 1
|
||||
except: pass
|
||||
elif item.speckle_type and item.speckle_type.endswith(".ModelCurve"):
|
||||
if item["baseCurve"] is not None:
|
||||
except:
|
||||
pass
|
||||
elif item.speckle_type and item.speckle_type.endswith(".ModelCurve"):
|
||||
if item["baseCurve"] is not None:
|
||||
cadLayerToNative(value, name, streamBranch, plugin)
|
||||
break
|
||||
elif item.speckle_type and (item.speckle_type == "Objects.Geometry.Mesh" or item.speckle_type == "Objects.Geometry.Brep" or item.speckle_type.startswith("Objects.BuiltElements.")):
|
||||
elif item.speckle_type and (
|
||||
item.speckle_type == "Objects.Geometry.Mesh"
|
||||
or item.speckle_type == "Objects.Geometry.Brep"
|
||||
or item.speckle_type.startswith("Objects.BuiltElements.")
|
||||
):
|
||||
bimLayerToNative(value, name, streamBranch, None, plugin)
|
||||
break
|
||||
elif item.speckle_type and item.speckle_type != "Objects.Geometry.Mesh" and item.speckle_type != "Objects.Geometry.Brep" and item.speckle_type.startswith("Objects.Geometry."): # or item.speckle_type == 'Objects.BuiltElements.Alignment'):
|
||||
elif (
|
||||
item.speckle_type
|
||||
and item.speckle_type != "Objects.Geometry.Mesh"
|
||||
and item.speckle_type != "Objects.Geometry.Brep"
|
||||
and item.speckle_type.startswith("Objects.Geometry.")
|
||||
): # or item.speckle_type == 'Objects.BuiltElements.Alignment'):
|
||||
cadLayerToNative(value, name, streamBranch, plugin)
|
||||
#if pt is not None: arcpy.AddMessage("Layer group created: " + str(pt.name))
|
||||
#if pl is not None: arcpy.AddMessage("Layer group created: " + str(pl.name))
|
||||
# if pt is not None: arcpy.AddMessage("Layer group created: " + str(pt.name))
|
||||
# if pl is not None: arcpy.AddMessage("Layer group created: " + str(pl.name))
|
||||
break
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
import sys
|
||||
import trace
|
||||
import threading
|
||||
|
||||
class KThread(threading.Thread):
|
||||
"""A subclass of threading.Thread, with a kill()
|
||||
method."""
|
||||
# https://web.archive.org/web/20130503082442/http://mail.python.org/pipermail/python-list/2004-May/281943.html
|
||||
def __init__(self, *args, **keywords):
|
||||
threading.Thread.__init__(self, *args, **keywords)
|
||||
self.killed = False
|
||||
|
||||
def start(self):
|
||||
"""Start the thread."""
|
||||
self.__run_backup = self.run
|
||||
self.run = self.__run # Force the Thread to install our trace.
|
||||
threading.Thread.start(self)
|
||||
|
||||
def __run(self):
|
||||
"""Hacked run function, which installs the trace."""
|
||||
sys.settrace(self.globaltrace)
|
||||
self.__run_backup()
|
||||
self.run = self.__run_backup
|
||||
|
||||
def globaltrace(self, frame, why, arg):
|
||||
if why == 'call':
|
||||
return self.localtrace
|
||||
else:
|
||||
return None
|
||||
|
||||
def localtrace(self, frame, why, arg):
|
||||
if self.killed:
|
||||
if why == 'line':
|
||||
raise SystemExit()
|
||||
return self.localtrace
|
||||
|
||||
def kill(self):
|
||||
self.killed = True
|
||||
|
||||
class KillableThread(threading.Thread):
|
||||
# is NOT running in the background
|
||||
# https://stackoverflow.com/questions/323972/is-there-any-way-to-kill-a-thread
|
||||
def __init__(self, sleep_interval=1):
|
||||
super().__init__()
|
||||
self._kill = threading.Event()
|
||||
self._interval = sleep_interval
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
print("Do Something")
|
||||
|
||||
# If no kill signal is set, sleep for the interval,
|
||||
# If kill signal comes in while sleeping, immediately
|
||||
# wake up and handle
|
||||
is_killed = self._kill.wait(self._interval)
|
||||
if is_killed:
|
||||
break
|
||||
|
||||
print("Killing Thread")
|
||||
|
||||
def kill(self):
|
||||
self._kill.set()
|
||||
@@ -1,153 +0,0 @@
|
||||
|
||||
import time
|
||||
from typing import Any, List, Tuple
|
||||
from PyQt5 import QtCore
|
||||
from PyQt5.QtCore import QCoreApplication, QSettings, Qt, QTranslator, QRect, QObject
|
||||
from PyQt5.QtWidgets import QAction, QDockWidget, QVBoxLayout, QWidget, QPushButton
|
||||
from PyQt5 import QtWidgets
|
||||
import webbrowser
|
||||
from specklepy.logging import metrics
|
||||
from specklepy.api.credentials import Account
|
||||
|
||||
import inspect
|
||||
|
||||
try:
|
||||
from speckle.speckle.ui.logger import logToUser
|
||||
except:
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.ui.logger import logToUser
|
||||
|
||||
SPECKLE_COLOR = (59,130,246)
|
||||
SPECKLE_COLOR_LIGHT = (69,140,255)
|
||||
|
||||
BACKGR_COLOR = f"background-color: rgb{str(SPECKLE_COLOR)};"
|
||||
BACKGR_COLOR_LIGHT = f"background-color: rgb{str(SPECKLE_COLOR_LIGHT)};"
|
||||
|
||||
BACKGR_COLOR_GREY = f"background-color: Gainsboro;"
|
||||
|
||||
class LogWidget(QWidget):
|
||||
|
||||
msgs: List[str] = []
|
||||
used_btns: List[int] = []
|
||||
btns: List[QPushButton]
|
||||
max_msg: int
|
||||
|
||||
active_account: Account
|
||||
speckle_version: str
|
||||
|
||||
# constructor
|
||||
def __init__(self, parent=None):
|
||||
super(LogWidget, self).__init__(parent)
|
||||
print("start LogWidget")
|
||||
self.parentWidget = parent
|
||||
print(self.parentWidget)
|
||||
self.max_msg = 10
|
||||
|
||||
# create a temporary floating button
|
||||
width = 0 #parent.frameSize().width()
|
||||
height = 0# parent.frameSize().height()
|
||||
|
||||
self.setAttribute(QtCore.Qt.WA_StyledBackground, True)
|
||||
self.setStyleSheet("background-color: rgba(250,250,250,80);")
|
||||
|
||||
self.layout = QVBoxLayout(self)
|
||||
self.layout.setContentsMargins(10, 60, 10, 40)
|
||||
self.layout.setAlignment(Qt.AlignBottom)
|
||||
self.setGeometry(0, 0, width, height)
|
||||
|
||||
# generate 100 buttons to use later
|
||||
self.btns = []
|
||||
for i in range(self.max_msg):
|
||||
button = QPushButton(f"👌 Error") # to '{streamName}' Sent , v
|
||||
button.setStyleSheet("QPushButton {color: black; border: 0px;border-radius: 17px;padding: 20px;height: 40px;text-align: left;"+ f"{BACKGR_COLOR_GREY}" + "}")
|
||||
button.clicked.connect(lambda: self.openLink())
|
||||
button.clicked.connect(lambda: self.hide())
|
||||
self.btns.append(button)
|
||||
|
||||
self.hide()
|
||||
|
||||
# overriding the mouseReleaseEvent method
|
||||
def mouseReleaseEvent(self, event):
|
||||
print("Mouse Release Event")
|
||||
self.hide()
|
||||
#self.parentWidget.hideError()
|
||||
|
||||
def hide(self):
|
||||
|
||||
self.setGeometry(0, 0, 0, 0)
|
||||
|
||||
# remove all buttons
|
||||
for i in reversed(range(self.layout.count())):
|
||||
self.layout.itemAt(i).widget().setParent(None)
|
||||
|
||||
# remove list of used btns
|
||||
self.used_btns.clear()
|
||||
self.msgs.clear()
|
||||
|
||||
|
||||
def addButton(self, text: str = "something went wrong", level: int = 2, url = "", blue = False):
|
||||
print("Add button")
|
||||
|
||||
self.setGeometry(0, 0, self.parentWidget.frameSize().width(), self.parentWidget.frameSize().height())
|
||||
|
||||
# find index of the first unused button
|
||||
btn, index = self.getNextBtn()
|
||||
btn.setAccessibleName(url)
|
||||
|
||||
if url != "":
|
||||
btn.setStyleSheet("QPushButton {color: white;border: 0px;border-radius: 17px;padding: 20px;height: 40px;text-align: left;"+ f"{BACKGR_COLOR}" + "} QPushButton:hover { "+ f"{BACKGR_COLOR_LIGHT}" + " }")
|
||||
|
||||
else:
|
||||
if blue is False:
|
||||
btn.setStyleSheet("QPushButton {color: black; border: 0px;border-radius: 17px;padding: 20px;height: 40px;text-align: left;"+ f"{BACKGR_COLOR_GREY}" + "}")
|
||||
else:
|
||||
btn.setStyleSheet("QPushButton {color: white;border: 0px;border-radius: 17px;padding: 20px;height: 40px;text-align: left;"+ f"{BACKGR_COLOR}" + "}")
|
||||
|
||||
btn.setText(text)
|
||||
self.resizeToText(btn)
|
||||
|
||||
#btn.resize(btn.sizeHint())
|
||||
self.layout.addWidget(btn) #, alignment=Qt.AlignCenter)
|
||||
|
||||
self.msgs.append(text)
|
||||
self.used_btns.append(1)
|
||||
|
||||
def openLink(self, url = ""):
|
||||
try:
|
||||
btn = self.sender()
|
||||
url = btn.accessibleName()
|
||||
if url == "": return
|
||||
|
||||
webbrowser.open(url, new=0, autoraise=True)
|
||||
|
||||
try:
|
||||
metrics.track("Connector Action", self.active_account, {"name": "Open In Web", "connector_version": str(self.speckle_version)})
|
||||
except:
|
||||
pass
|
||||
|
||||
self.hide()
|
||||
except Exception as e:
|
||||
pass #logger.logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
|
||||
def getNextBtn(self) -> Tuple[QPushButton, int]:
|
||||
index = len(self.used_btns) # get the next "free" button
|
||||
|
||||
if index >= len(self.btns):
|
||||
# remove first button
|
||||
self.layout.itemAt(0).widget().setParent(None)
|
||||
|
||||
self.used_btns.clear()
|
||||
index = 0
|
||||
|
||||
btn = self.btns[index]
|
||||
return btn, index
|
||||
|
||||
def resizeToText(self, btn):
|
||||
try:
|
||||
text = btn.text()
|
||||
if len(text.split("\n"))>2:
|
||||
height = len(text.split("\n"))*25
|
||||
btn.setMinimumHeight(height)
|
||||
return btn
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return btn
|
||||
@@ -1,163 +0,0 @@
|
||||
import os
|
||||
from typing import List, Union
|
||||
#import ui.speckle_qgis_dialog
|
||||
|
||||
from PyQt5 import QtWidgets, uic, QtCore
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
from specklepy.api.models import Stream
|
||||
from specklepy.api.client import SpeckleClient
|
||||
from specklepy.logging.exceptions import SpeckleException
|
||||
|
||||
from specklepy.api.credentials import get_local_accounts #, StreamWrapper
|
||||
from specklepy.api.wrapper import StreamWrapper
|
||||
from gql import gql
|
||||
|
||||
import inspect
|
||||
|
||||
try:
|
||||
from speckle.speckle.ui.logger import logToUser
|
||||
except:
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.ui.logger import logToUser
|
||||
|
||||
import arcpy
|
||||
|
||||
# This loads your .ui file so that PyQt can populate your plugin with the elements from Qt Designer
|
||||
ui_class = os.path.dirname(os.path.abspath(__file__)) + "/add_stream_modal.ui"
|
||||
|
||||
class AddStreamModalDialog(QtWidgets.QWidget):
|
||||
|
||||
search_button: QtWidgets.QPushButton = None
|
||||
search_text_field: QtWidgets.QLineEdit = None
|
||||
search_results_list: QtWidgets.QListWidget = None
|
||||
dialog_button_box: QtWidgets.QDialogButtonBox = None
|
||||
accounts_dropdown: QtWidgets.QComboBox
|
||||
|
||||
stream_results: List[Stream] = []
|
||||
speckle_client: Union[SpeckleClient, None] = None
|
||||
|
||||
#Events
|
||||
handleStreamAdd = pyqtSignal(StreamWrapper)
|
||||
|
||||
def __init__(self, parent=None, speckle_client: SpeckleClient = None):
|
||||
super(AddStreamModalDialog,self).__init__(parent,QtCore.Qt.WindowStaysOnTopHint)
|
||||
uic.loadUi(ui_class, self) # Load the .ui file
|
||||
self.show()
|
||||
try:
|
||||
|
||||
self.speckle_client = speckle_client
|
||||
|
||||
self.setWindowTitle("Add Speckle stream")
|
||||
|
||||
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(False)
|
||||
|
||||
self.search_button.clicked.connect(self.onSearchClicked)
|
||||
self.search_results_list.currentItemChanged.connect( self.searchResultChanged )
|
||||
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).clicked.connect(self.onOkClicked)
|
||||
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Cancel).clicked.connect(self.onCancelClicked)
|
||||
self.accounts_dropdown.currentIndexChanged.connect(self.onAccountSelected)
|
||||
self.populate_accounts_dropdown()
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
|
||||
def searchResultChanged(self):
|
||||
try:
|
||||
index = self.search_results_list.currentIndex().row()
|
||||
if index == -1: self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(False)
|
||||
else: self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(True)
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
|
||||
def onSearchClicked(self):
|
||||
try:
|
||||
query = self.search_text_field.text()
|
||||
sw = None
|
||||
results = []
|
||||
if "http" in query and len(query.split("/")) >= 3: # URL
|
||||
sw = StreamWrapper(query)
|
||||
stream = sw.get_client().stream.get(sw.stream_id)
|
||||
if isinstance(stream, Stream): results = [stream]
|
||||
else: results = []
|
||||
|
||||
elif self.speckle_client is not None:
|
||||
results = self.speckle_client.stream.search(query)
|
||||
elif self.speckle_client is None:
|
||||
logToUser(f"Account cannot be authenticated: {self.accounts_dropdown.currentText()}", level=2, func = inspect.stack()[0][3])
|
||||
|
||||
self.stream_results = results
|
||||
self.populateResultsList(sw)
|
||||
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
|
||||
def populateResultsList(self, sw):
|
||||
try:
|
||||
self.search_results_list.clear()
|
||||
if isinstance(self.stream_results, SpeckleException):
|
||||
logToUser("Some streams cannot be accessed", level=1, func = inspect.stack()[0][3])
|
||||
return
|
||||
for stream in self.stream_results:
|
||||
host = ""
|
||||
if sw is not None:
|
||||
host = sw.get_account().serverInfo.url
|
||||
else:
|
||||
host = self.speckle_client.account.serverInfo.url
|
||||
|
||||
if isinstance(stream, SpeckleException):
|
||||
logToUser("Some streams cannot be accessed", level=1, func = inspect.stack()[0][3])
|
||||
else:
|
||||
self.search_results_list.addItems([
|
||||
f"{stream.name}, {stream.id} | {host}" #for stream in self.stream_results
|
||||
])
|
||||
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
|
||||
def onOkClicked(self):
|
||||
try:
|
||||
if isinstance(self.stream_results, SpeckleException):
|
||||
logToUser("Selected stream cannot be accessed", level=1, func = inspect.stack()[0][3])
|
||||
return
|
||||
#elif index == -1 or len(self.stream_results) == 0:
|
||||
# logger.logToUser("Select stream from \"Search Results\". No stream selected", Qgis.Warning)
|
||||
# return
|
||||
else:
|
||||
try:
|
||||
index = self.search_results_list.currentIndex().row()
|
||||
stream = self.stream_results[index]
|
||||
item = self.search_results_list.item(index)
|
||||
url = item.text().split(" | ")[1] + "/streams/" + item.text().split(", ")[1].split(" | ")[0]
|
||||
sw = StreamWrapper(url)
|
||||
#acc = sw.get_account() #get_local_accounts()[self.accounts_dropdown.currentIndex()]
|
||||
self.handleStreamAdd.emit(sw) #StreamWrapper(f"{acc.serverInfo.url}/streams/{stream.id}?u={acc.userInfo.id}"))
|
||||
self.close()
|
||||
except Exception as e:
|
||||
logToUser("Some streams cannot be accessed: " + str(e), level=1, func = inspect.stack()[0][3])
|
||||
return
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
|
||||
def onCancelClicked(self):
|
||||
self.close()
|
||||
|
||||
def onAccountSelected(self, index):
|
||||
try:
|
||||
account = self.speckle_accounts[index]
|
||||
self.speckle_client = SpeckleClient(account.serverInfo.url, account.serverInfo.url.startswith("https"))
|
||||
self.speckle_client.authenticate_with_token(token=account.token)
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
|
||||
def populate_accounts_dropdown(self):
|
||||
# Populate the accounts comboBox
|
||||
try:
|
||||
self.speckle_accounts = get_local_accounts()
|
||||
self.accounts_dropdown.clear()
|
||||
self.accounts_dropdown.addItems(
|
||||
[
|
||||
f"{acc.userInfo.name}, {acc.userInfo.email} | {acc.serverInfo.url}"
|
||||
for acc in self.speckle_accounts
|
||||
]
|
||||
)
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>AddStreamDialog</class>
|
||||
<widget class="QWidget" name="AddStreamDialog">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::NonModal</enum>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetNoConstraint</enum>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="search_form">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="search_label">
|
||||
<property name="text">
|
||||
<string>Search Stream by name or URL</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="search_text_field"/>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QPushButton" name="search_button">
|
||||
<property name="text">
|
||||
<string>Search</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="accounts_dropdown"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="accounts_label">
|
||||
<property name="text">
|
||||
<string>Account</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="search_results_label">
|
||||
<property name="text">
|
||||
<string>Search Results</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="search_results_list">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>100</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QAbstractScrollArea::AdjustToContents</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="dialog_button_box">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -1,83 +0,0 @@
|
||||
import os
|
||||
from typing import List, Tuple, Union
|
||||
#import ui.speckle_qgis_dialog
|
||||
|
||||
from PyQt5 import QtWidgets, uic, QtCore
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
from specklepy.api.models import Stream
|
||||
from specklepy.api.client import SpeckleClient
|
||||
from specklepy.logging.exceptions import SpeckleException
|
||||
|
||||
from specklepy.api.credentials import Account, get_local_accounts #, StreamWrapper
|
||||
from specklepy.api.wrapper import StreamWrapper
|
||||
from gql import gql
|
||||
|
||||
import inspect
|
||||
|
||||
import arcpy
|
||||
try:
|
||||
from speckle.speckle.ui.logger import logToUser
|
||||
except:
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.ui.logger import logToUser
|
||||
|
||||
# This loads your .ui file so that PyQt can populate your plugin with the elements from Qt Designer
|
||||
|
||||
ui_class = os.path.dirname(os.path.abspath(__file__)) + "/create_branch.ui"
|
||||
|
||||
class CreateBranchModalDialog(QtWidgets.QWidget):
|
||||
|
||||
name_field: QtWidgets.QLineEdit = None
|
||||
description_field: QtWidgets.QLineEdit = None
|
||||
dialog_button_box: QtWidgets.QDialogButtonBox = None
|
||||
speckle_client: Union[SpeckleClient, None] = None
|
||||
|
||||
#Events
|
||||
handleBranchCreate = pyqtSignal(str,str)
|
||||
|
||||
def __init__(self, parent=None, speckle_client: SpeckleClient = None):
|
||||
super(CreateBranchModalDialog,self).__init__(parent,QtCore.Qt.WindowStaysOnTopHint)
|
||||
uic.loadUi(ui_class, self) # Load the .ui file
|
||||
self.show()
|
||||
try:
|
||||
|
||||
self.speckle_client = speckle_client
|
||||
|
||||
self.setWindowTitle("Create New Branch")
|
||||
|
||||
self.name_field.textChanged.connect(self.nameCheck)
|
||||
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(False)
|
||||
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).clicked.connect(self.onOkClicked)
|
||||
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Cancel).clicked.connect(self.onCancelClicked)
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
|
||||
def nameCheck(self):
|
||||
try:
|
||||
if len(self.name_field.text()) >= 3:
|
||||
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(True)
|
||||
else:
|
||||
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(False)
|
||||
return
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
|
||||
def onOkClicked(self):
|
||||
try:
|
||||
name = self.name_field.text()
|
||||
description = self.description_field.text()
|
||||
self.handleBranchCreate.emit(name, description)
|
||||
self.close()
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
return
|
||||
|
||||
def onCancelClicked(self):
|
||||
self.close()
|
||||
|
||||
def onAccountSelected(self, index):
|
||||
try:
|
||||
account = self.speckle_accounts[index]
|
||||
self.speckle_client = SpeckleClient(account.serverInfo.url, account.serverInfo.url.startswith("https"))
|
||||
self.speckle_client.authenticate_with_token(token=account.token)
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
@@ -1,64 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CreateStreamDialog</class>
|
||||
<widget class="QWidget" name="AddBranchDialog">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::NonModal</enum>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetNoConstraint</enum>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="search_form">
|
||||
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="name_label">
|
||||
<property name="text">
|
||||
<string>Branch Name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="name_label">
|
||||
<property name="text">
|
||||
<string>Description</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="name_field"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="description_field"/>
|
||||
</item>
|
||||
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="dialog_button_box">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -1,108 +0,0 @@
|
||||
import os
|
||||
from typing import List, Tuple, Union
|
||||
#import ui.speckle_qgis_dialog
|
||||
|
||||
|
||||
from PyQt5 import QtWidgets, uic, QtCore
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
|
||||
import arcpy
|
||||
|
||||
from specklepy.api.models import Stream
|
||||
from specklepy.api.client import SpeckleClient
|
||||
from specklepy.logging.exceptions import SpeckleException
|
||||
|
||||
from specklepy.api.credentials import Account, get_local_accounts #, StreamWrapper
|
||||
from specklepy.api.wrapper import StreamWrapper
|
||||
from gql import gql
|
||||
import inspect
|
||||
|
||||
try:
|
||||
from speckle.speckle.ui.logger import logToUser
|
||||
except:
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.ui.logger import logToUser
|
||||
|
||||
# This loads your .ui file so that PyQt can populate your plugin with the elements from Qt Designer
|
||||
|
||||
ui_class = os.path.dirname(os.path.abspath(__file__)) + "/create_stream.ui"
|
||||
|
||||
class CreateStreamModalDialog(QtWidgets.QWidget):
|
||||
|
||||
name_field: QtWidgets.QLineEdit = None
|
||||
description_field: QtWidgets.QLineEdit = None
|
||||
dialog_button_box: QtWidgets.QDialogButtonBox = None
|
||||
accounts_dropdown: QtWidgets.QComboBox
|
||||
public_toggle: QtWidgets.QCheckBox
|
||||
|
||||
speckle_client: Union[SpeckleClient, None] = None
|
||||
|
||||
#Events
|
||||
handleStreamCreate = pyqtSignal(Account, str, str, bool)
|
||||
|
||||
def __init__(self, parent=None, speckle_client: SpeckleClient = None):
|
||||
super(CreateStreamModalDialog,self).__init__(parent,QtCore.Qt.WindowStaysOnTopHint)
|
||||
uic.loadUi(ui_class, self) # Load the .ui file
|
||||
self.show()
|
||||
try:
|
||||
|
||||
self.speckle_client = speckle_client
|
||||
|
||||
self.setWindowTitle("Create New Stream")
|
||||
|
||||
self.name_field.textChanged.connect(self.nameCheck)
|
||||
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(True)
|
||||
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).clicked.connect(self.onOkClicked)
|
||||
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Cancel).clicked.connect(self.onCancelClicked)
|
||||
self.accounts_dropdown.currentIndexChanged.connect(self.onAccountSelected)
|
||||
self.populate_accounts_dropdown()
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
|
||||
def nameCheck(self):
|
||||
try:
|
||||
if len(self.name_field.text()) == 0 or len(self.name_field.text()) >= 3:
|
||||
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(True)
|
||||
else:
|
||||
self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(False)
|
||||
return
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
|
||||
def onOkClicked(self):
|
||||
try:
|
||||
acc = get_local_accounts()[self.accounts_dropdown.currentIndex()]
|
||||
name = self.name_field.text()
|
||||
description = self.description_field.text()
|
||||
public = self.public_toggle.isChecked()
|
||||
self.handleStreamCreate.emit(acc,name,description,public)
|
||||
self.close()
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
return
|
||||
|
||||
def onCancelClicked(self):
|
||||
#self.handleCancelStreamCreate.emit()
|
||||
self.close()
|
||||
|
||||
def onAccountSelected(self, index):
|
||||
try:
|
||||
account = self.speckle_accounts[index]
|
||||
self.speckle_client = SpeckleClient(account.serverInfo.url, account.serverInfo.url.startswith("https"))
|
||||
self.speckle_client.authenticate_with_token(token=account.token)
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
|
||||
def populate_accounts_dropdown(self):
|
||||
try:
|
||||
# Populate the accounts comboBox
|
||||
self.speckle_accounts = get_local_accounts()
|
||||
self.accounts_dropdown.clear()
|
||||
self.accounts_dropdown.addItems(
|
||||
[
|
||||
f"{acc.userInfo.name}, {acc.userInfo.email} | {acc.serverInfo.url}"
|
||||
for acc in self.speckle_accounts
|
||||
]
|
||||
)
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CreateStreamDialog</class>
|
||||
<widget class="QWidget" name="AddStreamDialog">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::NonModal</enum>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetNoConstraint</enum>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="search_form">
|
||||
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="accounts_label">
|
||||
<property name="text">
|
||||
<string>Account</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="name_label">
|
||||
<property name="text">
|
||||
<string>Stream Name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="name_label">
|
||||
<property name="text">
|
||||
<string>Description</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="name_label">
|
||||
<property name="text">
|
||||
<string>Public</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="accounts_dropdown"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="name_field"/>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="description_field"/>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="public_toggle"/>
|
||||
</item>
|
||||
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="dialog_button_box">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 345 B |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
@@ -1,55 +0,0 @@
|
||||
|
||||
from PyQt5.QtWidgets import QMessageBox
|
||||
from PyQt5 import QtCore
|
||||
import arcpy
|
||||
try:
|
||||
from speckle.speckle.plugin_utils.helpers import splitTextIntoLines
|
||||
except:
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.plugin_utils.helpers import splitTextIntoLines
|
||||
|
||||
import inspect
|
||||
|
||||
def logToUser(msg: str, func=None, level: int = 2, plugin = None, url = "", blue = False):
|
||||
print("Log to user")
|
||||
|
||||
msg = str(msg)
|
||||
dockwidget = plugin
|
||||
|
||||
try:
|
||||
if url == "" and blue is False: # only for info messages
|
||||
msg = addLevelSymbol(msg, level)
|
||||
if func is not None:
|
||||
msg += "::" + str(func)
|
||||
writeToLog(msg, level)
|
||||
|
||||
if dockwidget is None: return
|
||||
|
||||
new_msg = splitTextIntoLines(msg, 70)
|
||||
|
||||
dockwidget.msgLog.addButton(new_msg, level=level, url=url, blue=blue)
|
||||
|
||||
except Exception as e: print(e); return
|
||||
|
||||
def logToUserWithAction(msg: str, level: int = 0, plugin = None, url = ""):
|
||||
print("Log to user with action")
|
||||
return
|
||||
msg = str(msg)
|
||||
dockwidget = plugin
|
||||
if dockwidget is None: return
|
||||
try:
|
||||
new_msg = splitTextIntoLines(msg, 70)
|
||||
dockwidget.msgLog.addButton(new_msg, level=level, url=url)
|
||||
writeToLog(new_msg, level)
|
||||
except Exception as e: print(e); return
|
||||
|
||||
def addLevelSymbol(msg: str, level: int):
|
||||
if level == 0: msg = "🛈 " + msg
|
||||
if level == 1: msg = "⚠️ " + msg
|
||||
if level == 2: msg = "❗ " + msg
|
||||
return msg
|
||||
|
||||
def writeToLog(msg: str = "", level: int = 2):
|
||||
print(msg)
|
||||
if level == 0: arcpy.AddMessage(msg)
|
||||
if level == 1: arcpy.AddWarning(msg)
|
||||
if level == 2: arcpy.AddError(msg)
|
||||
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 7.1 KiB |
@@ -1,357 +0,0 @@
|
||||
|
||||
from typing import Any, List, Optional, Tuple, Union
|
||||
import arcpy
|
||||
from arcpy._mp import ArcGISProject, Map, Layer as arcLayer
|
||||
from arcpy.management import CreateTable
|
||||
|
||||
import os.path
|
||||
|
||||
from specklepy.api.credentials import Account, get_local_accounts
|
||||
from specklepy.api.client import SpeckleClient
|
||||
from specklepy.logging.exceptions import (
|
||||
GraphQLException,
|
||||
SpeckleException,
|
||||
)
|
||||
from specklepy.api.wrapper import StreamWrapper
|
||||
from specklepy.api.models import Branch, Stream, Streams
|
||||
from specklepy.logging import metrics
|
||||
|
||||
from osgeo import osr
|
||||
|
||||
import inspect
|
||||
|
||||
try:
|
||||
from speckle.speckle.ui.validation import tryGetStream
|
||||
from speckle.speckle.speckle_arcgis import SpeckleGIS
|
||||
from speckle.speckle.converter.layers import getAllProjLayers
|
||||
from speckle.speckle.ui.logger import logToUser
|
||||
except:
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.ui.validation import tryGetStream
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.speckle_arcgis import SpeckleGIS
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.layers import getAllProjLayers
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.ui.logger import logToUser
|
||||
|
||||
FIELDS = ["project_streams","project_layer_selection", "lat_lon"]
|
||||
|
||||
def get_project_streams(plugin: SpeckleGIS, content: str = None):
|
||||
try:
|
||||
print("GET proj streams")
|
||||
project = plugin.gis_project
|
||||
table = findOrCreateSpeckleTable(project)
|
||||
logToUser(table, level=0, func = inspect.stack()[0][3])
|
||||
|
||||
rows = arcpy.da.SearchCursor(table, "project_streams")
|
||||
saved_streams = []
|
||||
for x in rows:
|
||||
logToUser(x, level=0, func = inspect.stack()[0][3])
|
||||
saved_streams.append(x[0])
|
||||
|
||||
temp = []
|
||||
######### need to check whether saved streams are available (account reachable)
|
||||
if len(saved_streams) > 0:
|
||||
for url in saved_streams:
|
||||
if url=="": continue
|
||||
try:
|
||||
sw = StreamWrapper(url)
|
||||
try:
|
||||
stream = tryGetStream(sw, plugin.dataStorage)
|
||||
except SpeckleException as e:
|
||||
logToUser(e.message, level=2, func = inspect.stack()[0][3])
|
||||
stream = None
|
||||
#strId = stream.id # will cause exception if invalid
|
||||
temp.append((sw, stream))
|
||||
except SpeckleException as e:
|
||||
logToUser(e.message, level=2, func = inspect.stack()[0][3])
|
||||
#except GraphQLException as e:
|
||||
# logger.logToUser(e.message, Qgis.Warning)
|
||||
plugin.current_streams = temp
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
|
||||
def set_project_streams(plugin: SpeckleGIS):
|
||||
try:
|
||||
print("SET proj streams")
|
||||
project = plugin.gis_project
|
||||
table = findOrCreateSpeckleTable(project)
|
||||
print("SET proj streams 2")
|
||||
|
||||
value = [stream[0].stream_url for stream in plugin.current_streams] #",".join()
|
||||
print(value)
|
||||
logToUser(value, level=0, func = inspect.stack()[0][3])
|
||||
|
||||
if table is not None:
|
||||
proj_layers = []
|
||||
lan_lot = ""
|
||||
with arcpy.da.UpdateCursor(table, FIELDS) as cursor:
|
||||
for row in cursor: # just one row
|
||||
if row[1] is not None and row[1] != "": proj_layers.append(row[1])
|
||||
if row[2] is not None and row[2] != "": lan_lot = row[2]
|
||||
cursor.deleteRow()
|
||||
del cursor
|
||||
if len(proj_layers) == 0: proj_layers.append("")
|
||||
if len(value) == 0: value.append("")
|
||||
|
||||
cursor = arcpy.da.InsertCursor(table, FIELDS )
|
||||
length = max(len(proj_layers), len(value))
|
||||
|
||||
for i in range(length):
|
||||
if i==0:
|
||||
cursor.insertRow([value[i], proj_layers[i] , lan_lot])
|
||||
else:
|
||||
try:
|
||||
cursor.insertRow([value[i], proj_layers[i] , ""])
|
||||
except:
|
||||
if len(value) <= i: cursor.insertRow(["", proj_layers[i] , ""])
|
||||
if len(proj_layers) <= i: cursor.insertRow([value[i], "" , ""])
|
||||
del cursor
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
|
||||
def get_project_layer_selection(plugin: SpeckleGIS):
|
||||
try:
|
||||
print("GET project layer selection from the table")
|
||||
project = plugin.gis_project
|
||||
table = findOrCreateSpeckleTable(project)
|
||||
if table is None: return
|
||||
|
||||
rows = arcpy.da.SearchCursor(table, "project_layer_selection")
|
||||
saved_layers = []
|
||||
for x in rows:
|
||||
saved_layers.append(x[0])
|
||||
|
||||
|
||||
temp = []
|
||||
proj_layers = getAllProjLayers(project)
|
||||
######### need to check whether saved streams are available (account reachable)
|
||||
if len(saved_layers) > 0:
|
||||
for layerPath in saved_layers:
|
||||
if layerPath == "": continue
|
||||
found = 0
|
||||
for layer in proj_layers:
|
||||
print(layer.dataSource)
|
||||
if layer.dataSource == layerPath:
|
||||
temp.append((layer.name, layer))
|
||||
found += 1
|
||||
break
|
||||
if found == 0:
|
||||
logToUser(f'Saved layer not found: "{layerPath}"', level=1, func = inspect.stack()[0][3])
|
||||
plugin.current_layers = temp
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
|
||||
def set_project_layer_selection(plugin: SpeckleGIS):
|
||||
try:
|
||||
print("SET project layer selection function")
|
||||
project = plugin.gis_project
|
||||
value: List[str] = [layer[1].dataSource for layer in plugin.current_layers] #",".join([layer[1].dataSource for layer in plugin.current_layers])
|
||||
print(value)
|
||||
|
||||
table = findOrCreateSpeckleTable(project)
|
||||
#print(table)
|
||||
if table is not None:
|
||||
lan_lot = ""
|
||||
proj_streams = []
|
||||
with arcpy.da.UpdateCursor(table, FIELDS) as cursor:
|
||||
for row in cursor: # just one row
|
||||
if row[0] is not None and row[0] != "": proj_streams.append(row[0])
|
||||
if row[2] is not None and row[2] != "": lan_lot = row[2]
|
||||
cursor.deleteRow()
|
||||
del cursor
|
||||
if len(proj_streams) == 0: proj_streams.append("")
|
||||
if len(value) == 0: value.append("")
|
||||
#print(proj_streams)
|
||||
|
||||
cursor = arcpy.da.InsertCursor(table, FIELDS )
|
||||
length = max(len(proj_streams), len(value))
|
||||
#print(length)
|
||||
for i in range(length):
|
||||
#print(i)
|
||||
if i==0:
|
||||
cursor.insertRow([proj_streams[i], value[i] , lan_lot])
|
||||
print(i)
|
||||
else:
|
||||
try:
|
||||
cursor.insertRow([proj_streams[i], value[i] , ""])
|
||||
except:
|
||||
if len(proj_streams) <= i: cursor.insertRow(["", value[i] , ""])
|
||||
if len(value) <= i: cursor.insertRow([proj_streams[i], "" , ""])
|
||||
#print(i)
|
||||
del cursor
|
||||
|
||||
try:
|
||||
metrics.track("Connector Action", plugin.active_account, {"name": "Save Layer Selection", "connector_version": str(plugin.version)})
|
||||
except Exception as e:
|
||||
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=plugin.dockwidget )
|
||||
|
||||
#print(table)
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
|
||||
print("SET project layer selection 2")
|
||||
|
||||
def get_survey_point(plugin: SpeckleGIS, content = None):
|
||||
try:
|
||||
print("get survey point")
|
||||
project = plugin.gis_project
|
||||
table = findOrCreateSpeckleTable(project)
|
||||
if table is None: return
|
||||
|
||||
rows = arcpy.da.SearchCursor(table, "lat_lon")
|
||||
points = ""
|
||||
for x in rows:
|
||||
points = x[0]
|
||||
break
|
||||
|
||||
if points != "":
|
||||
vals: List[str] = points.replace(" ","").split(";")[:2]
|
||||
plugin.lat, plugin.lon = [float(i) for i in vals]
|
||||
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
|
||||
def set_survey_point(plugin: SpeckleGIS):
|
||||
|
||||
try:
|
||||
# from widget (2 strings) to local vars + update SR of the map
|
||||
print("SET survey point")
|
||||
|
||||
project = plugin.gis_project
|
||||
vals =[ str(plugin.dockwidget.surveyPointLat.text()), str(plugin.dockwidget.surveyPointLon.text()) ]
|
||||
|
||||
plugin.lat, plugin.lon = [float(i.replace(" ","")) for i in vals]
|
||||
|
||||
if plugin.lat>180 or plugin.lat<-180 or plugin.lon >180 or plugin.lon<-180:
|
||||
logToUser("LAT LON values must be within (-180, 180). You can right-click on the canvas location to copy coordinates in WGS 84", level = 1, plugin=self.dockwidget)
|
||||
return True
|
||||
pt = str(plugin.lat) + ";" + str(plugin.lon)
|
||||
|
||||
table = findOrCreateSpeckleTable(project)
|
||||
if table is not None:
|
||||
with arcpy.da.UpdateCursor(table, ["lat_lon"]) as cursor:
|
||||
for row in cursor: # just one row
|
||||
cursor.updateRow([pt])
|
||||
break
|
||||
del cursor
|
||||
|
||||
setProjectReferenceSystem(plugin)
|
||||
|
||||
try:
|
||||
metrics.track("Connector Action", plugin.active_account, {"name": "Set As Center Point", "connector_version": str(plugin.version)})
|
||||
except Exception as e:
|
||||
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=plugin.dockwidget )
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
plugin.dockwidget.surveyPointLat.setText(str(plugin.lat))
|
||||
plugin.dockwidget.surveyPointLon.setText(str(plugin.lon))
|
||||
logToUser("Lat, Lon values invalid: " + str(e), level=2, func = inspect.stack()[0][3])
|
||||
return False
|
||||
|
||||
def setProjectReferenceSystem(plugin: SpeckleGIS):
|
||||
try:
|
||||
# save to project; create SR
|
||||
newCrsString = "+proj=tmerc +ellps=WGS84 +datum=WGS84 +units=m +no_defs +lon_0=" + str(plugin.lon) + " lat_0=" + str(plugin.lat) + " +x_0=0 +y_0=0 +k_0=1"
|
||||
newCrs = osr.SpatialReference()
|
||||
newCrs.ImportFromProj4(newCrsString)
|
||||
newCrs.MorphToESRI() # converts the WKT to an ESRI-compatible format
|
||||
|
||||
validate = True if len(newCrs.ExportToWkt())>10 else False
|
||||
|
||||
if validate:
|
||||
newProjSR = arcpy.SpatialReference()
|
||||
newProjSR.loadFromString(newCrs.ExportToWkt())
|
||||
|
||||
#source = osr.SpatialReference()
|
||||
#source.ImportFromWkt(plugin.project.activeMap.spatialReference.exportToString())
|
||||
#transform = osr.CoordinateTransformation(source, newCrs)
|
||||
|
||||
plugin.gis_project.activeMap.spatialReference = newProjSR
|
||||
logToUser("Custom project Spatial Reference successfully applied", level=0, func = inspect.stack()[0][3])
|
||||
else:
|
||||
logToUser("Custom Spatial Reference could not be created", level=1, func = inspect.stack()[0][3])
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
return False
|
||||
|
||||
def findOrCreateSpeckleTable(project: ArcGISProject) -> Union[str, None]:
|
||||
try:
|
||||
path = arcpy.env.workspace #project.filePath.replace("aprx","gdb") #"\\".join(project.filePath.split("\\")[:-1]) + "\\speckle_layers\\" #arcpy.env.workspace + "\\" #
|
||||
|
||||
if 'speckle_gis' not in arcpy.ListTables():
|
||||
try:
|
||||
table = CreateTable(path, "speckle_gis")
|
||||
arcpy.management.AddField(table, "project_streams", "TEXT")
|
||||
arcpy.management.AddField(table, "project_layer_selection", "TEXT")
|
||||
arcpy.management.AddField(table, "lat_lon", "TEXT")
|
||||
|
||||
cursor = arcpy.da.InsertCursor(table, FIELDS )
|
||||
cursor.insertRow(["","",""])
|
||||
del cursor
|
||||
|
||||
except Exception as e:
|
||||
logToUser("Error creating a table: " + str(e), level=1, func = inspect.stack()[0][3])
|
||||
raise e
|
||||
else:
|
||||
#print("table already exists")
|
||||
# make sure fileds exist
|
||||
table = path + "\\speckle_gis"
|
||||
findOrCreateTableField(table, FIELDS[0])
|
||||
findOrCreateTableField(table, FIELDS[1])
|
||||
findOrCreateTableField(table, FIELDS[2])
|
||||
|
||||
findOrCreateRow(table, FIELDS)
|
||||
|
||||
return table
|
||||
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
return None
|
||||
|
||||
def findOrCreateTableField(table: str, field: str):
|
||||
try:
|
||||
with arcpy.da.UpdateCursor(table, [field]) as cursor:
|
||||
value = None
|
||||
for row in cursor:
|
||||
value = row # tuple(val,)
|
||||
if value[0] is None: cursor.updateRow("")
|
||||
break # look at the 1st row only
|
||||
del cursor
|
||||
|
||||
#if value is None: # if there are no rows
|
||||
# cursor = arcpy.da.InsertCursor(table, [field])
|
||||
# cursor.insertRow([""])
|
||||
# del cursor
|
||||
|
||||
except: # if field doesn't exist
|
||||
arcpy.management.AddField(table, field, "TEXT")
|
||||
#cursor = arcpy.da.InsertCursor(table, [field] )
|
||||
#cursor.insertRow([""])
|
||||
del cursor
|
||||
|
||||
def findOrCreateRow(table:str, fields: List[str]):
|
||||
try:
|
||||
# check if the row exists
|
||||
cursor = arcpy.da.SearchCursor(table, fields)
|
||||
k=-1
|
||||
for k, row in enumerate(cursor):
|
||||
#print(row)
|
||||
break
|
||||
del cursor
|
||||
|
||||
# if no rows
|
||||
if k == -1:
|
||||
cursor = arcpy.da.InsertCursor(table, fields)
|
||||
cursor.insertRow(["", "", ""])
|
||||
del cursor
|
||||
else:
|
||||
with arcpy.da.UpdateCursor(table, fields) as cursor:
|
||||
for row in cursor:
|
||||
if None in row: cursor.updateRow(["","",""])
|
||||
break # look at the 1st row only
|
||||
del cursor
|
||||
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
|
Before Width: | Height: | Size: 400 B |
@@ -1,647 +0,0 @@
|
||||
|
||||
import os
|
||||
import sys
|
||||
from typing import List
|
||||
#from speckle.converter.layers import getLayers
|
||||
|
||||
#import ui.speckle_qgis_dialog
|
||||
|
||||
from specklepy.logging.exceptions import (SpeckleException, GraphQLException)
|
||||
from PyQt5 import QtWidgets, uic
|
||||
from PyQt5 import QtGui
|
||||
from PyQt5.QtGui import QIcon, QPixmap
|
||||
from PyQt5.QtWidgets import (QMainWindow, QApplication, QWidget,
|
||||
QListWidgetItem, QAction, QDockWidget, QVBoxLayout,
|
||||
QHBoxLayout, QWidget, QLabel)
|
||||
from PyQt5 import QtCore
|
||||
from PyQt5.QtCore import pyqtSignal, Qt, QSize, QEvent
|
||||
from PyQt5 import QtGui, uic
|
||||
|
||||
from specklepy.api.credentials import get_local_accounts
|
||||
|
||||
import importlib
|
||||
|
||||
from specklepy.api.wrapper import StreamWrapper
|
||||
from specklepy.api.client import SpeckleClient
|
||||
from specklepy.logging import metrics
|
||||
|
||||
import arcpy
|
||||
|
||||
import inspect
|
||||
|
||||
try:
|
||||
#from speckle.speckle_arcgis_new import Speckle
|
||||
from speckle.speckle.converter.layers import getLayers, getAllProjLayers
|
||||
from speckle.speckle.ui.logger import logToUser
|
||||
from speckle.speckle.ui.LogWidget import LogWidget
|
||||
except:
|
||||
#from speckle_toolbox.esri.toolboxes.speckle.speckle_arcgis_new import Speckle
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.layers import getLayers, getAllProjLayers
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.ui.logger import logToUser
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.ui.LogWidget import LogWidget
|
||||
|
||||
#from ui.validation import tryGetStream
|
||||
|
||||
# Create module-like object
|
||||
#pytPath = os.path.dirname(os.path.abspath(__file__)).replace("/speckle/ui","/Speckle.pyt")
|
||||
#print(pytPath)
|
||||
#pytModule = importlib.machinery.SourceFileLoader("specklePyt", pytPath )
|
||||
#specklePyt = pytModule.load_module("specklePyt")
|
||||
|
||||
|
||||
# This loads your .ui file so that PyQt can populate your plugin with the elements from Qt Designer
|
||||
|
||||
COLOR_HIGHLIGHT = (210,210,210)
|
||||
|
||||
SPECKLE_COLOR = (59,130,246)
|
||||
SPECKLE_COLOR_LIGHT = (69,140,255)
|
||||
ICON_LOGO = os.path.dirname(os.path.abspath(__file__)) + "/logo-slab-white@0.5x.png"
|
||||
|
||||
ICON_SEARCH = os.path.dirname(os.path.abspath(__file__)) + "/magnify.png"
|
||||
|
||||
ICON_DELETE = os.path.dirname(os.path.abspath(__file__)) + "/delete.png"
|
||||
ICON_DELETE_BLUE = os.path.dirname(os.path.abspath(__file__)) + "/delete-blue.png"
|
||||
|
||||
ICON_SEND = os.path.dirname(os.path.abspath(__file__)) + "/cube-send.png"
|
||||
ICON_RECEIVE = os.path.dirname(os.path.abspath(__file__)) + "/cube-receive.png"
|
||||
|
||||
ICON_SEND_BLACK = os.path.dirname(os.path.abspath(__file__)) + "/cube-send-black.png"
|
||||
ICON_RECEIVE_BLACK = os.path.dirname(os.path.abspath(__file__)) + "/cube-receive-black.png"
|
||||
|
||||
ICON_SEND_BLUE = os.path.dirname(os.path.abspath(__file__)) + "/cube-send-blue.png"
|
||||
ICON_RECEIVE_BLUE = os.path.dirname(os.path.abspath(__file__)) + "/cube-receive-blue.png"
|
||||
|
||||
COLOR = f"color: rgb{str(SPECKLE_COLOR)};"
|
||||
BACKGR_COLOR = f"background-color: rgb{str(SPECKLE_COLOR)};"
|
||||
BACKGR_COLOR_LIGHT = f"background-color: rgb{str(SPECKLE_COLOR_LIGHT)};"
|
||||
|
||||
ui_class = os.path.dirname(os.path.abspath(__file__)) + "/speckle_qgis_dialog_base.ui"
|
||||
print(os.path.dirname(__file__))
|
||||
|
||||
class SpeckleGISDialog(QMainWindow):
|
||||
|
||||
closingPlugin = pyqtSignal()
|
||||
streamList: QtWidgets.QComboBox
|
||||
sendModeButton: QtWidgets.QPushButton
|
||||
receiveModeButton: QtWidgets.QPushButton
|
||||
streamBranchDropdown: QtWidgets.QComboBox
|
||||
layerSendModeDropdown: QtWidgets.QComboBox
|
||||
commitDropdown: QtWidgets.QComboBox
|
||||
layersWidget: QtWidgets.QListWidget
|
||||
saveLayerSelection: QtWidgets.QPushButton
|
||||
runButton: QtWidgets.QPushButton
|
||||
msgLog: LogWidget = None
|
||||
|
||||
gridLayoutTitleBar = QtWidgets.QGridLayout
|
||||
|
||||
def __init__(self):
|
||||
"""Constructor."""
|
||||
print("START MAIN WINDOW")
|
||||
super(SpeckleGISDialog, self).__init__(None)#, QtCore.Qt.WindowStaysOnTopHint)
|
||||
uic.loadUi(ui_class, self) # Load the .ui file
|
||||
#self.installEventFilter(self)
|
||||
self.show()
|
||||
#self.instances.append(1)
|
||||
try:
|
||||
self.streamBranchDropdown.setMaxCount(100)
|
||||
self.commitDropdown.setMaxCount(100)
|
||||
|
||||
self.streams_add_button.setFlat(True)
|
||||
self.streams_remove_button.setFlat(True)
|
||||
self.saveSurveyPoint.setFlat(True)
|
||||
self.saveLayerSelection.setFlat(True)
|
||||
self.reloadButton.setFlat(True)
|
||||
self.closeButton.setFlat(True)
|
||||
|
||||
#backgr_color = f"background-color: rgb{str(SPECKLE_COLOR)};"
|
||||
#backgr_color_light = f"background-color: rgb{str(SPECKLE_COLOR_LIGHT)};"
|
||||
backgr_image_del = f"border-image: url({ICON_DELETE_BLUE});"
|
||||
self.streams_add_button.setIcon(QIcon(ICON_SEARCH))
|
||||
self.streams_add_button.setMaximumWidth(25)
|
||||
self.streams_add_button.setStyleSheet("QPushButton {padding:3px;padding-left:5px;border: none; text-align: left;} QPushButton:hover { " + f"background-color: rgb{str(COLOR_HIGHLIGHT)};" + f"{COLOR}" + " }")
|
||||
self.streams_remove_button.setIcon(QIcon(ICON_DELETE))
|
||||
self.streams_remove_button.setMaximumWidth(25)
|
||||
self.streams_remove_button.setStyleSheet("QPushButton {padding:3px;padding-left:5px;border: none; text-align: left; image-position:right} QPushButton:hover { " + f"background-color: rgb{str(COLOR_HIGHLIGHT)};" + f"{COLOR}" + " }") #+ f"{backgr_image_del}"
|
||||
|
||||
self.saveLayerSelection.setStyleSheet("QPushButton {text-align: right;} QPushButton:hover { " + f"{COLOR}" + " }")
|
||||
self.saveSurveyPoint.setStyleSheet("QPushButton {text-align: right;} QPushButton:hover { " + f"{COLOR}" + " }")
|
||||
self.reloadButton.setStyleSheet("QPushButton {text-align: left;} QPushButton:hover { " + f"{COLOR}" + " }")
|
||||
self.closeButton.setStyleSheet("QPushButton {text-align: right;} QPushButton:hover { " + f"{COLOR}" + " }")
|
||||
|
||||
|
||||
self.sendModeButton.setStyleSheet("QPushButton {padding: 10px; border: 0px; " + f"color: rgb{str(SPECKLE_COLOR)};"+ "} QPushButton:hover { " + "}" )
|
||||
self.sendModeButton.setIcon(QIcon(ICON_SEND_BLUE))
|
||||
|
||||
self.receiveModeButton.setFlat(True)
|
||||
self.receiveModeButton.setStyleSheet("QPushButton {padding: 10px; border: 0px;}"+ "QPushButton:hover { " + f"background-color: rgb{str(COLOR_HIGHLIGHT)};" + "}" )
|
||||
self.receiveModeButton.setIcon(QIcon(ICON_RECEIVE_BLACK))
|
||||
|
||||
self.runButton.setStyleSheet("QPushButton {color: white;border: 0px;border-radius: 17px;padding: 10px;"+ f"{BACKGR_COLOR}" + "} QPushButton:hover { "+ f"{BACKGR_COLOR_LIGHT}" + " }")
|
||||
self.runButton.setMaximumWidth(200)
|
||||
self.runButton.setIcon(QIcon(ICON_SEND))
|
||||
|
||||
# add widgets that will only show on event trigger
|
||||
logWidget = LogWidget(parent=self)
|
||||
self.layout().addWidget(logWidget)
|
||||
self.msgLog = logWidget
|
||||
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3], plugin=self)
|
||||
|
||||
def addProps(self, plugin):
|
||||
self.msgLog.active_account = plugin.active_account
|
||||
self.msgLog.speckle_version = plugin.version
|
||||
|
||||
def addLabel(self, plugin):
|
||||
|
||||
try:
|
||||
exitIcon = QPixmap(ICON_LOGO)
|
||||
exitActIcon = QIcon(exitIcon)
|
||||
|
||||
# create a label
|
||||
text_label = QtWidgets.QPushButton(" for ArcGIS")
|
||||
text_label.setStyleSheet("border: 0px;"
|
||||
"color: white;"
|
||||
f"{BACKGR_COLOR}"
|
||||
"top-margin: 40 px;"
|
||||
"padding: 10px;"
|
||||
"padding-left: 20px;"
|
||||
"font-size: 15px;"
|
||||
"height: 30px;"
|
||||
"text-align: left;"
|
||||
)
|
||||
text_label.setIcon(exitActIcon)
|
||||
text_label.setIconSize(QSize(300, 93))
|
||||
text_label.setMinimumSize(QSize(100, 40))
|
||||
text_label.setMaximumWidth(220)
|
||||
|
||||
version = ""
|
||||
try:
|
||||
if isinstance(plugin.version, str): version = str(plugin.version)
|
||||
except: pass
|
||||
|
||||
version_label = QtWidgets.QPushButton(f"{version}")
|
||||
version_label.setStyleSheet("border: 0px;"
|
||||
"color: white;"
|
||||
f"{BACKGR_COLOR}"
|
||||
"padding-top: 15px;"
|
||||
"padding-left: 0px;"
|
||||
"margin-left: 0px;"
|
||||
"font-size: 10px;"
|
||||
"height: 30px;"
|
||||
"text-align: left;"
|
||||
)
|
||||
|
||||
widget = QWidget()
|
||||
widget.setStyleSheet(f"{BACKGR_COLOR}")
|
||||
connect_box = QHBoxLayout(widget)
|
||||
connect_box.addWidget(text_label) #, alignment=Qt.AlignCenter)
|
||||
connect_box.addWidget(version_label)
|
||||
connect_box.setContentsMargins(0, 0, 0, 0)
|
||||
self.gridLayoutTitleBar.addWidget(widget) # fro QMainWindow
|
||||
#self.setTitleBarWidget(widget) # for QDockWidget
|
||||
except Exception as e:
|
||||
logToUser(e)
|
||||
|
||||
def resizeEvent(self, event):
|
||||
try:
|
||||
#print("resize")
|
||||
QtWidgets.QMainWindow.resizeEvent(self, event)
|
||||
if self.msgLog.size().height() != 0: # visible
|
||||
self.msgLog.setGeometry(0, 0, self.msgLog.parentWidget.frameSize().width(), self.msgLog.parentWidget.frameSize().height()) #.resize(self.frameSize().width(), self.frameSize().height())
|
||||
except Exception as e:
|
||||
#logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
||||
return
|
||||
|
||||
def closeEvent(self, event):
|
||||
try:
|
||||
#import threading
|
||||
print("Close event")
|
||||
#threads = threading.enumerate()
|
||||
#print(f"Threads total: {str(len(threads))}: {str(threads)}")
|
||||
|
||||
#print(self.instances)
|
||||
|
||||
self.closingPlugin.emit()
|
||||
event.accept()
|
||||
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3], plugin=self)
|
||||
|
||||
def clearDropdown(self):
|
||||
try:
|
||||
#self.streamIdField.clear()
|
||||
self.streamBranchDropdown.clear()
|
||||
self.commitDropdown.clear()
|
||||
#self.layerSendModeDropdown.clear()
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3], plugin=self)
|
||||
|
||||
def reloadDialogUI(self, plugin):
|
||||
try:
|
||||
self.clearDropdown()
|
||||
self.populateUI(plugin)
|
||||
self.enableElements(plugin)
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3], plugin=self)
|
||||
|
||||
|
||||
|
||||
def run(self, plugin):
|
||||
try:
|
||||
print("dockwidget run")
|
||||
# Setup events on first load only!
|
||||
self.setupOnFirstLoad(plugin)
|
||||
# Connect streams section events
|
||||
self.completeStreamSection(plugin)
|
||||
# Populate the UI dropdowns
|
||||
self.populateUI(plugin)
|
||||
print("dockwidget run end")
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3], plugin=self)
|
||||
|
||||
|
||||
def setupOnFirstLoad(self, plugin):
|
||||
try:
|
||||
self.runButton.clicked.connect(plugin.onRunButtonClicked)
|
||||
|
||||
self.streams_add_button.clicked.connect( plugin.onStreamAddButtonClicked )
|
||||
self.reloadButton.clicked.connect(lambda: self.refreshClicked(plugin))
|
||||
self.closeButton.clicked.connect(lambda: self.closeClicked(plugin))
|
||||
self.saveSurveyPoint.clicked.connect(plugin.set_survey_point)
|
||||
self.saveLayerSelection.clicked.connect(lambda: self.populateLayerDropdown(plugin))
|
||||
self.sendModeButton.clicked.connect(lambda: self.setSendMode(plugin))
|
||||
self.layerSendModeDropdown.currentIndexChanged.connect( lambda: self.layerSendModeChange(plugin) )
|
||||
self.receiveModeButton.clicked.connect(lambda: self.setReceiveMode(plugin))
|
||||
|
||||
self.streamBranchDropdown.currentIndexChanged.connect( lambda: self.runBtnStatusChanged(plugin) )
|
||||
self.commitDropdown.currentIndexChanged.connect( lambda: self.runBtnStatusChanged(plugin) )
|
||||
|
||||
self.closingPlugin.connect(plugin.onClosePlugin)
|
||||
return
|
||||
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3], plugin=self)
|
||||
|
||||
def refreshClicked(self, plugin):
|
||||
try:
|
||||
try:
|
||||
metrics.track("Connector Action", plugin.active_account, {"name": "Refresh", "connector_version": str(plugin.version)})
|
||||
except Exception as e:
|
||||
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=plugin.dockwidget )
|
||||
|
||||
plugin.reloadUI()
|
||||
except Exception as e:
|
||||
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
||||
return
|
||||
|
||||
def closeClicked(self, plugin):
|
||||
try:
|
||||
try:
|
||||
metrics.track("Connector Action", plugin.active_account, {"name": "Close", "connector_version": str(plugin.version)})
|
||||
except Exception as e:
|
||||
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=plugin.dockwidget )
|
||||
|
||||
plugin.onClosePlugin()
|
||||
except Exception as e:
|
||||
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
||||
return
|
||||
|
||||
def setSendMode(self, plugin):
|
||||
try:
|
||||
plugin.btnAction = 0 # send
|
||||
color = f"color: rgb{str(SPECKLE_COLOR)};"
|
||||
self.sendModeButton.setStyleSheet("border: 0px;"
|
||||
f"color: rgb{str(SPECKLE_COLOR)};"
|
||||
"padding: 10px;")
|
||||
self.sendModeButton.setIcon(QIcon(ICON_SEND_BLUE))
|
||||
self.sendModeButton.setFlat(False)
|
||||
self.receiveModeButton.setFlat(True)
|
||||
self.receiveModeButton.setStyleSheet("QPushButton {border: 0px; color: black; padding: 10px; } QPushButton:hover { " + f"background-color: rgb{str(COLOR_HIGHLIGHT)};" + " };")
|
||||
self.receiveModeButton.setIcon(QIcon(ICON_RECEIVE_BLACK))
|
||||
#self.receiveModeButton.setFlat(True)
|
||||
self.runButton.setProperty("text", " SEND")
|
||||
self.runButton.setIcon(QIcon(ICON_SEND))
|
||||
|
||||
# enable sections only if in "saved streams" mode
|
||||
if self.layerSendModeDropdown.currentIndex() == 1: self.layersWidget.setEnabled(True)
|
||||
if self.layerSendModeDropdown.currentIndex() == 1: self.saveLayerSelection.setEnabled(True)
|
||||
self.commitDropdown.setEnabled(False)
|
||||
self.messageInput.setEnabled(True)
|
||||
self.layerSendModeDropdown.setEnabled(True)
|
||||
|
||||
self.runBtnStatusChanged(plugin)
|
||||
return
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3], plugin=self)
|
||||
|
||||
def setReceiveMode(self, plugin):
|
||||
try:
|
||||
plugin.btnAction = 1 # receive
|
||||
color = f"color: rgb{str(SPECKLE_COLOR)};"
|
||||
self.receiveModeButton.setStyleSheet("border: 0px;"
|
||||
f"color: rgb{str(SPECKLE_COLOR)};"
|
||||
"padding: 10px;")
|
||||
self.sendModeButton.setIcon(QIcon(ICON_SEND_BLACK))
|
||||
self.sendModeButton.setStyleSheet("QPushButton {border: 0px; color: black; padding: 10px;} QPushButton:hover { " + f"background-color: rgb{str(COLOR_HIGHLIGHT)};" + " };")
|
||||
self.receiveModeButton.setIcon(QIcon(ICON_RECEIVE_BLUE))
|
||||
self.sendModeButton.setFlat(True)
|
||||
self.receiveModeButton.setFlat(False)
|
||||
#self.sendModeButton.setFlat(True)
|
||||
self.runButton.setProperty("text", " RECEIVE")
|
||||
self.runButton.setIcon(QIcon(ICON_RECEIVE))
|
||||
#self.layerSendModeChange(plugin, 1)
|
||||
self.commitDropdown.setEnabled(True)
|
||||
self.layersWidget.setEnabled(False)
|
||||
self.messageInput.setEnabled(False)
|
||||
self.saveLayerSelection.setEnabled(False)
|
||||
self.layerSendModeDropdown.setEnabled(False)
|
||||
|
||||
self.runBtnStatusChanged(plugin)
|
||||
return
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3], plugin=self)
|
||||
|
||||
def completeStreamSection(self, plugin):
|
||||
self.streams_remove_button.clicked.connect( lambda: self.onStreamRemoveButtonClicked(plugin) )
|
||||
self.streamList.currentIndexChanged.connect( lambda: self.onActiveStreamChanged(plugin) )
|
||||
self.streamBranchDropdown.currentIndexChanged.connect( lambda: self.populateActiveCommitDropdown(plugin) )
|
||||
return
|
||||
|
||||
def populateUI(self, plugin):
|
||||
try:
|
||||
self.populateLayerSendModeDropdown()
|
||||
self.populateLayerDropdown(plugin, False)
|
||||
#items = [self.layersWidget.item(x).text() for x in range(self.layersWidget.count())]
|
||||
self.populateProjectStreams(plugin)
|
||||
self.populateSurveyPoint(plugin)
|
||||
|
||||
self.runBtnStatusChanged(plugin)
|
||||
self.runButton.setEnabled(False)
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3], plugin=self)
|
||||
|
||||
def runBtnStatusChanged(self, plugin):
|
||||
try:
|
||||
commitStr = str(self.commitDropdown.currentText())
|
||||
branchStr = str(self.streamBranchDropdown.currentText())
|
||||
|
||||
if plugin.btnAction == 1: # on receive
|
||||
if commitStr == "":
|
||||
self.runButton.setEnabled(False)
|
||||
else:
|
||||
self.runButton.setEnabled(True)
|
||||
|
||||
if plugin.btnAction == 0: # on send
|
||||
if branchStr == "":
|
||||
self.runButton.setEnabled(False)
|
||||
elif branchStr != "" and self.layerSendModeDropdown.currentIndex() == 1 and len(plugin.current_layers) == 0: # saved layers; but the list is empty
|
||||
self.runButton.setEnabled(False)
|
||||
else:
|
||||
self.runButton.setEnabled(True)
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3], plugin=self)
|
||||
|
||||
|
||||
def layerSendModeChange(self, plugin, runMode = None):
|
||||
try:
|
||||
print("Send mode changed")
|
||||
|
||||
if self.layerSendModeDropdown.currentIndex() == 0 or runMode == 1: # by manual selection OR receive mode
|
||||
self.current_layers = []
|
||||
self.layersWidget.setEnabled(False)
|
||||
self.saveLayerSelection.setEnabled(False)
|
||||
|
||||
elif self.layerSendModeDropdown.currentIndex() == 1 and (runMode == 0 or runMode is None): # by saved AND when Send mode
|
||||
self.layersWidget.setEnabled(True)
|
||||
self.saveLayerSelection.setEnabled(True)
|
||||
|
||||
branchStr = str(self.streamBranchDropdown.currentText())
|
||||
if self.layerSendModeDropdown.currentIndex() == 0:
|
||||
if branchStr == "": self.runButton.setEnabled(False) # by manual selection
|
||||
else: self.runButton.setEnabled(True) # by manual selection
|
||||
elif self.layerSendModeDropdown.currentIndex() == 1: self.runBtnStatusChanged(plugin) # by saved
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3], plugin=self)
|
||||
|
||||
|
||||
def populateLayerDropdown(self, plugin, bySelection: bool = True):
|
||||
print("populate layer dropdown / clicked save selection")
|
||||
if not self: return
|
||||
try:
|
||||
from speckle.speckle.ui.project_vars import set_project_layer_selection
|
||||
except:
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.ui.project_vars import set_project_layer_selection
|
||||
|
||||
try:
|
||||
self.layersWidget.clear()
|
||||
nameDisplay = []
|
||||
project = plugin.gis_project
|
||||
|
||||
if bySelection is False: # read from project data
|
||||
print("populate layers from saved data")
|
||||
#print(project)
|
||||
#print(project.activeMap)
|
||||
|
||||
all_layers_ids = [l.dataSource for l in getAllProjLayers(project)]
|
||||
for layer_tuple in plugin.current_layers:
|
||||
if layer_tuple[1].dataSource in all_layers_ids:
|
||||
listItem = self.fillLayerList(layer_tuple[1])
|
||||
self.layersWidget.addItem(listItem)
|
||||
|
||||
else: # read selected layers
|
||||
# Fetch selected layers
|
||||
print("populate layers from selection")
|
||||
|
||||
plugin.current_layers = []
|
||||
layers = getLayers(plugin, bySelection) # List[QgsLayerTreeNode]
|
||||
print(layers)
|
||||
for i, layer in enumerate(layers):
|
||||
plugin.current_layers.append((layer.name, layer))
|
||||
listItem = self.fillLayerList(layer)
|
||||
self.layersWidget.addItem(listItem)
|
||||
print("populate layers from selection 2")
|
||||
set_project_layer_selection(plugin)
|
||||
print("populate layers from selection 3")
|
||||
|
||||
self.layersWidget.setIconSize(QSize(20, 20))
|
||||
self.runBtnStatusChanged(plugin)
|
||||
|
||||
return
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3], plugin=self)
|
||||
|
||||
def fillLayerList(self, layer):
|
||||
print("Fill layer list")
|
||||
|
||||
try:
|
||||
ICON_XXL = os.path.dirname(os.path.abspath(__file__)) + "/size-xxl.png"
|
||||
ICON_RASTER = os.path.dirname(os.path.abspath(__file__)) + "/legend_raster.png"
|
||||
ICON_POLYGON = os.path.dirname(os.path.abspath(__file__)) + "/legend_polygon.png"
|
||||
ICON_LINE = os.path.dirname(os.path.abspath(__file__)) + "/legend_line.png"
|
||||
ICON_POINT = os.path.dirname(os.path.abspath(__file__)) + "/legend_point.png"
|
||||
|
||||
listItem = QListWidgetItem(layer.name)
|
||||
#print(listItem)
|
||||
|
||||
if layer.isRasterLayer: # and layer.width()*layer.height() > 1000000:
|
||||
listItem.setIcon(QIcon(ICON_RASTER))
|
||||
|
||||
elif layer.isFeatureLayer: # and layer.featureCount() > 20000:
|
||||
geomType = arcpy.Describe(layer.dataSource).shapeType
|
||||
if geomType == "Polygon": listItem.setIcon(QIcon(ICON_POLYGON))
|
||||
elif geomType == "Polyline": listItem.setIcon(QIcon(ICON_LINE))
|
||||
elif geomType == "Point" or geomType == "Multipoint": listItem.setIcon(QIcon(ICON_POINT))
|
||||
else:
|
||||
listItem.setIcon(QIcon(ICON_XXL))
|
||||
#else:
|
||||
# icon = QgsIconUtils().iconForLayer(layer)
|
||||
# listItem.setIcon(icon)
|
||||
|
||||
return listItem
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3], plugin=self)
|
||||
|
||||
def populateSurveyPoint(self, plugin):
|
||||
if not self:
|
||||
return
|
||||
try:
|
||||
self.surveyPointLat.clear()
|
||||
self.surveyPointLat.setText(str(plugin.lat))
|
||||
self.surveyPointLon.clear()
|
||||
self.surveyPointLon.setText(str(plugin.lon))
|
||||
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3], plugin=self)
|
||||
|
||||
def enableElements(self, plugin):
|
||||
try:
|
||||
self.sendModeButton.setEnabled(plugin.is_setup)
|
||||
self.receiveModeButton.setEnabled(plugin.is_setup)
|
||||
self.runButton.setEnabled(plugin.is_setup)
|
||||
self.streams_add_button.setEnabled(plugin.is_setup)
|
||||
if plugin.is_setup is False: self.streams_remove_button.setEnabled(plugin.is_setup)
|
||||
self.streamBranchDropdown.setEnabled(plugin.is_setup)
|
||||
self.layerSendModeDropdown.setEnabled(plugin.is_setup)
|
||||
self.commitDropdown.setEnabled(False)
|
||||
self.show()
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3], plugin=self)
|
||||
|
||||
def populateProjectStreams(self, plugin):
|
||||
|
||||
try:
|
||||
from speckle.speckle.ui.project_vars import set_project_streams
|
||||
except:
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.ui.project_vars import set_project_streams
|
||||
|
||||
try:
|
||||
if not self: return
|
||||
self.streamList.clear()
|
||||
for stream in plugin.current_streams:
|
||||
self.streamList.addItems(
|
||||
[f"Stream not accessible - {stream[0].stream_id}" if stream[1] is None or isinstance(stream[1], SpeckleException) else f"{stream[1].name}, {stream[1].id} | {stream[0].stream_url.split('/streams')[0]}"]
|
||||
)
|
||||
if len(plugin.current_streams)==0: self.streamList.addItems([""])
|
||||
self.streamList.addItems(["Create New Stream"])
|
||||
set_project_streams(plugin)
|
||||
index = self.streamList.currentIndex()
|
||||
if index == -1: self.streams_remove_button.setEnabled(False)
|
||||
else: self.streams_remove_button.setEnabled(True)
|
||||
|
||||
if len(plugin.current_streams)>0: plugin.active_stream = plugin.current_streams[0]
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3], plugin=self)
|
||||
|
||||
|
||||
def onActiveStreamChanged(self, plugin):
|
||||
|
||||
if not self: return
|
||||
try:
|
||||
index = self.streamList.currentIndex()
|
||||
if (len(plugin.current_streams) == 0 and index ==1) or (len(plugin.current_streams)>0 and index == len(plugin.current_streams)):
|
||||
self.populateProjectStreams(plugin)
|
||||
plugin.onStreamCreateClicked()
|
||||
return
|
||||
if len(plugin.current_streams) == 0: return
|
||||
if index == -1: return
|
||||
|
||||
try: plugin.active_stream = plugin.current_streams[index]
|
||||
except: plugin.active_stream = None
|
||||
|
||||
self.populateActiveStreamBranchDropdown(plugin)
|
||||
self.populateActiveCommitDropdown(plugin)
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3], plugin=self)
|
||||
|
||||
def populateLayerSendModeDropdown(self):
|
||||
if not self: return
|
||||
try:
|
||||
self.layerSendModeDropdown.clear()
|
||||
self.layerSendModeDropdown.addItems(
|
||||
["Send visible layers", "Send saved layers"]
|
||||
)
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3], plugin=self)
|
||||
|
||||
def populateActiveStreamBranchDropdown(self, plugin):
|
||||
if not self: return
|
||||
if plugin.active_stream is None: return
|
||||
try:
|
||||
self.streamBranchDropdown.clear()
|
||||
if isinstance(plugin.active_stream[1], SpeckleException):
|
||||
#logger.logToUser("Some streams cannot be accessed", Qgis.Warning)
|
||||
return
|
||||
elif plugin.active_stream is None or plugin.active_stream[1] is None or plugin.active_stream[1].branches is None:
|
||||
return
|
||||
self.streamBranchDropdown.addItems(
|
||||
[f"{branch.name}" for branch in plugin.active_stream[1].branches.items]
|
||||
)
|
||||
self.streamBranchDropdown.addItems(["Create New Branch"])
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3], plugin=self)
|
||||
|
||||
def populateActiveCommitDropdown(self, plugin):
|
||||
if not self: return
|
||||
try:
|
||||
self.commitDropdown.clear()
|
||||
if plugin.active_stream is None: return
|
||||
branchName = self.streamBranchDropdown.currentText()
|
||||
if branchName == "": return
|
||||
if branchName == "Create New Branch":
|
||||
self.streamBranchDropdown.setCurrentText("main")
|
||||
plugin.onBranchCreateClicked()
|
||||
return
|
||||
branch = None
|
||||
if isinstance(plugin.active_stream[1], SpeckleException):
|
||||
#logger.logToUser("Some streams cannot be accessed", Qgis.Warning)
|
||||
return
|
||||
elif plugin.active_stream[1]:
|
||||
for b in plugin.active_stream[1].branches.items:
|
||||
if b.name == branchName:
|
||||
branch = b
|
||||
break
|
||||
try:
|
||||
self.commitDropdown.addItems(
|
||||
[f"{commit.id}"+ " | " + f"{commit.message}" for commit in branch.commits.items]
|
||||
)
|
||||
except: pass
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3], plugin=self)
|
||||
|
||||
def onStreamRemoveButtonClicked(self, plugin):
|
||||
try:
|
||||
#from ui.project_vars import set_project_streams
|
||||
if not self: return
|
||||
index = self.streamList.currentIndex()
|
||||
if len(plugin.current_streams) > 0: plugin.current_streams.pop(index)
|
||||
plugin.active_stream = None
|
||||
self.streamBranchDropdown.clear()
|
||||
self.commitDropdown.clear()
|
||||
#self.streamIdField.setText("")
|
||||
|
||||
#set_project_streams(plugin)
|
||||
self.populateProjectStreams(plugin)
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3], plugin=self)
|
||||
|
||||
@@ -1,316 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SpeckleQArcGISDialog</class>
|
||||
<widget class="QMainWindow" name="SpeckleQArcGISDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QWidget" name="dockWidgetContents">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayoutTitleBar">
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="leftMargin">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>30</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
|
||||
|
||||
<item row="0" column="1">
|
||||
<layout class="QHBoxLayout" name="streamListButtons">
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="streamListLabel">
|
||||
<property name="text">
|
||||
<string>Stream</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="streamListButtons" stretch="20,1">
|
||||
<item>
|
||||
<widget class="QComboBox" name="streamList"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="streams_add_button">
|
||||
<property name="text">
|
||||
<string> </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="streams_remove_button">
|
||||
<property name="text">
|
||||
<string> </string>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>10</width>
|
||||
<height>10</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
|
||||
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="streamBranchLabel">
|
||||
<property name="text">
|
||||
<string>Branch</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="streamBranchDropdown"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="commitLabel">
|
||||
<property name="text">
|
||||
<string>Commit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="commitDropdown"/>
|
||||
</item>
|
||||
|
||||
<item row="4" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
|
||||
<item row="5" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="sendModeButton">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Send</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="receiveModeButton">
|
||||
<property name="text">
|
||||
<string>Receive</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
<item row="6" column="1">
|
||||
<widget class="QComboBox" name="layerSendModeDropdown"/>
|
||||
</item>
|
||||
|
||||
|
||||
|
||||
<item row="7" column="1">
|
||||
<widget class="QListWidget" name="layersWidget">
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::NoSelection</enum>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QAbstractScrollArea::AdjustToContents</enum>
|
||||
</property>
|
||||
<property name="resizeMode">
|
||||
<enum>QListView::Fixed</enum>
|
||||
</property>
|
||||
<property name="viewMode">
|
||||
<enum>QListView::ListMode</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
|
||||
<item row="8" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<widget class="QPushButton" name="saveLayerSelection">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Set visible layers as selection</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="messageLabel">
|
||||
<property name="text">
|
||||
<string>Message</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QLineEdit" name="messageInput">
|
||||
<property name="placeholderText">
|
||||
<string>Sent XXX objects from ArcGIS</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
|
||||
|
||||
<item row="10" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<widget class="QPushButton" name="runButton">
|
||||
<property name="text">
|
||||
<string> SEND</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
<item row="11" column="0">
|
||||
<widget class="QLabel" name="surveyPointLabel">
|
||||
<property name="text">
|
||||
<string>Lat °, Lon °</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="surveyPointLat">
|
||||
<property name="placeholderText">
|
||||
<string>0.0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="surveyPointLon">
|
||||
<property name="placeholderText">
|
||||
<string>0.0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<widget class="QPushButton" name="saveSurveyPoint">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Set as a project center</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
<item row="12" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
|
||||
<item>
|
||||
<widget class="QPushButton" name="reloadButton">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Refresh</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="closeButton">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Close</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
|
||||
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -1,19 +0,0 @@
|
||||
import os
|
||||
from PyQt5 import QtWidgets, uic
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
|
||||
# This loads your .ui file so that PyQt can populate your plugin with the elements from Qt Designer
|
||||
|
||||
ui_class = os.path.dirname(os.path.abspath(__file__)) + "/streamlist_dialog.ui"
|
||||
|
||||
class StreamListDialog(QtWidgets.QWidget):
|
||||
streams_add_button: QtWidgets.QPushButton
|
||||
streams_reload_button: QtWidgets.QPushButton
|
||||
streams_remove_button: QtWidgets.QPushButton
|
||||
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(StreamListDialog, self).__init__(parent)
|
||||
uic.loadUi(ui_class, self) # Load the .ui file
|
||||
self.show()
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>StreamListDialog</class>
|
||||
<widget class="QWidget" name="StreamListDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>70</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_3">
|
||||
<property name="text">
|
||||
<string>PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="text">
|
||||
<string>PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_2">
|
||||
<property name="text">
|
||||
<string>PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -1,165 +0,0 @@
|
||||
|
||||
from typing import Union
|
||||
from specklepy.api.wrapper import StreamWrapper
|
||||
from specklepy.api.models import Stream, Branch, Commit
|
||||
from specklepy.transports.server import ServerTransport
|
||||
from specklepy.api.client import SpeckleClient
|
||||
from specklepy.logging.exceptions import SpeckleException, GraphQLException
|
||||
|
||||
import inspect
|
||||
|
||||
import arcpy
|
||||
try:
|
||||
from speckle.speckle.ui.logger import logToUser
|
||||
except:
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.ui.logger import logToUser
|
||||
|
||||
def tryGetStream(
|
||||
sw: StreamWrapper, dataStorage, write=False, dockwidget=None
|
||||
) -> Union[Stream, None]:
|
||||
try:
|
||||
# print("tryGetStream")
|
||||
client, stream = tryGetClient(sw, dataStorage, write, dockwidget)
|
||||
return stream
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3], plugin=dockwidget)
|
||||
return None
|
||||
|
||||
|
||||
def tryGetClient(sw: StreamWrapper, dataStorage, write=False, dockwidget=None):
|
||||
# only streams with write access
|
||||
try:
|
||||
client = None
|
||||
savedRole = None
|
||||
savedStreamId = None
|
||||
for acc in dataStorage.accounts:
|
||||
# only check accounts on selected server
|
||||
if acc.serverInfo.url in sw.server_url:
|
||||
client = SpeckleClient(
|
||||
acc.serverInfo.url, acc.serverInfo.url.startswith("https")
|
||||
)
|
||||
try:
|
||||
client.authenticate_with_account(acc)
|
||||
if client.account.token is not None:
|
||||
break
|
||||
except SpeckleException as ex:
|
||||
if "already connected" in ex.message:
|
||||
logToUser(
|
||||
"Dependencies versioning error.\nClick here for details.",
|
||||
url="dependencies_error",
|
||||
level=2,
|
||||
plugin=dockwidget,
|
||||
)
|
||||
return
|
||||
else:
|
||||
raise ex
|
||||
|
||||
# if token still not found
|
||||
if client is None or client.account.token is None:
|
||||
for acc in dataStorage.accounts:
|
||||
client = sw.get_client()
|
||||
if client is not None:
|
||||
break
|
||||
|
||||
if client is not None:
|
||||
stream = client.stream.get(
|
||||
id=sw.stream_id, branch_limit=100, commit_limit=100
|
||||
)
|
||||
if isinstance(stream, Stream):
|
||||
# print(stream.role)
|
||||
if write == False:
|
||||
# try get stream, only read access needed
|
||||
# print("only read access needed")
|
||||
return client, stream
|
||||
else:
|
||||
# check write access
|
||||
# print("write access needed")
|
||||
if stream.role is None or (
|
||||
isinstance(stream.role, str) and "reviewer" in stream.role
|
||||
):
|
||||
savedRole = stream.role
|
||||
savedStreamId = stream.id
|
||||
else:
|
||||
return client, stream
|
||||
|
||||
if savedRole is not None and savedStreamId is not None:
|
||||
logToUser(
|
||||
f"You don't have write access to the stream '{savedStreamId}'. You role is '{savedRole}'",
|
||||
level=2,
|
||||
func=inspect.stack()[0][3],
|
||||
plugin=dockwidget,
|
||||
)
|
||||
|
||||
return None, None
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3], plugin=dockwidget)
|
||||
return None, None
|
||||
|
||||
|
||||
def validateStream(stream: Stream, dockwidget) -> Union[Stream, None]:
|
||||
try:
|
||||
if isinstance(stream, SpeckleException):
|
||||
return None
|
||||
|
||||
if stream.branches is None:
|
||||
logToUser("Stream has no branches", level=1, plugin=dockwidget)
|
||||
return None
|
||||
return stream
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, plugin=dockwidget)
|
||||
return
|
||||
|
||||
|
||||
def validateBranch(stream: Stream, branchName: str, checkCommits: bool) -> Union[Branch, None]:
|
||||
try:
|
||||
branch = None
|
||||
if not stream.branches or not stream.branches.items:
|
||||
return None
|
||||
for b in stream.branches.items:
|
||||
if b.name == branchName:
|
||||
branch = b
|
||||
break
|
||||
if branch is None:
|
||||
logToUser("Failed to find a branch", level=2, func = inspect.stack()[0][3])
|
||||
return None
|
||||
if checkCommits == True:
|
||||
if branch.commits is None:
|
||||
logToUser("Failed to find a branch", level=2, func = inspect.stack()[0][3])
|
||||
return None
|
||||
if len(branch.commits.items)==0:
|
||||
logToUser("Branch contains no commits", level=2, func = inspect.stack()[0][3])
|
||||
return None
|
||||
return branch
|
||||
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
return None
|
||||
|
||||
def validateCommit(branch: Branch, commitId: str) -> Union[Commit, None]:
|
||||
try:
|
||||
commit = None
|
||||
try: commitId = commitId.split(" | ")[0]
|
||||
except: logToUser("Commit ID is not valid", level=2, func = inspect.stack()[0][3])
|
||||
|
||||
for i in branch.commits.items:
|
||||
if i.id == commitId:
|
||||
commit = i
|
||||
break
|
||||
if commit is None:
|
||||
try:
|
||||
commit = branch.commits.items[0]
|
||||
logToUser("Failed to find a commit. Receiving Latest", level=2, func = inspect.stack()[0][3])
|
||||
except:
|
||||
logToUser("Failed to find a commit", level=2, func = inspect.stack()[0][3])
|
||||
return None
|
||||
return commit
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func = inspect.stack()[0][3])
|
||||
|
||||
def validateTransport(client: SpeckleClient, streamId: str) -> Union[ServerTransport, None]:
|
||||
try:
|
||||
transport = ServerTransport(client=client, stream_id=streamId)
|
||||
return transport
|
||||
except Exception as e:
|
||||
logToUser("Make sure you have sufficient permissions: " + str(e), level=2, func = inspect.stack()[0][3])
|
||||
return None
|
||||
@@ -0,0 +1,74 @@
|
||||
from PyQt5.QtWidgets import QMessageBox
|
||||
from PyQt5 import QtCore
|
||||
import arcpy
|
||||
|
||||
try:
|
||||
from speckle.speckle.plugin_utils.helpers import splitTextIntoLines
|
||||
except:
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.plugin_utils.helpers import (
|
||||
splitTextIntoLines,
|
||||
)
|
||||
|
||||
import inspect
|
||||
|
||||
|
||||
def logToUser(msg: str, func=None, level: int = 2, plugin=None, url="", blue=False):
|
||||
print("Log to user")
|
||||
print(msg)
|
||||
|
||||
msg = str(msg)
|
||||
dockwidget = plugin
|
||||
|
||||
try:
|
||||
if url == "" and blue is False: # only for info messages
|
||||
msg = addLevelSymbol(msg, level)
|
||||
if func is not None:
|
||||
msg += "::" + str(func)
|
||||
writeToLog(msg, level)
|
||||
|
||||
if dockwidget is None:
|
||||
return
|
||||
|
||||
new_msg = splitTextIntoLines(msg, 70)
|
||||
|
||||
dockwidget.msgLog.addButton(new_msg, level=level, url=url, blue=blue)
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return
|
||||
|
||||
|
||||
def logToUserWithAction(msg: str, level: int = 0, plugin=None, url=""):
|
||||
print("Log to user with action")
|
||||
return
|
||||
msg = str(msg)
|
||||
dockwidget = plugin
|
||||
if dockwidget is None:
|
||||
return
|
||||
try:
|
||||
new_msg = splitTextIntoLines(msg, 70)
|
||||
dockwidget.msgLog.addButton(new_msg, level=level, url=url)
|
||||
writeToLog(new_msg, level)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return
|
||||
|
||||
|
||||
def addLevelSymbol(msg: str, level: int):
|
||||
if level == 0:
|
||||
msg = "🛈 " + msg
|
||||
if level == 1:
|
||||
msg = "⚠️ " + msg
|
||||
if level == 2:
|
||||
msg = "❗ " + msg
|
||||
return msg
|
||||
|
||||
|
||||
def writeToLog(msg: str = "", level: int = 2):
|
||||
print(msg)
|
||||
if level == 0:
|
||||
arcpy.AddMessage(msg)
|
||||
if level == 1:
|
||||
arcpy.AddWarning(msg)
|
||||
if level == 2:
|
||||
arcpy.AddError(msg)
|
||||
@@ -0,0 +1,128 @@
|
||||
"""Logging Utility Module for Speckle QGIS"""
|
||||
|
||||
import inspect
|
||||
from typing import Union
|
||||
import webbrowser
|
||||
|
||||
import arcpy
|
||||
|
||||
|
||||
def logToUser(
|
||||
msg: Union[str, Exception],
|
||||
func=None,
|
||||
level: int = 2,
|
||||
plugin=None,
|
||||
url="",
|
||||
blue=False,
|
||||
report=False,
|
||||
):
|
||||
from speckle.specklepy_qt_ui.qt_ui.utils.logger import logToUser as logToUser_UI
|
||||
|
||||
msg = str(msg)
|
||||
print(msg)
|
||||
logToUser_UI(msg, func, level, plugin, url, blue, report)
|
||||
logger.writeToLog(msg.replace("\n", ". ") + " " + url, level, func)
|
||||
|
||||
|
||||
class Logging:
|
||||
"""Holds utility methods for logging messages to QGIS"""
|
||||
|
||||
qgisInterface = None
|
||||
|
||||
def __init__(self, iface) -> None:
|
||||
self.qgisInterface = iface
|
||||
|
||||
def log(self, message: str, level: int = 0):
|
||||
"""Logs a specific message to the Speckle messages panel."""
|
||||
try:
|
||||
if level == 0:
|
||||
arcpy.AddMessage(message)
|
||||
elif level == 1:
|
||||
arcpy.AddWarning(message)
|
||||
# elif level == 2: 3 error will quit pluging
|
||||
# arcpy.AddError(message)
|
||||
except Exception as e:
|
||||
try:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3])
|
||||
except:
|
||||
pass
|
||||
|
||||
def btnClicked(url):
|
||||
try:
|
||||
if url == "":
|
||||
return
|
||||
webbrowser.open(url, new=0, autoraise=True)
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
def logToUserWithAction(
|
||||
self,
|
||||
message: str,
|
||||
action_text: str,
|
||||
url: str = "",
|
||||
level: int = 0,
|
||||
duration: int = 120,
|
||||
):
|
||||
self.log(message, level)
|
||||
return
|
||||
if not self.qgisInterface:
|
||||
return
|
||||
try:
|
||||
from qgis.core import Qgis
|
||||
from qgis.PyQt.QtWidgets import QPushButton
|
||||
|
||||
if level == 0:
|
||||
level = Qgis.Info
|
||||
elif level == 1:
|
||||
level = Qgis.Warning
|
||||
elif level == 2:
|
||||
level = Qgis.Critical
|
||||
|
||||
widget = self.qgisInterface.messageBar().createMessage("Speckle", message)
|
||||
button = QPushButton(widget)
|
||||
button.setText(action_text)
|
||||
button.pressed.connect(lambda: self.btnClicked(url))
|
||||
widget.layout().addWidget(button)
|
||||
self.qgisInterface.messageBar().pushWidget(widget, level, duration)
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
def logToUserPanel(
|
||||
self,
|
||||
message: str,
|
||||
level: int = 0,
|
||||
duration: int = 20,
|
||||
func=None,
|
||||
plugin=None,
|
||||
):
|
||||
"""Logs a specific message to the user in QGIS"""
|
||||
return
|
||||
self.log(message, level)
|
||||
|
||||
if not self.qgisInterface:
|
||||
return
|
||||
try:
|
||||
from qgis.core import Qgis
|
||||
|
||||
if level == 0:
|
||||
level = Qgis.Info
|
||||
if level == 1:
|
||||
level = Qgis.Warning
|
||||
if level == 2:
|
||||
level = Qgis.Critical
|
||||
|
||||
if self.qgisInterface:
|
||||
self.qgisInterface.messageBar().pushMessage(
|
||||
"Speckle", message, level=level, duration=duration
|
||||
)
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
def writeToLog(self, msg: str = "", level: int = 2, func=None, plugin=None):
|
||||
msg = str(msg)
|
||||
if func is not None and func != "None":
|
||||
msg += "::" + str(func)
|
||||
self.log(msg, level)
|
||||
|
||||
|
||||
logger = Logging(None)
|
||||
@@ -0,0 +1,572 @@
|
||||
from typing import Any, List, Optional, Tuple, Union
|
||||
import arcpy
|
||||
from arcpy._mp import ArcGISProject, Map, Layer as arcLayer
|
||||
from arcpy.management import CreateTable
|
||||
|
||||
import os.path
|
||||
|
||||
from specklepy.api.credentials import Account, get_local_accounts
|
||||
from specklepy.api.client import SpeckleClient
|
||||
from specklepy.logging.exceptions import (
|
||||
GraphQLException,
|
||||
SpeckleException,
|
||||
)
|
||||
from specklepy.api.wrapper import StreamWrapper
|
||||
from specklepy.api.models import Branch, Stream, Streams
|
||||
from specklepy.logging import metrics
|
||||
|
||||
from osgeo import osr
|
||||
|
||||
import inspect
|
||||
|
||||
try:
|
||||
from speckle.speckle.utils.validation import tryGetStream
|
||||
from speckle.speckle.speckle_arcgis import SpeckleGIS
|
||||
from speckle.speckle.converter.layers import getAllProjLayers
|
||||
from speckle.speckle.utils.panel_logging import logToUser
|
||||
except:
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.utils.validation import (
|
||||
tryGetStream,
|
||||
)
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.speckle_arcgis import SpeckleGIS
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.converter.layers import (
|
||||
getAllProjLayers,
|
||||
)
|
||||
from speckle_toolbox.esri.toolboxes.speckle.speckle.utils.panel_logging import (
|
||||
logToUser,
|
||||
)
|
||||
|
||||
FIELDS = ["project_streams", "project_layer_selection", "lat_lon"]
|
||||
|
||||
|
||||
def get_project_streams(plugin: SpeckleGIS, content: str = None):
|
||||
try:
|
||||
print("GET proj streams")
|
||||
project = plugin.project
|
||||
table = findOrCreateSpeckleTable(project)
|
||||
logToUser(table, level=0, func=inspect.stack()[0][3])
|
||||
|
||||
rows = arcpy.da.SearchCursor(table, "project_streams")
|
||||
saved_streams = []
|
||||
for x in rows:
|
||||
logToUser(x, level=0, func=inspect.stack()[0][3])
|
||||
saved_streams.append(x[0])
|
||||
|
||||
temp = []
|
||||
######### need to check whether saved streams are available (account reachable)
|
||||
if len(saved_streams) > 0:
|
||||
for url in saved_streams:
|
||||
if url == "":
|
||||
continue
|
||||
try:
|
||||
sw = StreamWrapper(url)
|
||||
try:
|
||||
stream = tryGetStream(sw, plugin.dataStorage)
|
||||
except SpeckleException as e:
|
||||
logToUser(e.message, level=2, func=inspect.stack()[0][3])
|
||||
stream = None
|
||||
# strId = stream.id # will cause exception if invalid
|
||||
temp.append((sw, stream))
|
||||
except SpeckleException as e:
|
||||
logToUser(e.message, level=2, func=inspect.stack()[0][3])
|
||||
# except GraphQLException as e:
|
||||
# logger.logToUser(e.message, Qgis.Warning)
|
||||
plugin.current_streams = temp
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
|
||||
|
||||
def set_project_streams(plugin: SpeckleGIS):
|
||||
try:
|
||||
print("SET proj streams")
|
||||
project = plugin.project
|
||||
table = findOrCreateSpeckleTable(project)
|
||||
print("SET proj streams 2")
|
||||
|
||||
value = [
|
||||
stream[0].stream_url for stream in plugin.current_streams
|
||||
] # ",".join()
|
||||
print(value)
|
||||
logToUser(value, level=0, func=inspect.stack()[0][3])
|
||||
|
||||
if table is not None:
|
||||
proj_layers = []
|
||||
lan_lot = ""
|
||||
with arcpy.da.UpdateCursor(table, FIELDS) as cursor:
|
||||
for row in cursor: # just one row
|
||||
if row[1] is not None and row[1] != "":
|
||||
proj_layers.append(row[1])
|
||||
if row[2] is not None and row[2] != "":
|
||||
lan_lot = row[2]
|
||||
cursor.deleteRow()
|
||||
del cursor
|
||||
if len(proj_layers) == 0:
|
||||
proj_layers.append("")
|
||||
if len(value) == 0:
|
||||
value.append("")
|
||||
|
||||
cursor = arcpy.da.InsertCursor(table, FIELDS)
|
||||
length = max(len(proj_layers), len(value))
|
||||
|
||||
for i in range(length):
|
||||
if i == 0:
|
||||
cursor.insertRow([value[i], proj_layers[i], lan_lot])
|
||||
else:
|
||||
try:
|
||||
cursor.insertRow([value[i], proj_layers[i], ""])
|
||||
except:
|
||||
if len(value) <= i:
|
||||
cursor.insertRow(["", proj_layers[i], ""])
|
||||
if len(proj_layers) <= i:
|
||||
cursor.insertRow([value[i], "", ""])
|
||||
del cursor
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
|
||||
|
||||
def get_project_layer_selection(plugin: SpeckleGIS):
|
||||
try:
|
||||
print("GET project layer selection from the table")
|
||||
project = plugin.project
|
||||
table = findOrCreateSpeckleTable(project)
|
||||
if table is None:
|
||||
return
|
||||
|
||||
rows = arcpy.da.SearchCursor(table, "project_layer_selection")
|
||||
saved_layers = []
|
||||
for x in rows:
|
||||
saved_layers.append(x[0])
|
||||
|
||||
temp = []
|
||||
proj_layers = getAllProjLayers(project)
|
||||
######### need to check whether saved streams are available (account reachable)
|
||||
if len(saved_layers) > 0:
|
||||
for layerPath in saved_layers:
|
||||
if layerPath == "":
|
||||
continue
|
||||
found = 0
|
||||
for layer in proj_layers:
|
||||
print(layer.dataSource)
|
||||
if layer.dataSource == layerPath:
|
||||
temp.append((layer.name, layer))
|
||||
found += 1
|
||||
break
|
||||
if found == 0:
|
||||
logToUser(
|
||||
f'Saved layer not found: "{layerPath}"',
|
||||
level=1,
|
||||
func=inspect.stack()[0][3],
|
||||
)
|
||||
plugin.current_layers = temp
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
|
||||
|
||||
def set_project_layer_selection(plugin: SpeckleGIS):
|
||||
try:
|
||||
print("SET project layer selection function")
|
||||
project = plugin.project
|
||||
value: List[str] = [
|
||||
layer[1].dataSource for layer in plugin.current_layers
|
||||
] # ",".join([layer[1].dataSource for layer in plugin.current_layers])
|
||||
print(value)
|
||||
|
||||
table = findOrCreateSpeckleTable(project)
|
||||
# print(table)
|
||||
if table is not None:
|
||||
lan_lot = ""
|
||||
proj_streams = []
|
||||
with arcpy.da.UpdateCursor(table, FIELDS) as cursor:
|
||||
for row in cursor: # just one row
|
||||
if row[0] is not None and row[0] != "":
|
||||
proj_streams.append(row[0])
|
||||
if row[2] is not None and row[2] != "":
|
||||
lan_lot = row[2]
|
||||
cursor.deleteRow()
|
||||
del cursor
|
||||
if len(proj_streams) == 0:
|
||||
proj_streams.append("")
|
||||
if len(value) == 0:
|
||||
value.append("")
|
||||
# print(proj_streams)
|
||||
|
||||
cursor = arcpy.da.InsertCursor(table, FIELDS)
|
||||
length = max(len(proj_streams), len(value))
|
||||
# print(length)
|
||||
for i in range(length):
|
||||
# print(i)
|
||||
if i == 0:
|
||||
cursor.insertRow([proj_streams[i], value[i], lan_lot])
|
||||
print(i)
|
||||
else:
|
||||
try:
|
||||
cursor.insertRow([proj_streams[i], value[i], ""])
|
||||
except:
|
||||
if len(proj_streams) <= i:
|
||||
cursor.insertRow(["", value[i], ""])
|
||||
if len(value) <= i:
|
||||
cursor.insertRow([proj_streams[i], "", ""])
|
||||
# print(i)
|
||||
del cursor
|
||||
|
||||
try:
|
||||
metrics.track(
|
||||
"Connector Action",
|
||||
plugin.active_account,
|
||||
{
|
||||
"name": "Save Layer Selection",
|
||||
"connector_version": str(plugin.version),
|
||||
},
|
||||
)
|
||||
except Exception as e:
|
||||
logToUser(
|
||||
e, level=2, func=inspect.stack()[0][3], plugin=plugin.dockwidget
|
||||
)
|
||||
|
||||
# print(table)
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
|
||||
print("SET project layer selection 2")
|
||||
|
||||
|
||||
def get_rotation(dataStorage):
|
||||
dataStorage.crs_rotation = 0
|
||||
return
|
||||
try:
|
||||
# get from saved project, set to local vars
|
||||
proj = dataStorage.project
|
||||
points = proj.readEntry("speckle-qgis", "crs_rotation", "")
|
||||
if points[1] and len(points[0]) > 0:
|
||||
vals: List[str] = points[0].replace(" ", "").split(";")[0]
|
||||
dataStorage.crs_rotation = float(vals)
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3])
|
||||
return
|
||||
|
||||
|
||||
def set_rotation(dataStorage, dockwidget=None):
|
||||
return
|
||||
try:
|
||||
# from widget (3 strings) to local vars AND memory (1 string)
|
||||
proj = dataStorage.project
|
||||
r = dataStorage.crs_rotation
|
||||
if dataStorage.crs_rotation is None:
|
||||
r = 0
|
||||
proj.writeEntry("speckle-qgis", "crs_rotation", r)
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logToUser("Lat, Lon values invalid: " + str(e), level=2)
|
||||
return False
|
||||
|
||||
def get_crs_offsets(dataStorage):
|
||||
dataStorage.crs_offset_x, dataStorage.crs_offset_y = (0,0)
|
||||
return
|
||||
try:
|
||||
# get from saved project, set to local vars
|
||||
proj = dataStorage.project
|
||||
points = proj.readEntry("speckle-qgis", "crs_offsets_rotation", "")
|
||||
if points[1] and len(points[0]) > 0:
|
||||
vals: List[str] = points[0].replace(" ", "").split(";")[:2]
|
||||
dataStorage.crs_offset_x, dataStorage.crs_offset_y = [
|
||||
float(i) for i in vals
|
||||
]
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3])
|
||||
return
|
||||
|
||||
|
||||
def set_crs_offsets(dataStorage, dockwidget=None):
|
||||
return
|
||||
try:
|
||||
# from widget (3 strings) to local vars AND memory (1 string)
|
||||
proj = dataStorage.project
|
||||
x = dataStorage.crs_offset_x
|
||||
y = dataStorage.crs_offset_y
|
||||
|
||||
if dataStorage.crs_offset_x is None or dataStorage.crs_offset_y is None:
|
||||
x = 0
|
||||
y = 0
|
||||
pt = str(x) + ";" + str(y)
|
||||
proj.writeEntry("speckle-qgis", "crs_offsets_rotation", pt)
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logToUser("Lat, Lon values invalid: " + str(e), level=2)
|
||||
return False
|
||||
|
||||
|
||||
def get_project_saved_layers(plugin):
|
||||
plugin.dataStorage.current_layers = []
|
||||
plugin.dataStorage.saved_layers = []
|
||||
return
|
||||
try:
|
||||
proj = plugin.project
|
||||
saved_layers = proj.readEntry("speckle-qgis", "project_layer_selection", "")
|
||||
temp = []
|
||||
# print(saved_layers)
|
||||
if saved_layers[1] and len(saved_layers[0]) != 0:
|
||||
for id in saved_layers[0].split(","):
|
||||
found = 0
|
||||
for layer in proj.mapLayers().values():
|
||||
if layer.id() == id:
|
||||
temp.append((layer, layer.name(), ""))
|
||||
found += 1
|
||||
break
|
||||
if found == 0:
|
||||
logToUser(
|
||||
f'Saved layer not found: "{id}"',
|
||||
level=1,
|
||||
func=inspect.stack()[0][3],
|
||||
)
|
||||
plugin.dataStorage.current_layers = temp.copy()
|
||||
plugin.dataStorage.saved_layers = temp.copy()
|
||||
# print(temp)
|
||||
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3], plugin=plugin.dockwidget)
|
||||
return
|
||||
|
||||
|
||||
def set_project_layer_selection(plugin):
|
||||
return
|
||||
try:
|
||||
proj = plugin.project
|
||||
# value = ",".join([x.id() for x in self.iface.layerTreeView().selectedLayers()]) #'points_qgis2_b22ed3d0_0ff9_40d2_97f2_bd17a350d698' <qgis._core.QgsVectorDataProvider object at 0x000002627D9D4790>
|
||||
value = ",".join([x[0].id() for x in plugin.dataStorage.current_layers])
|
||||
|
||||
# print(value)
|
||||
proj.writeEntry("speckle-qgis", "project_layer_selection", value)
|
||||
try:
|
||||
metrics.track(
|
||||
"Connector Action",
|
||||
plugin.dataStorage.active_account,
|
||||
{
|
||||
"name": "Save Layer Selection",
|
||||
"connector_version": str(plugin.dataStorage.plugin_version),
|
||||
},
|
||||
)
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3], plugin=plugin.dockwidget)
|
||||
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3], plugin=plugin.dockwidget)
|
||||
return
|
||||
|
||||
def get_survey_point(plugin: SpeckleGIS, content=None):
|
||||
try:
|
||||
print("get survey point")
|
||||
project = plugin.project
|
||||
table = findOrCreateSpeckleTable(project)
|
||||
if table is None:
|
||||
return
|
||||
|
||||
rows = arcpy.da.SearchCursor(table, "lat_lon")
|
||||
points = ""
|
||||
for x in rows:
|
||||
points = x[0]
|
||||
break
|
||||
|
||||
if points != "":
|
||||
vals: List[str] = points.replace(" ", "").split(";")[:2]
|
||||
plugin.lat, plugin.lon = [float(i) for i in vals]
|
||||
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
|
||||
|
||||
def set_survey_point(plugin: SpeckleGIS):
|
||||
|
||||
try:
|
||||
# from widget (2 strings) to local vars + update SR of the map
|
||||
print("SET survey point")
|
||||
|
||||
project = plugin.project
|
||||
vals = [
|
||||
str(plugin.dockwidget.surveyPointLat.text()),
|
||||
str(plugin.dockwidget.surveyPointLon.text()),
|
||||
]
|
||||
|
||||
plugin.lat, plugin.lon = [float(i.replace(" ", "")) for i in vals]
|
||||
|
||||
if (
|
||||
plugin.lat > 180
|
||||
or plugin.lat < -180
|
||||
or plugin.lon > 180
|
||||
or plugin.lon < -180
|
||||
):
|
||||
logToUser(
|
||||
"LAT LON values must be within (-180, 180). You can right-click on the canvas location to copy coordinates in WGS 84",
|
||||
level=1,
|
||||
plugin=self.dockwidget,
|
||||
)
|
||||
return True
|
||||
pt = str(plugin.lat) + ";" + str(plugin.lon)
|
||||
|
||||
table = findOrCreateSpeckleTable(project)
|
||||
if table is not None:
|
||||
with arcpy.da.UpdateCursor(table, ["lat_lon"]) as cursor:
|
||||
for row in cursor: # just one row
|
||||
cursor.updateRow([pt])
|
||||
break
|
||||
del cursor
|
||||
|
||||
setProjectReferenceSystem(plugin)
|
||||
|
||||
try:
|
||||
metrics.track(
|
||||
"Connector Action",
|
||||
plugin.active_account,
|
||||
{
|
||||
"name": "Set As Center Point",
|
||||
"connector_version": str(plugin.version),
|
||||
},
|
||||
)
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3], plugin=plugin.dockwidget)
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
plugin.dockwidget.surveyPointLat.setText(str(plugin.lat))
|
||||
plugin.dockwidget.surveyPointLon.setText(str(plugin.lon))
|
||||
logToUser(
|
||||
"Lat, Lon values invalid: " + str(e), level=2, func=inspect.stack()[0][3]
|
||||
)
|
||||
return False
|
||||
|
||||
|
||||
def setProjectReferenceSystem(plugin: SpeckleGIS):
|
||||
try:
|
||||
# save to project; create SR
|
||||
newCrsString = (
|
||||
"+proj=tmerc +ellps=WGS84 +datum=WGS84 +units=m +no_defs +lon_0="
|
||||
+ str(plugin.lon)
|
||||
+ " lat_0="
|
||||
+ str(plugin.lat)
|
||||
+ " +x_0=0 +y_0=0 +k_0=1"
|
||||
)
|
||||
newCrs = osr.SpatialReference()
|
||||
newCrs.ImportFromProj4(newCrsString)
|
||||
newCrs.MorphToESRI() # converts the WKT to an ESRI-compatible format
|
||||
|
||||
validate = True if len(newCrs.ExportToWkt()) > 10 else False
|
||||
|
||||
if validate:
|
||||
newProjSR = arcpy.SpatialReference()
|
||||
newProjSR.loadFromString(newCrs.ExportToWkt())
|
||||
|
||||
# source = osr.SpatialReference()
|
||||
# source.ImportFromWkt(plugin.project.activeMap.spatialReference.exportToString())
|
||||
# transform = osr.CoordinateTransformation(source, newCrs)
|
||||
|
||||
plugin.project.activeMap.spatialReference = newProjSR
|
||||
logToUser(
|
||||
"Custom project Spatial Reference successfully applied",
|
||||
level=0,
|
||||
func=inspect.stack()[0][3],
|
||||
)
|
||||
else:
|
||||
logToUser(
|
||||
"Custom Spatial Reference could not be created",
|
||||
level=1,
|
||||
func=inspect.stack()[0][3],
|
||||
)
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
return False
|
||||
|
||||
|
||||
def findOrCreateSpeckleTable(project: ArcGISProject) -> Union[str, None]:
|
||||
try:
|
||||
path = (
|
||||
arcpy.env.workspace
|
||||
) # project.filePath.replace("aprx","gdb") #"\\".join(project.filePath.split("\\")[:-1]) + "\\speckle_layers\\" #arcpy.env.workspace + "\\" #
|
||||
|
||||
if "speckle_gis" not in arcpy.ListTables():
|
||||
try:
|
||||
table = CreateTable(path, "speckle_gis")
|
||||
arcpy.management.AddField(table, "project_streams", "TEXT")
|
||||
arcpy.management.AddField(table, "project_layer_selection", "TEXT")
|
||||
arcpy.management.AddField(table, "lat_lon", "TEXT")
|
||||
|
||||
cursor = arcpy.da.InsertCursor(table, FIELDS)
|
||||
cursor.insertRow(["", "", ""])
|
||||
del cursor
|
||||
|
||||
except Exception as e:
|
||||
logToUser(
|
||||
"Error creating a table: " + str(e),
|
||||
level=1,
|
||||
func=inspect.stack()[0][3],
|
||||
)
|
||||
raise e
|
||||
else:
|
||||
# print("table already exists")
|
||||
# make sure fileds exist
|
||||
table = path + "\\speckle_gis"
|
||||
findOrCreateTableField(table, FIELDS[0])
|
||||
findOrCreateTableField(table, FIELDS[1])
|
||||
findOrCreateTableField(table, FIELDS[2])
|
||||
|
||||
findOrCreateRow(table, FIELDS)
|
||||
|
||||
return table
|
||||
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
return None
|
||||
|
||||
|
||||
def findOrCreateTableField(table: str, field: str):
|
||||
try:
|
||||
with arcpy.da.UpdateCursor(table, [field]) as cursor:
|
||||
value = None
|
||||
for row in cursor:
|
||||
value = row # tuple(val,)
|
||||
if value[0] is None:
|
||||
cursor.updateRow("")
|
||||
break # look at the 1st row only
|
||||
del cursor
|
||||
|
||||
# if value is None: # if there are no rows
|
||||
# cursor = arcpy.da.InsertCursor(table, [field])
|
||||
# cursor.insertRow([""])
|
||||
# del cursor
|
||||
|
||||
except: # if field doesn't exist
|
||||
arcpy.management.AddField(table, field, "TEXT")
|
||||
# cursor = arcpy.da.InsertCursor(table, [field] )
|
||||
# cursor.insertRow([""])
|
||||
del cursor
|
||||
|
||||
|
||||
def findOrCreateRow(table: str, fields: List[str]):
|
||||
try:
|
||||
# check if the row exists
|
||||
cursor = arcpy.da.SearchCursor(table, fields)
|
||||
k = -1
|
||||
for k, row in enumerate(cursor):
|
||||
# print(row)
|
||||
break
|
||||
del cursor
|
||||
|
||||
# if no rows
|
||||
if k == -1:
|
||||
cursor = arcpy.da.InsertCursor(table, fields)
|
||||
cursor.insertRow(["", "", ""])
|
||||
del cursor
|
||||
else:
|
||||
with arcpy.da.UpdateCursor(table, fields) as cursor:
|
||||
for row in cursor:
|
||||
if None in row:
|
||||
cursor.updateRow(["", "", ""])
|
||||
break # look at the 1st row only
|
||||
del cursor
|
||||
|
||||
except Exception as e:
|
||||
logToUser(str(e), level=2, func=inspect.stack()[0][3])
|
||||
@@ -0,0 +1,174 @@
|
||||
import inspect
|
||||
from typing import Union
|
||||
from specklepy.core.api.credentials import get_default_account
|
||||
from specklepy.core.api.wrapper import StreamWrapper
|
||||
from specklepy.core.api.models import Stream, Branch, Commit
|
||||
from specklepy.transports.server import ServerTransport
|
||||
from specklepy.core.api.client import SpeckleClient
|
||||
from specklepy.logging.exceptions import SpeckleException, GraphQLException
|
||||
|
||||
from speckle.speckle.utils.panel_logging import logToUser
|
||||
|
||||
|
||||
def tryGetClient(sw: StreamWrapper, dataStorage, write=False, dockwidget=None):
|
||||
# only streams with write access
|
||||
client = None
|
||||
savedRole = None
|
||||
savedStreamId = None
|
||||
for acc in dataStorage.accounts:
|
||||
# only check accounts on selected server
|
||||
if acc.serverInfo.url in sw.server_url:
|
||||
client = SpeckleClient(
|
||||
acc.serverInfo.url, acc.serverInfo.url.startswith("https")
|
||||
)
|
||||
try:
|
||||
client.authenticate_with_account(acc)
|
||||
if client.account.token is not None:
|
||||
break
|
||||
except SpeckleException as ex:
|
||||
if "already connected" in ex.message:
|
||||
logToUser(
|
||||
"Dependencies versioning error.\nClick here for details.",
|
||||
url="dependencies_error",
|
||||
level=2,
|
||||
plugin=dockwidget,
|
||||
)
|
||||
return None, None
|
||||
else:
|
||||
raise ex
|
||||
|
||||
# if token still not found
|
||||
if client is None or client.account.token is None:
|
||||
client = sw.get_client()
|
||||
|
||||
if client is not None:
|
||||
stream = client.stream.get(id=sw.stream_id, branch_limit=100, commit_limit=100)
|
||||
if isinstance(stream, Stream):
|
||||
if write is False:
|
||||
# try get stream, only read access needed
|
||||
return client, stream
|
||||
else:
|
||||
# check write access
|
||||
if stream.role is None:
|
||||
raise Exception(
|
||||
f"You don't have write access to the stream '{stream.id}'. You role is '{stream.role}'"
|
||||
)
|
||||
elif isinstance(stream.role, str) and "reviewer" in stream.role:
|
||||
raise Exception(
|
||||
f"You don't have write access to the stream '{savedStreamId}'. You role is '{savedRole}'"
|
||||
)
|
||||
else:
|
||||
return client, stream
|
||||
else:
|
||||
return None, None
|
||||
else:
|
||||
return None, None
|
||||
|
||||
|
||||
def tryGetStream(
|
||||
sw: StreamWrapper, dataStorage, write=False, dockwidget=None
|
||||
) -> Union[Stream, None]:
|
||||
try:
|
||||
# print("tryGetStream")
|
||||
client, stream = tryGetClient(sw, dataStorage, write, dockwidget)
|
||||
return stream
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3], plugin=dockwidget)
|
||||
return None
|
||||
|
||||
|
||||
def validateStream(stream: Stream, dockwidget) -> Union[Stream, None]:
|
||||
try:
|
||||
# dockwidget.dataStorage.check_for_accounts()
|
||||
# stream = tryGetStream(streamWrapper, dockwidget.dataStorage)
|
||||
|
||||
if isinstance(stream, SpeckleException):
|
||||
return None
|
||||
|
||||
if stream.branches is None:
|
||||
logToUser("Stream has no branches", level=1, plugin=dockwidget)
|
||||
return None
|
||||
return stream
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, plugin=dockwidget)
|
||||
return
|
||||
|
||||
|
||||
def validateBranch(
|
||||
stream: Stream, branchName: str, checkCommits: bool, dockwidget
|
||||
) -> Union[Branch, None]:
|
||||
try:
|
||||
branch = None
|
||||
if not stream.branches or not stream.branches.items:
|
||||
return None
|
||||
for b in stream.branches.items:
|
||||
if b.name == branchName:
|
||||
branch = b
|
||||
break
|
||||
if branch is None:
|
||||
logToUser("Failed to find a branch", level=2, plugin=dockwidget)
|
||||
return None
|
||||
if checkCommits == True:
|
||||
if branch.commits is None:
|
||||
logToUser("Failed to find a branch", level=2, plugin=dockwidget)
|
||||
return None
|
||||
if len(branch.commits.items) == 0:
|
||||
logToUser("Branch contains no commits", level=1, plugin=dockwidget)
|
||||
return None
|
||||
return branch
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, plugin=dockwidget)
|
||||
return
|
||||
|
||||
|
||||
def validateCommit(
|
||||
branch: Branch, commitId: str, dockwidget=None
|
||||
) -> Union[Commit, None]:
|
||||
try:
|
||||
commit = None
|
||||
try:
|
||||
commitId = commitId.split(" | ")[0]
|
||||
except:
|
||||
logToUser("Commit ID is not valid", level=2, plugin=dockwidget)
|
||||
|
||||
if commitId.startswith("Latest") and len(branch.commits.items) > 0:
|
||||
commit = branch.commits.items[0]
|
||||
else:
|
||||
for i in branch.commits.items:
|
||||
if i.id == commitId:
|
||||
commit = i
|
||||
break
|
||||
if commit is None:
|
||||
try:
|
||||
commit = branch.commits.items[0]
|
||||
logToUser(
|
||||
"Failed to find a commit. Receiving Latest",
|
||||
level=1,
|
||||
plugin=dockwidget,
|
||||
)
|
||||
except:
|
||||
logToUser("Failed to find a commit", level=2, plugin=dockwidget)
|
||||
return None
|
||||
return commit
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, plugin=dockwidget)
|
||||
return
|
||||
|
||||
|
||||
def validateTransport(
|
||||
client: SpeckleClient, streamId: str
|
||||
) -> Union[ServerTransport, None]:
|
||||
try:
|
||||
account = client.account
|
||||
if not account.token:
|
||||
account = get_default_account()
|
||||
transport = ServerTransport(client=client, account=account, stream_id=streamId)
|
||||
# print(transport)
|
||||
return transport
|
||||
except Exception as e:
|
||||
logToUser(
|
||||
"Make sure you have sufficient permissions: " + str(e),
|
||||
level=1,
|
||||
func=inspect.stack()[0][3],
|
||||
)
|
||||
return None
|
||||
@@ -1,111 +0,0 @@
|
||||
|
||||
from typing import Dict, List
|
||||
|
||||
from numpy import double
|
||||
from import UpdateSavedStreams
|
||||
from import UpdateSelectedStream
|
||||
|
||||
from specklepy_qt_ui.qt_ui.ConnectorBindings import ConnectorBindings
|
||||
from specklepy_qt_ui.qt_ui.Models.StreamState import StreamState
|
||||
|
||||
class QGISBindings(ConnectorBindings):
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def UpdateSavedStreams(self, streams: List[StreamState]):
|
||||
UpdateSavedStreams(streams)
|
||||
|
||||
def UpdateSelectedStream(self):
|
||||
UpdateSelectedStream()
|
||||
|
||||
def Open3DView(self, viewCoordinates: List[double], viewName: str = ""):
|
||||
'''Opens a 3D view in the host application
|
||||
viewCoordinates: First three values are the camera position, second three the target.
|
||||
viewName: Id or Name of the view'''
|
||||
return
|
||||
|
||||
def GetHostAppNameVersion(self)-> str:
|
||||
'''Gets the current host application name with version.'''
|
||||
return
|
||||
|
||||
def GetHostAppName(self) -> str:
|
||||
'''Gets the current host application name.'''
|
||||
return
|
||||
|
||||
def GetFileName(self) -> str:
|
||||
'''Gets the current opened/focused file's name.
|
||||
Make sure to check regarding unsaved/temporary files.'''
|
||||
return
|
||||
|
||||
def GetDocumentId(self) -> str:
|
||||
'''Gets the current opened/focused file's id.
|
||||
Generate one in here if the host app does not provide one.'''
|
||||
return
|
||||
|
||||
def GetDocumentLocation(self) -> str:
|
||||
'''Gets the current opened/focused file's locations.
|
||||
Make sure to check regarding unsaved/temporary files.'''
|
||||
return
|
||||
|
||||
def ResetDocument(self):
|
||||
'''Clears the document state of selections and previews'''
|
||||
return
|
||||
|
||||
def GetActiveViewName(self) -> str:
|
||||
'''Gets the current opened/focused file's view, if applicable.'''
|
||||
return
|
||||
|
||||
def GetStreamsInFile(self) -> List[StreamState]:
|
||||
'''Returns the serialised clients present in the current open host file.'''
|
||||
return
|
||||
|
||||
def WriteStreamsToFile(self, streams: List[StreamState]):
|
||||
'''Writes serialised clients to the current open host file.'''
|
||||
return
|
||||
|
||||
def AddNewStream(self, state: StreamState):
|
||||
'''Adds a new client and persists the info to the host file'''
|
||||
return
|
||||
|
||||
def PersistAndUpdateStreamInFile(self, state: StreamState):
|
||||
'''Persists the stream info to the host file; if maintaining a local in memory copy, make sure to update it too.'''
|
||||
return
|
||||
|
||||
def SendStream(self, state: StreamState, progress: ProgressViewModel) -> str:
|
||||
'''Pushes a client's stream'''
|
||||
return
|
||||
|
||||
def PreviewSend(self, state: StreamState, progress: ProgressViewModel):
|
||||
'''Previews a send operation'''
|
||||
|
||||
def ReceiveStream(self, state: StreamState, progress: ProgressViewModel) -> StreamState:
|
||||
'''Receives stream data from the server'''
|
||||
|
||||
def PreviewReceive(self, state: StreamState, progress: ProgressViewModel) -> StreamState:
|
||||
'''Previews a receive operation'''
|
||||
|
||||
def GetSelectedObjects(self) -> List[str]:
|
||||
'''Adds the current selection to the provided client.'''
|
||||
|
||||
def GetObjectsInView(self) -> List[str]:
|
||||
'''Gets a list of objects in the currently active view'''
|
||||
|
||||
def SelectClientObjects(self, objs: List[str], deselect: bool = False):
|
||||
'''clients should be able to select/preview/hover one way or another their associated objects'''
|
||||
|
||||
def GetSelectionFilters(self) -> List[ISelectionFilter]:
|
||||
'''Should return a list of filters that the application supports.'''
|
||||
|
||||
def GetReceiveModes(self) -> List[ReceiveMode]:
|
||||
'''Should return a list of receive modes that the application supports.'''
|
||||
|
||||
def GetCustomStreamMenuItems(self) -> List[MenuItem]:
|
||||
'''Return a list of custom menu items for stream cards.'''
|
||||
|
||||
def GetSettings(self) -> List[ISetting]:
|
||||
return
|
||||
|
||||
def ImportFamilyCommand(self, Mapping: Dict[str, List[MappingValue]] ) -> Dict[str, List[MappingValue]] :
|
||||
'''Imports family symbols in Revit'''
|
||||
return
|
||||
@@ -1,104 +0,0 @@
|
||||
import threading
|
||||
from specklepy_qt_ui.qt_ui.dockwidget_main import SpeckleQGISDialog as SpeckleQGISDialog_UI
|
||||
import specklepy_qt_ui.qt_ui
|
||||
|
||||
from speckle.ui_widgets.widget_transforms import MappingSendDialogQGIS
|
||||
|
||||
from PyQt5 import QtWidgets, uic
|
||||
import os
|
||||
import inspect
|
||||
from specklepy.logging.exceptions import (SpeckleException, GraphQLException)
|
||||
from specklepy.logging import metrics
|
||||
|
||||
|
||||
from PyQt5 import QtWidgets, uic
|
||||
from PyQt5.QtWidgets import QCheckBox, QListWidgetItem, QHBoxLayout, QWidget
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
|
||||
|
||||
from specklepy_qt_ui.qt_ui.widget_transforms import MappingSendDialog
|
||||
from specklepy_qt_ui.qt_ui.LogWidget import LogWidget
|
||||
from specklepy_qt_ui.qt_ui.utils.logger import logToUser
|
||||
from specklepy_qt_ui.qt_ui.DataStorage import DataStorage
|
||||
|
||||
FORM_CLASS, _ = uic.loadUiType(
|
||||
os.path.join(os.path.dirname(specklepy_qt_ui.qt_ui.__file__), os.path.join("ui", "dockwidget_main.ui") )
|
||||
)
|
||||
|
||||
class SpeckleQGISDialog(SpeckleQGISDialog_UI, FORM_CLASS):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
"""Constructor."""
|
||||
super(SpeckleQGISDialog_UI, self).__init__(parent)
|
||||
|
||||
self.setupUi(self)
|
||||
self.runAllSetup()
|
||||
|
||||
def createMappingDialog(self):
|
||||
|
||||
if self.mappingSendDialog is None:
|
||||
self.mappingSendDialog = MappingSendDialogQGIS(None)
|
||||
self.mappingSendDialog.dataStorage = self.dataStorage
|
||||
|
||||
self.mappingSendDialog.runSetup()
|
||||
|
||||
def completeStreamSection(self, plugin):
|
||||
try:
|
||||
self.streams_remove_button.clicked.connect( lambda: self.onStreamRemoveButtonClicked(plugin) )
|
||||
self.streamList.currentIndexChanged.connect( lambda: self.onActiveStreamChanged(plugin) )
|
||||
self.streamBranchDropdown.currentIndexChanged.connect( lambda: self.populateActiveCommitDropdown(plugin) )
|
||||
return
|
||||
except Exception as e:
|
||||
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
||||
return
|
||||
|
||||
def onStreamRemoveButtonClicked(self, plugin):
|
||||
try:
|
||||
from speckle.utils.project_vars import set_project_streams
|
||||
if not self: return
|
||||
index = self.streamList.currentIndex()
|
||||
if len(plugin.current_streams) > 0: plugin.current_streams.pop(index)
|
||||
plugin.active_stream = None
|
||||
self.streamBranchDropdown.clear()
|
||||
self.commitDropdown.clear()
|
||||
#self.streamIdField.setText("")
|
||||
|
||||
set_project_streams(plugin)
|
||||
self.populateProjectStreams(plugin)
|
||||
except Exception as e:
|
||||
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
||||
return
|
||||
|
||||
def populateProjectStreams(self, plugin):
|
||||
try:
|
||||
from speckle.utils.project_vars import set_project_streams
|
||||
if not self: return
|
||||
self.streamList.clear()
|
||||
for stream in plugin.current_streams:
|
||||
self.streamList.addItems(
|
||||
[f"Stream not accessible - {stream[0].stream_id}" if stream[1] is None or isinstance(stream[1], SpeckleException) else f"{stream[1].name}, {stream[1].id} | {stream[0].stream_url.split('/streams')[0].split('/projects')[0]}"]
|
||||
)
|
||||
if len(plugin.current_streams)==0: self.streamList.addItems([""])
|
||||
self.streamList.addItems(["Create New Stream"])
|
||||
set_project_streams(plugin)
|
||||
index = self.streamList.currentIndex()
|
||||
if index == -1: self.streams_remove_button.setEnabled(False)
|
||||
else: self.streams_remove_button.setEnabled(True)
|
||||
|
||||
if len(plugin.current_streams)>0: plugin.active_stream = plugin.current_streams[0]
|
||||
except Exception as e:
|
||||
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
|
||||
return
|
||||
|
||||
def cancelOperations(self):
|
||||
#print("____cancelOperations______")
|
||||
for t in threading.enumerate():
|
||||
#print(t.name)
|
||||
if 'speckle_' in t.name:
|
||||
#print(f"thread to kill: {t}")
|
||||
t.kill()
|
||||
t.join()
|
||||
# not printed if same thread
|
||||
#print("Remaining threads: ")
|
||||
#print(threading.enumerate())
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
import inspect
|
||||
import os
|
||||
import threading
|
||||
from PyQt5 import QtWidgets, uic
|
||||
from specklepy.logging.exceptions import SpeckleException
|
||||
|
||||
from speckle.speckle.utils.panel_logging import logToUser
|
||||
import speckle.specklepy_qt_ui.qt_ui
|
||||
from speckle.specklepy_qt_ui.qt_ui.mainWindow import (
|
||||
SpeckleGISDialog as SpeckleGISDialog_UI,
|
||||
)
|
||||
|
||||
ui_file_path = os.path.join(
|
||||
os.path.dirname(speckle.specklepy_qt_ui.qt_ui.__file__),
|
||||
os.path.join("ui", "mainWindow_main.ui"),
|
||||
)
|
||||
|
||||
|
||||
class SpeckleGISDialog(SpeckleGISDialog_UI):
|
||||
def __init__(self, parent=None):
|
||||
"""Constructor."""
|
||||
super(SpeckleGISDialog, self).__init__(
|
||||
parent
|
||||
) # , QtCore.Qt.WindowStaysOnTopHint)
|
||||
uic.loadUi(ui_file_path, self) # Load the .ui file
|
||||
# self.show()
|
||||
self.runAllSetup()
|
||||
|
||||
def populateProjectStreams(self, plugin):
|
||||
try:
|
||||
from speckle.speckle.utils.project_vars import set_project_streams
|
||||
|
||||
if not self:
|
||||
return
|
||||
self.streamList.clear()
|
||||
for stream in plugin.current_streams:
|
||||
self.streamList.addItems(
|
||||
[
|
||||
(
|
||||
f"Stream not accessible - {stream[0].stream_id}"
|
||||
if stream[1] is None
|
||||
or isinstance(stream[1], SpeckleException)
|
||||
else f"{stream[1].name}, {stream[1].id} | {stream[0].stream_url.split('/streams')[0].split('/projects')[0]}"
|
||||
)
|
||||
]
|
||||
)
|
||||
if len(plugin.current_streams) == 0:
|
||||
self.streamList.addItems([""])
|
||||
self.streamList.addItems(["Create New Stream"])
|
||||
set_project_streams(plugin)
|
||||
index = self.streamList.currentIndex()
|
||||
if index == -1:
|
||||
self.streams_remove_button.setEnabled(False)
|
||||
else:
|
||||
self.streams_remove_button.setEnabled(True)
|
||||
|
||||
if len(plugin.current_streams) > 0:
|
||||
plugin.active_stream = plugin.current_streams[0]
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3], plugin=self)
|
||||
return
|
||||
|
||||
def completeStreamSection(self, plugin):
|
||||
try:
|
||||
self.streams_remove_button.clicked.connect(
|
||||
lambda: self.onStreamRemoveButtonClicked(plugin)
|
||||
)
|
||||
self.streamList.currentIndexChanged.connect(
|
||||
lambda: self.onActiveStreamChanged(plugin)
|
||||
)
|
||||
self.streamBranchDropdown.currentIndexChanged.connect(
|
||||
lambda: self.populateActiveCommitDropdown(plugin)
|
||||
)
|
||||
return
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3], plugin=self)
|
||||
return
|
||||
|
||||
def onStreamRemoveButtonClicked(self, plugin):
|
||||
try:
|
||||
from speckle.speckle.utils.project_vars import set_project_streams
|
||||
|
||||
if not self:
|
||||
return
|
||||
index = self.streamList.currentIndex()
|
||||
if len(plugin.current_streams) > 0:
|
||||
plugin.current_streams.pop(index)
|
||||
plugin.active_stream = None
|
||||
self.streamBranchDropdown.clear()
|
||||
self.commitDropdown.clear()
|
||||
|
||||
set_project_streams(plugin)
|
||||
self.populateProjectStreams(plugin)
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3], plugin=self)
|
||||
return
|
||||
|
||||
def populateProjectStreams(self, plugin):
|
||||
try:
|
||||
from speckle.speckle.utils.project_vars import set_project_streams
|
||||
|
||||
if not self:
|
||||
return
|
||||
self.streamList.clear()
|
||||
for stream in plugin.current_streams:
|
||||
self.streamList.addItems(
|
||||
[
|
||||
(
|
||||
f"Stream not accessible - {stream[0].stream_id}"
|
||||
if stream[1] is None
|
||||
or isinstance(stream[1], SpeckleException)
|
||||
else f"{stream[1].name}, {stream[1].id} | {stream[0].stream_url.split('/streams')[0].split('/projects')[0]}"
|
||||
)
|
||||
]
|
||||
)
|
||||
if len(plugin.current_streams) == 0:
|
||||
self.streamList.addItems([""])
|
||||
self.streamList.addItems(["Create New Stream"])
|
||||
set_project_streams(plugin)
|
||||
index = self.streamList.currentIndex()
|
||||
if index == -1:
|
||||
self.streams_remove_button.setEnabled(False)
|
||||
else:
|
||||
self.streams_remove_button.setEnabled(True)
|
||||
|
||||
if len(plugin.current_streams) > 0:
|
||||
plugin.active_stream = plugin.current_streams[0]
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3], plugin=self)
|
||||
return
|
||||
|
||||
def cancelOperations(self):
|
||||
for t in threading.enumerate():
|
||||
if "speckle_" in t.name:
|
||||
t.kill()
|
||||
t.join()
|
||||
@@ -1,404 +0,0 @@
|
||||
import inspect
|
||||
import os
|
||||
from typing import Any, List, Tuple, Union
|
||||
from speckle.converter.layers import getAllLayers
|
||||
from speckle.converter.layers.utils import getElevationLayer, getLayerGeomType
|
||||
from specklepy_qt_ui.qt_ui.widget_transforms import MappingSendDialog
|
||||
from specklepy_qt_ui.qt_ui.utils.logger import displayUserMsg
|
||||
from specklepy_qt_ui.qt_ui.DataStorage import DataStorage
|
||||
|
||||
from speckle.utils.panel_logging import logToUser
|
||||
|
||||
from qgis.core import QgsVectorLayer, QgsRasterLayer, QgsIconUtils
|
||||
|
||||
from PyQt5 import QtWidgets, uic, QtCore
|
||||
from PyQt5.QtWidgets import QListWidgetItem
|
||||
|
||||
from specklepy.logging import metrics
|
||||
from osgeo import gdal
|
||||
import webbrowser
|
||||
import specklepy_qt_ui.qt_ui
|
||||
|
||||
FORM_CLASS, _ = uic.loadUiType(
|
||||
os.path.join(
|
||||
os.path.join(
|
||||
os.path.dirname(specklepy_qt_ui.qt_ui.__file__), "ui", "transforms.ui"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class MappingSendDialogQGIS(MappingSendDialog, FORM_CLASS):
|
||||
def __init__(self, parent=None):
|
||||
super(MappingSendDialog, self).__init__(parent, QtCore.Qt.WindowStaysOnTopHint)
|
||||
self.setupUi(self)
|
||||
self.runAllSetup()
|
||||
|
||||
def runSetup(self):
|
||||
self.attr_label.setEnabled(False)
|
||||
self.attrDropdown.setEnabled(False)
|
||||
self.dialog_button.setText("Apply")
|
||||
|
||||
self.populateTransforms()
|
||||
self.populateLayersByTransform()
|
||||
self.populateSavedTransforms(self.dataStorage)
|
||||
self.populateSavedElevationLayer(self.dataStorage)
|
||||
|
||||
# self.elevationLayerDropdown.currentIndexChanged.connect(self.saveElevationLayer)
|
||||
|
||||
def populateSavedTransforms(
|
||||
self, dataStorage
|
||||
): # , savedTransforms: Union[List, None] = None, getLayer: Union[str, None] = None, getTransform: Union[str, None] = None):
|
||||
if dataStorage is not None:
|
||||
self.dataStorage = dataStorage # making sure lists are synced
|
||||
self.transformationsList.clear()
|
||||
vals = self.dataStorage.savedTransforms
|
||||
all_l_names = [l.name() for l in self.dataStorage.all_layers]
|
||||
|
||||
for item in vals:
|
||||
layer_name = item.split(" -> ")[0].split(" ('")[0]
|
||||
transform_name = item.split(" -> ")[1]
|
||||
|
||||
layer = None
|
||||
for l in self.dataStorage.all_layers:
|
||||
if layer_name == l.name():
|
||||
layer = l
|
||||
if layer is None:
|
||||
logToUser(
|
||||
f"Layer '{layer_name}' not found in the project.\nTransformation is removed.",
|
||||
level=2,
|
||||
)
|
||||
self.dataStorage.savedTransforms.remove(item)
|
||||
else:
|
||||
if transform_name not in self.dataStorage.transformsCatalog:
|
||||
displayUserMsg(
|
||||
f"Saved transformation '{transform_name}' is not valid.\nTransformation is removed.",
|
||||
level=1,
|
||||
)
|
||||
self.dataStorage.savedTransforms.remove(item)
|
||||
elif all_l_names.count(layer.name()) > 1:
|
||||
displayUserMsg(
|
||||
f"Layer name '{layer.name()}' is used for more than 1 layer in the project.\nTransformation is removed.",
|
||||
level=1,
|
||||
)
|
||||
self.dataStorage.savedTransforms.remove(item)
|
||||
else:
|
||||
listItem = QListWidgetItem(item)
|
||||
icon = QgsIconUtils().iconForLayer(layer)
|
||||
listItem.setIcon(icon)
|
||||
|
||||
self.transformationsList.addItem(listItem)
|
||||
|
||||
def onAddTransform(self):
|
||||
from speckle.utils.project_vars import set_transformations
|
||||
|
||||
root = self.dataStorage.project.layerTreeRoot()
|
||||
self.dataStorage.all_layers = getAllLayers(root)
|
||||
|
||||
if (
|
||||
len(self.layerDropdown.currentText()) > 1
|
||||
and len(self.transformDropdown.currentText()) > 1
|
||||
):
|
||||
listItem = (
|
||||
str(self.layerDropdown.currentText())
|
||||
+ " -> "
|
||||
+ str(self.transformDropdown.currentText())
|
||||
)
|
||||
layer_name = listItem.split(" -> ")[0].split(" ('")[0]
|
||||
transform_name = listItem.split(" -> ")[1].lower()
|
||||
|
||||
exists = 0
|
||||
for record in self.dataStorage.savedTransforms:
|
||||
current_layer_name = record.split(" -> ")[0].split(" ('")[0]
|
||||
current_transf_name = record.split(" -> ")[1].lower()
|
||||
if layer_name == current_layer_name: # in layers
|
||||
exists += 1
|
||||
displayUserMsg(
|
||||
"Selected layer already has a transformation applied", level=1
|
||||
)
|
||||
break
|
||||
|
||||
if exists == 0:
|
||||
layer = None
|
||||
for l in self.dataStorage.all_layers:
|
||||
if layer_name == l.name():
|
||||
layer = l
|
||||
if layer is not None:
|
||||
if (
|
||||
"attribute" in transform_name
|
||||
and self.attrDropdown.currentText() != ""
|
||||
):
|
||||
listItem = (
|
||||
str(self.layerDropdown.currentText())
|
||||
+ " ('"
|
||||
+ str(self.attrDropdown.currentText())
|
||||
+ "') -> "
|
||||
+ str(self.transformDropdown.currentText())
|
||||
)
|
||||
|
||||
self.dataStorage.savedTransforms.append(listItem)
|
||||
self.populateSavedTransforms(self.dataStorage)
|
||||
|
||||
try:
|
||||
metrics.track(
|
||||
"Connector Action",
|
||||
self.dataStorage.active_account,
|
||||
{
|
||||
"name": "Transformation on Send Add",
|
||||
"Transformation": listItem.split(" -> ")[1],
|
||||
"connector_version": str(
|
||||
self.dataStorage.plugin_version
|
||||
),
|
||||
},
|
||||
)
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3])
|
||||
|
||||
set_transformations(self.dataStorage)
|
||||
|
||||
def onRemoveTransform(self):
|
||||
from speckle.utils.project_vars import set_transformations
|
||||
|
||||
if self.transformationsList.currentItem() is not None:
|
||||
listItem = self.transformationsList.currentItem().text()
|
||||
# print(listItem)
|
||||
|
||||
if listItem in self.dataStorage.savedTransforms:
|
||||
self.dataStorage.savedTransforms.remove(listItem)
|
||||
|
||||
try:
|
||||
metrics.track(
|
||||
"Connector Action",
|
||||
self.dataStorage.active_account,
|
||||
{
|
||||
"name": "Transformation on Send Remove",
|
||||
"Transformation": listItem.split(" -> ")[1],
|
||||
"connector_version": str(self.dataStorage.plugin_version),
|
||||
},
|
||||
)
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3])
|
||||
|
||||
self.populateSavedTransforms(self.dataStorage)
|
||||
set_transformations(self.dataStorage)
|
||||
|
||||
def onOkClicked(self):
|
||||
try:
|
||||
self.saveElevationLayer()
|
||||
self.close()
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3])
|
||||
return
|
||||
|
||||
def populateLayers(self):
|
||||
try:
|
||||
self.layerDropdown.clear()
|
||||
root = self.dataStorage.project.layerTreeRoot()
|
||||
self.dataStorage.all_layers = getAllLayers(root)
|
||||
for i, layer in enumerate(self.dataStorage.all_layers):
|
||||
listItem = layer.name()
|
||||
self.layerDropdown.addItem(listItem)
|
||||
icon = QgsIconUtils().iconForLayer(layer)
|
||||
self.layerDropdown.setItemIcon(i, icon)
|
||||
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3])
|
||||
return
|
||||
|
||||
def populateLayersByTransform(self):
|
||||
try:
|
||||
self.layerDropdown.clear()
|
||||
root = self.dataStorage.project.layerTreeRoot()
|
||||
self.dataStorage.all_layers = getAllLayers(root)
|
||||
|
||||
transform = str(self.transformDropdown.currentText())
|
||||
layers_dropdown = []
|
||||
|
||||
for i, layer in enumerate(self.dataStorage.all_layers):
|
||||
listItem = None
|
||||
if "extrude" in transform.lower():
|
||||
if isinstance(layer, QgsVectorLayer):
|
||||
geom_type = getLayerGeomType(layer)
|
||||
if "polygon" in geom_type.lower():
|
||||
listItem = layer.name()
|
||||
|
||||
elif "elevation" in transform.lower():
|
||||
if isinstance(layer, QgsRasterLayer):
|
||||
# avoiding tiling layers
|
||||
ds = gdal.Open(layer.source(), gdal.GA_ReadOnly)
|
||||
if ds is None:
|
||||
continue
|
||||
|
||||
# for satellites
|
||||
if "texture" in transform.lower():
|
||||
listItem = layer.name()
|
||||
# for elevation to mesh
|
||||
elif "mesh" in transform.lower():
|
||||
try:
|
||||
if layer.bandCount() == 1:
|
||||
listItem = layer.name()
|
||||
except:
|
||||
pass
|
||||
|
||||
if listItem is not None:
|
||||
layers_dropdown.append(listItem)
|
||||
self.layerDropdown.addItem(listItem)
|
||||
icon = QgsIconUtils().iconForLayer(layer)
|
||||
self.layerDropdown.setItemIcon(len(layers_dropdown) - 1, icon)
|
||||
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3])
|
||||
return
|
||||
|
||||
def populateAttributesByLayer(self):
|
||||
try:
|
||||
self.attrDropdown.clear()
|
||||
root = self.dataStorage.project.layerTreeRoot()
|
||||
self.dataStorage.all_layers = getAllLayers(root)
|
||||
|
||||
layer_name = str(self.layerDropdown.currentText())
|
||||
transform_name = self.transformDropdown.currentText()
|
||||
layerForAttributes = None
|
||||
for i, layer in enumerate(self.dataStorage.all_layers):
|
||||
if layer_name == layer.name():
|
||||
if isinstance(layer, QgsVectorLayer):
|
||||
geom_type = getLayerGeomType(layer)
|
||||
if "polygon" in geom_type.lower():
|
||||
layerForAttributes = layer
|
||||
break
|
||||
|
||||
if layerForAttributes is not None and "attribute" in transform_name:
|
||||
self.attr_label.setEnabled(True)
|
||||
self.attrDropdown.setEnabled(True)
|
||||
|
||||
if "ignore" not in transform_name:
|
||||
self.attrDropdown.addItem("Random height")
|
||||
|
||||
for field in layerForAttributes.fields():
|
||||
field_type = field.type()
|
||||
if field_type in [2, 6, 10]:
|
||||
self.attrDropdown.addItem(str(field.name()))
|
||||
else:
|
||||
self.attr_label.setEnabled(False)
|
||||
self.attrDropdown.setEnabled(False)
|
||||
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3])
|
||||
return
|
||||
|
||||
def populateTransforms(self):
|
||||
try:
|
||||
self.transformDropdown.clear()
|
||||
for item in self.dataStorage.transformsCatalog:
|
||||
self.transformDropdown.addItem(item)
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3])
|
||||
return
|
||||
|
||||
def populateSavedElevationLayer(
|
||||
self, dataStorage
|
||||
): # , savedTransforms: Union[List, None] = None, getLayer: Union[str, None] = None, getTransform: Union[str, None] = None):
|
||||
try:
|
||||
if dataStorage is not None:
|
||||
self.dataStorage = dataStorage # making sure lists are synced
|
||||
elevationLayer = getElevationLayer(self.dataStorage)
|
||||
|
||||
self.elevationLayerDropdown.clear()
|
||||
root = self.dataStorage.project.layerTreeRoot()
|
||||
self.dataStorage.all_layers = getAllLayers(root)
|
||||
|
||||
self.elevationLayerDropdown.addItem("")
|
||||
|
||||
setAsindex = 0
|
||||
countRaster = 1
|
||||
for i, layer in enumerate(self.dataStorage.all_layers):
|
||||
if isinstance(layer, QgsRasterLayer):
|
||||
# avoiding tiling layers
|
||||
ds = gdal.Open(layer.source(), gdal.GA_ReadOnly)
|
||||
if ds is None:
|
||||
continue
|
||||
elif layer.bandCount() != 1:
|
||||
continue
|
||||
|
||||
listItem = layer.name()
|
||||
self.elevationLayerDropdown.addItem(listItem)
|
||||
icon = QgsIconUtils().iconForLayer(layer)
|
||||
self.elevationLayerDropdown.setItemIcon(countRaster, icon)
|
||||
|
||||
if elevationLayer is not None:
|
||||
if listItem == elevationLayer.name():
|
||||
setAsindex = countRaster
|
||||
countRaster += 1
|
||||
self.elevationLayerDropdown.setCurrentIndex(setAsindex)
|
||||
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3])
|
||||
return
|
||||
|
||||
def saveElevationLayer(self):
|
||||
# print("saveElevationLayer")
|
||||
from speckle.utils.project_vars import set_elevationLayer
|
||||
|
||||
root = self.dataStorage.project.layerTreeRoot()
|
||||
layer = None
|
||||
|
||||
if self.dataStorage is None:
|
||||
return
|
||||
|
||||
layerName = str(self.elevationLayerDropdown.currentText())
|
||||
try:
|
||||
if self.dataStorage.elevationLayer.name() == layerName:
|
||||
return
|
||||
except:
|
||||
pass
|
||||
|
||||
if len(layerName) < 1:
|
||||
layer = None
|
||||
else:
|
||||
self.dataStorage.all_layers = getAllLayers(root)
|
||||
all_l_names = [l.name() for l in self.dataStorage.all_layers]
|
||||
# print(all_l_names)
|
||||
|
||||
for l in self.dataStorage.all_layers:
|
||||
if layerName == l.name():
|
||||
layer = l
|
||||
try:
|
||||
# print(layerName)
|
||||
if all_l_names.count(layer.name()) > 1:
|
||||
displayUserMsg(
|
||||
f"Layer name '{layer.name()}' is used for more than 1 layer in the project",
|
||||
level=1,
|
||||
)
|
||||
layer = None
|
||||
break
|
||||
else:
|
||||
self.dataStorage.elevationLayer = layer
|
||||
set_elevationLayer(self.dataStorage)
|
||||
logToUser(
|
||||
f"Elevation layer '{layerName}' successfully set",
|
||||
level=0,
|
||||
)
|
||||
break
|
||||
except:
|
||||
displayUserMsg(
|
||||
f"Layer '{layer.name()}' is not found in the project",
|
||||
level=1,
|
||||
)
|
||||
layer = None
|
||||
break
|
||||
|
||||
try:
|
||||
metrics.track(
|
||||
"Connector Action",
|
||||
self.dataStorage.active_account,
|
||||
{
|
||||
"name": "Add transformation on Send",
|
||||
"Transformation": "Set Layer as Elevation",
|
||||
"connector_version": str(self.dataStorage.plugin_version),
|
||||
},
|
||||
)
|
||||
except Exception as e:
|
||||
logToUser(e, level=2, func=inspect.stack()[0][3])
|
||||
|
||||
def onMoreInfo(self):
|
||||
webbrowser.open("https://speckle.guide/user/qgis.html#transformations")
|
||||