Compare commits

...

12 Commits

Author SHA1 Message Date
KatKatKateryna e409e6d578 Merge pull request #22 from specklesystems/kate/2.9_debugging
Kate/2.9 debugging
2022-10-25 18:30:24 +01:00
KatKatKateryna 98cfc35cbc add conflicted file 2022-10-25 19:29:58 +02:00
KatKatKateryna 1ba8aaaa15 Revert "add conflicted file"
This reverts commit 1f95fbd169.
2022-10-25 19:29:43 +02:00
KatKatKateryna 1f95fbd169 add conflicted file 2022-10-25 19:26:12 +02:00
KatKatKateryna 42f9f8c815 2.9.3; don't duplicate layers of Refresh 2022-10-25 19:10:20 +02:00
KatKatKateryna 019f67ffbc 2.9.2 naming 2022-10-25 18:50:16 +02:00
KatKatKateryna 3f6a21f65e Toolbox naming 2022-10-25 18:03:00 +02:00
KatKatKateryna 3ce685f77a exception for unrefresed UI; defining types properly 2022-10-25 18:00:17 +02:00
KatKatKateryna be8996ebaa file reading failproof; move plugin to PYT, raster mesh sent correctly 2022-10-25 17:49:24 +02:00
KatKatKateryna 03d8a20a44 patch to update whl version; installer to update specklepy 2022-10-25 16:36:03 +02:00
KatKatKateryna 057cbb8cc5 Raster flipped; extra precautions writing txt file; installer instructions updated 2022-10-25 15:38:12 +02:00
KatKatKateryna a68fdbc999 whl package fix, added missing plugin folder 2022-10-25 14:13:13 +02:00
14 changed files with 874 additions and 47 deletions
+31 -2
View File
@@ -4,17 +4,46 @@ import sys
def patch_installer(tag):
"""Patches the installer with the correct connector version and specklepy version"""
iss_file = "speckle-sharp-ci-tools/arcgis.iss"
setup_whl_file = "setup.py"
toolbox_install_file = "speckle_arcgis_installer/toolbox_install.py"
#py_tag = get_specklepy_version()
with open(iss_file, "r") as file:
lines = file.readlines()
lines.insert(12, f'#define AppVersion "{tag.split("-")[0]}"\n')
lines.insert(13, f'#define AppInfoVersion "{tag}"\n')
if "#define AppVersion" in lines[12]: lines[12] = f'#define AppVersion "{tag.split("-")[0]}"\n'
else: lines.insert(12, f'#define AppVersion "{tag.split("-")[0]}"\n')
if "#define AppInfoVersion" in lines[13]: lines[13] = f'#define AppInfoVersion "{tag}"\n'
else: lines.insert(13, f'#define AppInfoVersion "{tag}"\n')
with open(iss_file, "w") as file:
file.writelines(lines)
print(f"Patched installer with connector v{tag} and specklepy ")
file.close()
with open(setup_whl_file, "r") as file:
lines = file.readlines()
if "version=" in lines[17]: lines[17] = f'\t\t\tversion="{tag.split("-")[0]}",\n'
else: lines.insert(17, f'\t\t\tversion="{tag.split("-")[0]}",\n')
with open(setup_whl_file, "w") as file:
file.writelines(lines)
print(f"Patched whl setup with connector v{tag} and specklepy ")
file.close()
with open(toolbox_install_file, "r") as file:
lines = file.readlines()
for i, line in enumerate(lines):
if "-py3-none-any.whl" in line:
p1 = line.split("-py3-none-any.whl")[0].split("-")[0]
p2 = f'{tag.split("-")[0]}'
p3 = line.split("-py3-none-any.whl")[1]
lines[i] = p1+"-"+p2+"-py3-none-any.whl"+p3
with open(toolbox_install_file, "w") as file:
file.writelines(lines)
print(f"Patched toolbox_installer with connector v{tag} and specklepy ")
file.close()
def main():
if len(sys.argv) < 2:
+5 -4
View File
@@ -14,20 +14,21 @@ def read(fname):
return open(os.path.join(os.path.dirname(__file__), fname)).read()
setup(name='speckle_toolbox',
version='0.1',
author='SpeckleSystems',
version="2.9.3",
description=("Example for extending geoprocessing through Python modules"),
long_description=read('Readme.md'),
python_requires='~=3.3',
setup_requires=['wheel'],
packages=['speckle_toolbox'],
package_data={'speckle_toolbox':['esri/toolboxes/*',
package_data={'speckle_toolbox':[
'esri/arcpy/*',
'esri/help/gp/*', 'esri/help/gp/toolboxes/*', 'esri/help/gp/messages/*',
'esri/toolboxes/*','esri/toolboxes/speckle/*',
'esri/toolboxes/speckle/converter/*', 'esri/toolboxes/speckle/converter/geometry/*', 'esri/toolboxes/speckle/converter/layers/*',
'esri/toolboxes/speckle/plugin_utils/*']
'esri/toolboxes/speckle/plugin_utils/*',
'esri/toolboxes/speckle/ui/*']
},
setup_requires=['wheel'],
)
# then to install in ArcGIS:
Binary file not shown.
@@ -1,13 +1,13 @@
# MANUAL INSTALLATION:
# 1. enter correct path to Python exe of your new environemnt in line 10
# 2. enter the location of 'manual_toolbox_install.py' in the following command and run this command in ArcGIS Python console (View -> Python Window)
# import sysconfig; import subprocess; x = sysconfig.get_paths()['data'] + r"\python.exe"; subprocess.run((x, 'C:\\...\\manual_toolbox_install.py'), capture_output=True, text=True, shell=True, timeout=1000 )
# import sysconfig; import subprocess; x = sysconfig.get_paths()['data'] + r"\python.exe"; subprocess.run((x, 'C:\\Users\\Kateryna\\Documents\\00_Speckle\\GitHub\\speckle-arcgis\\speckle_arcgis_installer\\manual_toolbox_install.py'), capture_output=True, text=True, shell=True, timeout=1000 )
# then restart
from subprocess_call import subprocess_call
import os
pythonPath = "C:\\ ...\\custom_environment_name\\python.exe"
pythonPath = "C:\\ Users\\Kateryna\\AppData\\Local\\ESRI\\conda\\envs\\arcgispro-py3-speckle\\python.exe"
def installToolbox(newExec: str):
print("Installing Speckle Toolbox")
+1 -1
View File
@@ -14,7 +14,7 @@ def subprocess_call(*args, **kwargs):
startupinfo.dwFlags = subprocess.CREATE_NEW_CONSOLE | subprocess.STARTF_USESHOWWINDOW
startupinfo.wShowWindow = subprocess.SW_HIDE
kwargs['startupinfo'] = startupinfo
print("start")
#print("start")
#print(*args)
try:
# if manually: cmd.exe -> conda activate [env folder] -> pip install specklepy
+34 -12
View File
@@ -6,9 +6,10 @@ pythonPath = os.getenv('APPDATA').replace("\\Roaming","") + r"\Local\ESRI\conda\
def installToolbox(newExec: str):
print("Installing Speckle Toolbox")
whl_file = os.path.join(os.path.dirname(__file__), "speckle_toolbox-0.1-py3-none-any.whl" )
whl_file = os.path.join(os.path.dirname(__file__), "speckle_toolbox-2.9.3-py3-none-any.whl" )
print(whl_file)
subprocess_call([newExec, '-m','pip','install','--upgrade', '--force-reinstall', whl_file])
# to uninstall: cmd.exe "C:\\Users\\username\\AppData\\Local\\ESRI\\conda\\envs\\arcgispro-py3-speckle\\python.exe" -m pip uninstall C:\\Users\\username\\Downloads\\speckle-arcgis\\foo-0.1-py3-none-any.whl
# to uninstall: cmd.exe "C:\\Users\\username\\AppData\\Local\\ESRI\\conda\\envs\\arcgispro-2.9.3-py3-none-any.whl
return
def installDependencies(pythonExec: str):
@@ -30,19 +31,9 @@ def installDependencies(pythonExec: str):
except Exception as e:
subprocess_call([ pythonExec, "-m", "pip", "install", f"{pkgName}=={pkgVersion}"])
pkgVersion = "1.10.11"
pkgName = "panda3d"
try:
import panda3d
except Exception as e:
print("panda3d not installed")
subprocess_call( [pythonExec, "-m", "pip", "install", f"{pkgName}=={pkgVersion}"])
# Check if specklpy needs updating
try:
print(f"Attempting to update specklepy to {pkgVersion}")
# pip.main(['install', "specklepy==2.7.4"])
result = subprocess_call(
[
pythonExec,
@@ -59,6 +50,37 @@ def installDependencies(pythonExec: str):
else:
return False
except Exception as e:
print(e)
print(e.with_traceback)
pkgVersion = "1.10.11"
pkgName = "panda3d"
try:
import panda3d
except Exception as e:
print("panda3d not installed")
subprocess_call( [pythonExec, "-m", "pip", "install", f"{pkgName}=={pkgVersion}"])
# Check if specklpy needs updating
try:
print(f"Attempting to update panda3d to {pkgVersion}")
result = subprocess_call(
[
pythonExec,
"-m",
"pip",
"install",
"--upgrade",
f"{pkgName}=={pkgVersion}",
]
)
if result == True:
print("dependencies upgraded")
return True
else:
return False
except Exception as e:
print(e)
print(e.with_traceback)
+764 -1
View File
@@ -1 +1,764 @@
from speckle.speckle_arcgis import *
#from speckle.speckle_arcgis import *
# -*- coding: utf-8 -*-
from typing import Any, Callable, List, Optional, Tuple
#r'''
from collections import defaultdict
import arcpy
#from arcpy import toolbox
from arcpy._mp import ArcGISProject, Map, Layer as arcLayer
from arcpy import metadata as md
from specklepy.api.models import Branch, Stream, Streams
from speckle.converter.layers.Layer import Layer, RasterLayer
from speckle.converter.layers._init_ import convertSelectedLayers, layerToNative, cadLayerToNative
from arcgis.features import FeatureLayer
import os
import os.path
import specklepy
from specklepy.transports.server.server import ServerTransport
from specklepy.api.credentials import get_local_accounts
from specklepy.api.client import SpeckleClient
from specklepy.api import operations
from specklepy.logging.exceptions import (
GraphQLException,
SpeckleException,
SpeckleWarning,
)
#from specklepy.api.credentials import StreamWrapper
from specklepy.api.wrapper import StreamWrapper
from specklepy.objects import Base
from specklepy.logging import metrics
from speckle.ui.project_vars import toolboxInputsClass, speckleInputsClass
from speckle.converter.layers.emptyLayerTemplates import createGroupLayer
from speckle.converter.layers.Layer import VectorLayer
#'''
def traverseObject(
base: Base,
callback: Optional[Callable[[Base], bool]],
check: Optional[Callable[[Base], bool]],
):
if check and check(base):
res = callback(base) if callback else False
if res:
return
memberNames = base.get_member_names()
for name in memberNames:
try:
if ["id", "applicationId", "units", "speckle_type"].index(name):
continue
except:
pass
traverseValue(base[name], callback, check)
def traverseValue(
value: Any,
callback: Optional[Callable[[Base], bool]],
check: Optional[Callable[[Base], bool]],
):
if isinstance(value, Base):
traverseObject(value, callback, check)
if isinstance(value, List):
for item in value:
traverseValue(item, callback, check)
class Toolbox:
def __init__(self):
"""Define the toolbox (the name of the toolbox is the name of the
.pyt file)."""
print("___ping_Toolbox")
self.label = "Speckle Tools"
self.alias = "speckle_toolbox_"
# List of tool classes associated with this toolbox
self.tools = [Speckle]
metrics.set_host_app("ArcGIS")
# https://pro.arcgis.com/en/pro-app/2.8/arcpy/mapping/alphabeticallistofclasses.htm#except: print("something happened")
class Speckle:
def __init__(self):
#print("________________reset_______________")
self.label = "Speckle"
self.description = "Allows you to send and receive your layers " + \
"to/from other software using Speckle server."
self.toRefresh = False
self.speckleInputs = None
self.toolboxInputs = None
#print("ping_Speckle1")
#print(speckleInputsClass.instances)
total = len(speckleInputsClass.instances)
#print(total)
for i in range(total):
#print(i)
#print(speckleInputsClass.instances[total-i-1])
if speckleInputsClass.instances[total-i-1] is not None:
try:
#print(speckleInputsClass.instances[total-i-1].streams_default)
y = speckleInputsClass.instances[total-i-1].streams_default # in case not initialized properly
self.speckleInputs = speckleInputsClass.instances[total-i-1] # take latest (first in reverted list)
#print("FOUND INSTANCE")
break
except: pass
#print(self.speckleInputs)
if self.speckleInputs is None: self.speckleInputs = speckleInputsClass()
#print(toolboxInputsClass.instances)
#print("TOTAL = ...................")
total = len(toolboxInputsClass.instances)
#print(total)
for i in range(total):
if toolboxInputsClass.instances[total-i-1] is not None:
self.toolboxInputs = toolboxInputsClass.instances[total-i-1] # take latest (first in reverted list)
#print("FOUND INSTANCE")
break
#print(self.toolboxInputs)
if self.toolboxInputs is None: self.toolboxInputs = toolboxInputsClass()
#print("ping_Speckle2")
def getParameterInfo(self):
#data types: https://pro.arcgis.com/en/pro-app/2.8/arcpy/geoprocessing_and_python/defining-parameter-data-types-in-a-python-toolbox.htm
# parameter details: https://pro.arcgis.com/en/pro-app/latest/arcpy/geoprocessing_and_python/customizing-tool-behavior-in-a-python-toolbox.htm
print("Get parameter values")
cat1 = "Add Streams"
cat2 = "Send/Receive"
cat3 = "Create custom Spatial Reference"
streamsDefalut = arcpy.Parameter(
displayName="Add stream from default account",
name="streamsDefalut",
datatype="GPString",
parameterType="Optional",
#category="Sending data",
direction="Input",
category=cat1
)
streamsDefalut.filter.type = 'ValueList'
streamsDefalut.filter.list = [ (st.name + " - " + st.id) for st in self.speckleInputs.streams_default ]
addDefStreams = arcpy.Parameter(
displayName="Add",
name="addDefStreams",
datatype="GPBoolean",
parameterType="Optional",
#category="Sending data",
direction="Input",
category=cat1
)
addDefStreams.value = False
streamUrl = arcpy.Parameter(
displayName="Add stream by URL",
name="streamUrl",
datatype="GPString",
parameterType="Optional",
direction="Input",
category=cat1
)
streamUrl.value = ""
addUrlStreams = arcpy.Parameter(
displayName="Add",
name="addUrlStreams",
datatype="GPBoolean",
parameterType="Optional",
direction="Input",
category=cat1
)
addUrlStreams.value = False
############################################################################
lat = arcpy.Parameter(
displayName="Origin point LAT",
name="lat",
datatype="GPString",
parameterType="Optional",
direction="Input",
category=cat3
)
lat.value = str(self.toolboxInputs.lat)
lon = arcpy.Parameter(
displayName="Origin point LON",
name="lon",
datatype="GPString",
parameterType="Optional",
direction="Input",
category=cat3
)
lon.value = str(self.toolboxInputs.lon)
setLatLon = arcpy.Parameter(
displayName="Create and apply",
name="setLatLon",
datatype="GPBoolean",
parameterType="Optional",
direction="Input",
category=cat3
)
setLatLon.value = False
####################################################################################################
savedStreams = arcpy.Parameter(
displayName="Select Stream",
name="savedStreams",
datatype="GPString",
parameterType="Required",
direction="Input",
multiValue=False,
#category=cat2
)
savedStreams.filter.list = [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}" for i,stream in enumerate(self.speckleInputs.saved_streams)]
removeStream = arcpy.Parameter(
displayName="Remove",
name="removeStream",
datatype="GPBoolean",
parameterType="Optional",
direction="Input"
)
removeStream.value = False
branch = arcpy.Parameter(
displayName="Branch",
name="branch",
datatype="GPString",
parameterType="Required",
#category="Sending data",
direction="Input",
#category=cat2
)
branch.value = ""
branch.filter.type = 'ValueList'
commit = arcpy.Parameter(
displayName="Commit",
name="commit",
datatype="GPString",
parameterType="Optional",
#category="Sending data",
direction="Input",
#category=cat2
)
commit.value = ""
commit.filter.type = 'ValueList'
msg = arcpy.Parameter(
displayName="Message",
name="message",
datatype="GPString",
parameterType="Optional",
direction="Input",
multiValue=False,
#category=cat2
)
msg.value = ""
selectedLayers = arcpy.Parameter(
displayName="Selected Layers",
name="selectedLayers",
datatype="GPString",
parameterType="Optional",
direction="Input",
multiValue=True,
#category=cat2
)
selectedLayers.filter.list = [str(i) + "-" + l.longName for i,l in enumerate(self.speckleInputs.all_layers)] #"Polyline"
action = arcpy.Parameter(
displayName="",
name="action",
datatype="GPString",
parameterType="Required",
#category="Sending data",
direction="Input",
multiValue=False,
#category=cat2
)
action.value = "Send"
#action.filter.type = 'ValueList'
action.filter.list = ["Send", "Receive"]
refresh = arcpy.Parameter(
displayName="Refresh",
name="refresh",
datatype="GPBoolean",
parameterType="Optional",
direction="Input"
)
#refresh.filter.type = "ValueList"
refresh.value = False
parameters = [streamsDefalut, addDefStreams, streamUrl, addUrlStreams, lat, lon, setLatLon, savedStreams, removeStream, branch, commit, selectedLayers, msg, action, refresh]
return parameters
def isLicensed(self): #optional
return True
def updateParameters(self, parameters: List, toRefresh = False): #optional
print("UPDATING PARAMETERS")
for i, par in enumerate(parameters):
if par.name == "addDefStreams" and par.altered and par.value == True:
for p in parameters:
if p.name == "streamsDefalut" and p.valueAsText is not None:
# add value from streamsDefault to saved streams
selected_stream_name = p.valueAsText[:]
#print(selected_stream_name)
for stream in self.speckleInputs.streams_default:
#print(stream)
if stream.name == selected_stream_name.split(" - ")[0]:
print("_____Add from list___")
wr = StreamWrapper(f"{self.speckleInputs.account.serverInfo.url}/streams/{stream.id}?u={self.speckleInputs.account.userInfo.id}")
self.toolboxInputs.setProjectStreams(wr)
for p_saved in parameters:
if p_saved.name == "savedStreams":
saved_streams = self.speckleInputs.getProjectStreams()
self.speckleInputs.saved_streams = saved_streams
p_saved.filter.list = [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}" for i,stream in enumerate(saved_streams)]
if len(p_saved.filter.list)>0: print(p_saved.filter.list); p_saved.value = p_saved.filter.list[0]
break
p.value = None
par.value = False
if par.name == "addUrlStreams" and par.altered and par.value == True:
for p in parameters:
if p.name == "streamUrl" and p.valueAsText is not None:
# add value from streamsDefault to saved streams
query = p.valueAsText[:]
if "http" in query and len(query.split("/")) >= 3: # URL
steamId = query
try: steamId = query.split("/streams/")[1].split("/")[0]
except: pass
# quesry stream, add to saved
stream = self.speckleInputs.speckle_client.stream.get(steamId)
if isinstance(stream, Stream):
print("_____Add by URL___")
wr = StreamWrapper(f"{self.speckleInputs.account.serverInfo.url}/streams/{stream.id}?u={self.speckleInputs.account.userInfo.id}")
self.toolboxInputs.setProjectStreams(wr)
for p_saved in parameters:
if p_saved.name == "savedStreams":
saved_streams = self.speckleInputs.getProjectStreams()
self.speckleInputs.saved_streams = saved_streams
p_saved.filter.list = [f"Stream not accessible - {st[0].stream_id}" if st[1] is None or isinstance(st[1], SpeckleException) else f"{st[1].name} - {st[1].id}" for i,st in enumerate(saved_streams)]
if len(p_saved.filter.list)>0: print(p_saved.filter.list); p_saved.value = p_saved.filter.list[0]
else: pass
p.value = None
break
par.value = False
if par.name == "removeStream" and par.altered and par.value == True:
for p in parameters:
if p.name == "savedStreams" and p.valueAsText is not None:
# get value from savedStreams
selected_stream_name = p.valueAsText[:]
#print(selected_stream_name)
for streamTup in self.speckleInputs.saved_streams:
#print(stream)
stream = streamTup[1]
if stream.name == selected_stream_name.split(" - ")[0]:
print("_____Remove stream___")
wr = StreamWrapper(f"{self.speckleInputs.account.serverInfo.url}/streams/{stream.id}?u={self.speckleInputs.account.userInfo.id}")
self.toolboxInputs.setProjectStreams(wr, False)
for p_saved in parameters:
if p_saved.name == "savedStreams":
saved_streams = self.speckleInputs.getProjectStreams()
self.speckleInputs.saved_streams = saved_streams
p_saved.filter.list = [f"Stream not accessible - {st[0].stream_id}" if st[1] is None or isinstance(st[1], SpeckleException) else f"{st[1].name} - {st[1].id}" for i,st in enumerate(saved_streams)]
p_saved.value = None
break
p.value = None
par.value = False
#######################################################################
if par.name == "setLatLon" and par.altered and par.value == True:
lat = lon = 0
for p in parameters:
if p.name == "lat" and p.valueAsText is not None:
# add value from the UI to saved lat
lat = p.valueAsText[:].replace(",","").replace(" ","").replace(";","").replace("-","").replace("_","")
try: lat = float(lat)
except: lat = 0; p.value = "0.0"
if p.name == "lon" and p.valueAsText is not None:
# add value from the UI to saved lat
lon = p.valueAsText[:].replace(",","").replace(" ","").replace(";","").replace("-","").replace("_","")
try: lon = float(lon)
except: lon = 0; p.value = "0.0"
coords = [lat, lon]
self.toolboxInputs.set_survey_point(coords)
par.value = False
#######################################################################
if par.name == "savedStreams" and par.altered:
# Search for the stream by name
if par.value is not None and "Stream not accessible" not in par.valueAsText[:]:
#print("SAVED STREAMS - selection")
selected_stream_name = par.valueAsText[:]
self.toolboxInputs.active_stream = None
for st in self.speckleInputs.saved_streams:
if st[1].name == selected_stream_name.split(" - ")[0]:
self.toolboxInputs.active_stream = st[1]
break
# edit branches: globals and UI
branch_list = [branch.name for branch in self.toolboxInputs.active_stream.branches.items]
for p in parameters:
if p.name == "branch":
p.filter.list = branch_list
if p.valueAsText not in branch_list:
p.value = "main"
for b in self.toolboxInputs.active_stream.branches.items:
if b.name == p.value:
self.toolboxInputs.active_branch = b
break
# setting commit value and list
for p in parameters:
if p.name == "commit":
try:
p.filter.list = [f"{commit.id}"+ " - " + f"{commit.message}" for commit in self.toolboxInputs.active_branch.commits.items]
if p.valueAsText not in p.filter.list:
p.value = self.toolboxInputs.active_branch.commits.items[0].id + " - " + self.toolboxInputs.active_branch.commits.items[0].message
self.toolboxInputs.active_commit = self.toolboxInputs.active_branch.commits.items[0]
except:
p.filter.list = []
p.value = None
self.toolboxInputs.active_commit = None
else: par.value = None
#print(self.toolboxInputs.action)
if par.name == "branch" and par.altered: # branches
if par.value is not None:
selected_branch_name = par.valueAsText[:]
self.toolboxInputs.active_branch = None
if self.toolboxInputs.active_stream is not None:
for br in self.toolboxInputs.active_stream.branches.items:
if br.name == selected_branch_name:
self.toolboxInputs.active_branch = br
break
# edit commit values
if self.toolboxInputs.active_branch is not None:
for p in parameters:
if p.name == "commit":
try:
p.filter.list = [f"{commit.id}"+ " - " + f"{commit.message}" for commit in self.toolboxInputs.active_branch.commits.items]
if p.valueAsText not in p.filter.list:
p.value = self.toolboxInputs.active_branch.commits.items[0].id + " - " + self.toolboxInputs.active_branch.commits.items[0].message
self.toolboxInputs.active_commit = self.toolboxInputs.active_branch.commits.items[0]
except:
p.filter.list = []
p.value = None
self.toolboxInputs.active_commit = None
if par.name == "commit" and par.altered: # commits
if par.value is not None:
selected_commit_id = par.valueAsText[:].split(" - ")[0]
self.toolboxInputs.active_commit = None
if self.toolboxInputs.active_branch is not None:
for c in self.toolboxInputs.active_branch.commits.items:
if c.id == selected_commit_id:
self.toolboxInputs.active_commit = c
break
if par.name == "selectedLayers" and par.altered: # selected layers
if par.value is not None:
self.toolboxInputs.selected_layers = par.values
#print("selected layers changed")
#print(self.toolboxInputs.action)
#print(self.toolboxInputs.selected_layers)
if par.name == "msg" and par.altered and par.valueAsText is not None:
self.toolboxInputs.messageSpeckle = par.valueAsText
if par.name == "action" and par.altered:
#print("action changed")
#print(par.valueAsText)
if par.valueAsText == "Send": self.toolboxInputs.action = 1
else: self.toolboxInputs.action = 0
#print(self.toolboxInputs.action)
#print(self.toolboxInputs.selected_layers)
if par.name == "refresh" and par.altered: # refresh btn
if par.value == True:
self.refresh(parameters)
if self.toRefresh == True:
self.refresh(parameters)
self.toRefresh = False
print("____________________________parameters___________________________")
#[print(str(x.name) + " - " + str(x.valueAsText)) for x in parameters]
#[x.clearMessage() for x in parameters] # https://pro.arcgis.com/en/pro-app/latest/arcpy/geoprocessing_and_python/programming-a-toolvalidator-class.htm
#[print(x.valueAsText) for x in parameters]
return
def refresh(self, parameters: List[Any]):
print("Refresh______")
self.speckleInputs: speckleInputsClass = speckleInputsClass()
self.toolboxInputs: toolboxInputsClass = toolboxInputsClass()
for par in parameters:
if par.name == "streamUrl": par.value = None
if par.name == "streamsDefalut": par.value = None
if par.name == "savedStreams": par.value = None
if par.name == "branch": par.value = ""
if par.name == "commit": par.value = None
if par.name == "selectedLayers": par.value = None
if par.name == "msg": par.value = ""
if par.name == "action": par.value = "Send"
if par.name == "refresh": par.value = False
if par.name == "lat": par.value = str(self.toolboxInputs.get_survey_point()[0])
if par.name == "lon": par.value = str(self.toolboxInputs.get_survey_point()[1])
if par.name == "streamsDefalut": par.filter.list = [ (st.name + " - " + st.id) for st in self.speckleInputs.streams_default ]
if par.name == "savedStreams":
#print("par.name")
saved_streams = self.speckleInputs.getProjectStreams()
#print(saved_streams)
par.filter.list = [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}" for i,stream in enumerate(saved_streams)]
if par.name == "selectedLayers": par.filter.list = [str(i) + "-" + l.longName for i,l in enumerate(self.speckleInputs.all_layers)]
return parameters
def updateMessages(self, parameters): #optional
return
def execute(self, parameters: List, messages):
# https://pro.arcgis.com/en/pro-app/latest/arcpy/get-started/what-is-arcpy-.htm
#Warning if any of the fields is invalid/empty
print("___________________________Run___________________________")
check = self.validateStreamBranch(parameters) # apparently pdate needed to assign proper self.values
print(self.toolboxInputs.selected_layers)
print(self.toolboxInputs.action)
if self.toolboxInputs.action == 1 and check is True: self.onSend(parameters)
elif self.toolboxInputs.action == 0 and check is True: self.onReceive(parameters)
print("__________________________Run_end___________________________")
def validateStreamBranch(self, parameters: List):
self.updateParameters(parameters)
if self.toolboxInputs.active_stream is None:
arcpy.AddError("Choose a valid stream")
return False
if self.toolboxInputs.active_branch is None:
arcpy.AddError("Choose a valid branch")
return False
return True
def onSend(self, parameters: List):
print("______________SEND_______________")
#if self.validateStreamBranch(parameters) == False: return
if len(self.toolboxInputs.selected_layers) == 0:
arcpy.AddError("No layers selected for sending")
return
streamId = self.toolboxInputs.active_stream.id #stream_id
client = self.speckleInputs.speckle_client # ?
# Get the stream wrapper
#streamWrapper = StreamWrapper(None)
#client = streamWrapper.get_client()
# Ensure the stream actually exists
#try:
# client.stream.get(streamId)
#except SpeckleException as error:
# print(str(error))
# return
# next create a server transport - this is the vehicle through which you will send and receive
transport = ServerTransport(client=client, stream_id=streamId)
##################################### conversions ################################################
base_obj = Base(units = "m")
base_obj.layers = convertSelectedLayers(self.speckleInputs.all_layers, self.toolboxInputs.selected_layers, self.speckleInputs.project)
try:
# this serialises the block and sends it to the transport
objId = operations.send(base=base_obj, transports=[transport])
except SpeckleException as error:
arcpy.AddError("Error sending data")
#print("Error sending data")
return
except SpeckleWarning as warning:
arcpy.AddMessage("SpeckleWarning: " + str(warning.args[0]))
message = self.toolboxInputs.messageSpeckle
if message is None or ( isinstance(message, str) and len(message) == 0): message = "Sent from ArcGIS"
try:
# you can now create a commit on your stream with this object
client.commit.create(
stream_id=streamId,
object_id=objId,
branch_name=self.toolboxInputs.active_branch.name,
message=message,
source_application="ArcGIS",
)
arcpy.AddMessage("Successfully sent data to stream: " + streamId)
except:
arcpy.AddError("Error creating commit")
def onReceive(self, parameters: List[Any]):
print("______________RECEIVE_______________")
#if self.validateStreamBranch(parameters) == False: return
try:
streamId = self.toolboxInputs.active_stream.id #stream_id
client = self.speckleInputs.speckle_client #
except SpeckleWarning as warning:
arcpy.AddWarning(str(warning.args[0]))
# get commit
commit = None
try:
#commit = self.toolboxInputs.active_branch.commits.items[0]
commit = self.toolboxInputs.active_commit
commitId = commit.id # text to make sure commit exists
except:
try:
commit = self.toolboxInputs.active_branch.commits.items[0]
commitId = commit.id
arcpy.AddWarning("Failed to find a commit. Getting the last commit of the branch")
except:
arcpy.AddError("Failed to find a commit")
return
# next create a server transport - this is the vehicle through which you will send and receive
try:
transport = ServerTransport(client=client, stream_id=streamId)
client.commit.received(
streamId,
commit.id,
source_application="ArcGIS",
message="Received commit in ArcGIS",
)
except:
arcpy.AddError("Make sure your account has access to the chosen stream")
return
try:
#print(commit)
objId = commit.referencedObject
commitDetailed = client.commit.get(streamId, commit.id)
app = commitDetailed.sourceApplication
if objId is None:
return
commitObj = operations.receive(objId, transport, None)
if app != "QGIS" and app != "ArcGIS":
if self.speckleInputs.project.activeMap.spatialReference.type == "Geographic" or self.speckleInputs.project.activeMap.spatialReference is None: #TODO test with invalid CRS
arcpy.AddMessage("It is advisable to set the project Spatial reference to Projected type before receiving CAD geometry (e.g. EPSG:32631), or create a custom one from geographic coordinates")
print("It is advisable to set the project Spatial reference to Projected type before receiving CAD geometry (e.g. EPSG:32631), or create a custom one from geographic coordinates")
print(f"Succesfully received {objId}")
# Clear 'latest' group
streamBranch = streamId + "_" + self.toolboxInputs.active_branch.name + "_" + str(commit.id)
newGroupName = f'{streamBranch}'
groupExists = 0
#print(newGroupName)
for l in self.speckleInputs.project.activeMap.listLayers():
#print(l.longName)
if l.longName.startswith(newGroupName + "\\"):
#print(l.longName)
self.speckleInputs.project.activeMap.removeLayer(l)
groupExists+=1
elif l.longName == newGroupName:
groupExists+=1
if groupExists == 0:
# create empty group layer file
path = self.speckleInputs.project.filePath.replace("aprx","gdb") #"\\".join(self.toolboxInputs.project.filePath.split("\\")[:-1]) + "\\speckle_layers\\"
#print(path)
f = open(path + "\\" + newGroupName + ".lyrx", "w")
content = createGroupLayer().replace("TestGroupLayer", newGroupName)
f.write(content)
f.close()
smth = arcpy.mp.LayerFile(path + "\\" + newGroupName + ".lyrx")
#print(smth)
layerGroup = self.speckleInputs.project.activeMap.addLayer(smth)[0]
layerGroup.name = newGroupName
if app == "QGIS" or app == "ArcGIS": check: Callable[[Base], bool] = lambda base: isinstance(base, Layer) or isinstance(base, VectorLayer) or isinstance(base, RasterLayer)
else: check: Callable[[Base], bool] = lambda base: isinstance(base, Base)
def callback(base: Base) -> bool:
print("callback")
#print(base)
if isinstance(base, Layer) or isinstance(base, VectorLayer) or isinstance(base, RasterLayer):
layer = layerToNative(base, streamBranch, self.speckleInputs.project)
if layer is not None:
print("Layer created: " + layer.name)
else:
loopObj(base, "")
return True
def loopObj(base: Base, baseName: str):
memberNames = base.get_member_names()
for name in memberNames:
if name in ["id", "applicationId", "units", "speckle_type"]: continue
try: loopVal(base[name], baseName + "/" + name) # loop properties not included above
except: pass
def loopVal(value: Any, name: str): # "name" is the parent object/property/layer name
if isinstance(value, Base):
try: # dont go through parts of Speckle Geometry object
print("objects to loop through: " + value.speckle_type)
if value.speckle_type.startswith("Objects.Geometry."): pass #.Brep") or value.speckle_type.startswith("Objects.Geometry.Mesh") or value.speckle_type.startswith("Objects.Geometry.Surface") or value.speckle_type.startswith("Objects.Geometry.Extrusion"): pass
else: loopObj(value, name)
except: loopObj(value, name)
if isinstance(value, List):
for item in value:
loopVal(item, name)
#print(item)
if item.speckle_type and item.speckle_type.startswith("Objects.Geometry."):
pt, pl = cadLayerToNative(value, name, streamBranch, self.speckleInputs.project)
if pt is not None: print("Layer group created: " + pt.name())
if pl is not None: print("Layer group created: " + pl.name())
break
traverseObject(commitObj, callback, check)
except SpeckleException as e:
print("Receive failed")
return
print("received")
#self.updateParameters(parameters, True)
#self.refresh(parameters)
#__all__ = ["Toolbox", "Speckle"]
@@ -1,5 +1,5 @@
<?xml version="1.0"?>
<metadata xml:lang="en"><Esri><CreaDate>20220718</CreaDate><CreaTime>13500100</CreaTime><ArcGISFormat>1.0</ArcGISFormat><SyncOnce>TRUE</SyncOnce><ModDate>20221024</ModDate><ModTime>110535</ModTime><scaleRange><minScale>150000000</minScale><maxScale>5000</maxScale></scaleRange><ArcGISProfile>ItemDescription</ArcGISProfile></Esri><toolbox name="Speckle" alias="speckle_toolbox_"><arcToolboxHelpPath>c:\program files\arcgis\pro\Resources\Help\gp</arcToolboxHelpPath><toolsets/></toolbox><dataIdInfo><idCitation><resTitle>Speckle</resTitle></idCitation><idPurp>Speckle connector for ArcGIS</idPurp><searchKeys><keyword>speckle3d</keyword></searchKeys></dataIdInfo><distInfo><distributor><distorFormat><formatName>ArcToolbox Toolbox</formatName></distorFormat></distributor></distInfo><mdHrLv><ScopeCd value="005"></ScopeCd></mdHrLv><Binary><Thumbnail><Data EsriPropertyType="PictureX">/9j/4AAQSkZJRgABAQEAYABgAAD/4gxYSUNDX1BST0ZJTEUAAQEAAAxITGlubwIQAABtbnRyUkdC
<metadata xml:lang="en"><Esri><CreaDate>20220718</CreaDate><CreaTime>13500100</CreaTime><ArcGISFormat>1.0</ArcGISFormat><SyncOnce>TRUE</SyncOnce><ModDate>20221025</ModDate><ModTime>190532</ModTime><scaleRange><minScale>150000000</minScale><maxScale>5000</maxScale></scaleRange><ArcGISProfile>ItemDescription</ArcGISProfile></Esri><toolbox name="Speckle" alias="speckle_toolbox_"><arcToolboxHelpPath>c:\program files\arcgis\pro\Resources\Help\gp</arcToolboxHelpPath><toolsets/></toolbox><dataIdInfo><idCitation><resTitle>Speckle</resTitle></idCitation><idPurp>Speckle connector for ArcGIS</idPurp><searchKeys><keyword>speckle3d</keyword></searchKeys></dataIdInfo><distInfo><distributor><distorFormat><formatName>ArcToolbox Toolbox</formatName></distorFormat></distributor></distInfo><mdHrLv><ScopeCd value="005"></ScopeCd></mdHrLv><Binary><Thumbnail><Data EsriPropertyType="PictureX">/9j/4AAQSkZJRgABAQEAYABgAAD/4gxYSUNDX1BST0ZJTEUAAQEAAAxITGlubwIQAABtbnRyUkdC
IFhZWiAHzgACAAkABgAxAABhY3NwTVNGVAAAAABJRUMgc1JHQgAAAAAAAAAAAAAAAAAA9tYAAQAA
AADTLUhQICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFj
cHJ0AAABUAAAADNkZXNjAAABhAAAAGx3dHB0AAAB8AAAABRia3B0AAACBAAAABRyWFlaAAACGAAA
@@ -161,7 +161,10 @@ def rasterFeatureToSpeckle(selectedLayer: arcLayer, projectCRS: arcpy.SpatialRef
#ds = gdal.Open(selectedLayer.source(), gdal.GA_ReadOnly)
extent = my_raster.extent
rasterOriginPoint = arcpy.PointGeometry(arcpy.Point(extent.XMin, extent.YMin, extent.ZMin), my_raster.spatialReference, has_z = True)
print(extent.XMin)
print(extent.YMin)
rasterOriginPoint = arcpy.PointGeometry(arcpy.Point(extent.XMin, extent.YMax, extent.ZMin), my_raster.spatialReference, has_z = True)
#if extent.YMin>0: rasterOriginPoint = arcpy.PointGeometry(arcpy.Point(extent.XMin, extent.YMax, extent.ZMin), my_raster.spatialReference, has_z = True)
print(rasterOriginPoint)
rasterResXY = [my_raster.meanCellWidth, my_raster.meanCellHeight] #[float(ds.GetGeoTransform()[1]), float(ds.GetGeoTransform()[5])]
rasterBandNoDataVal = [] #list(my_raster.noDataValues)
@@ -192,7 +195,7 @@ def rasterFeatureToSpeckle(selectedLayer: arcLayer, projectCRS: arcpy.SpatialRef
print(np.shape(rb.read()))
valMin = rb.minimum
valMax = rb.maximum
bandVals = np.flip(np.swapaxes(rb.read(), 1, 2), 0).flatten() #.tolist()
bandVals = np.swapaxes(rb.read(), 1, 2).flatten() #.tolist() np.flip( , 0)
bandValsFlat = []
bandValsFlat.extend(bandVals.tolist())
@@ -240,7 +243,7 @@ def rasterFeatureToSpeckle(selectedLayer: arcLayer, projectCRS: arcpy.SpatialRef
b["@(10000)" + item + "_values"] = bandValsFlat #[0:int(max_values/rasterBandCount)]
b["X resolution"] = rasterResXY[0]
b["Y resolution"] = rasterResXY[1]
b["Y resolution"] = -1* rasterResXY[1]
b["X pixels"] = rasterDimensions[0]
b["Y pixels"] = rasterDimensions[1]
b["Band count"] = rasterBandCount
@@ -316,10 +319,10 @@ def rasterFeatureToSpeckle(selectedLayer: arcLayer, projectCRS: arcpy.SpatialRef
# identify symbology type and if Multiband, which band is which color
for v in range(rasterDimensions[1] ): #each row, Y
for h in range(rasterDimensions[0] ): #item in a row, X
pt1 = arcpy.PointGeometry(arcpy.Point(extent.XMin+h*rasterResXY[0],extent.YMin+v*rasterResXY[1]), my_raster.spatialReference, has_z = True)
pt2 = arcpy.PointGeometry(arcpy.Point(extent.XMin+h*rasterResXY[0], extent.YMin+(v+1)*rasterResXY[1]), my_raster.spatialReference, has_z = True)
pt3 = arcpy.PointGeometry(arcpy.Point(extent.XMin+(h+1)*rasterResXY[0], extent.YMin+(v+1)*rasterResXY[1]), my_raster.spatialReference, has_z = True)
pt4 = arcpy.PointGeometry(arcpy.Point(extent.XMin+(h+1)*rasterResXY[0], extent.YMin+v*rasterResXY[1]), my_raster.spatialReference, has_z = True)
pt1 = arcpy.PointGeometry(arcpy.Point(extent.XMin+h*rasterResXY[0],extent.YMax-v*rasterResXY[1]), my_raster.spatialReference, has_z = True)
pt2 = arcpy.PointGeometry(arcpy.Point(extent.XMin+h*rasterResXY[0], extent.YMax-(v+1)*rasterResXY[1]), my_raster.spatialReference, has_z = True)
pt3 = arcpy.PointGeometry(arcpy.Point(extent.XMin+(h+1)*rasterResXY[0], extent.YMax-(v+1)*rasterResXY[1]), my_raster.spatialReference, has_z = True)
pt4 = arcpy.PointGeometry(arcpy.Point(extent.XMin+(h+1)*rasterResXY[0], extent.YMax-v*rasterResXY[1]), my_raster.spatialReference, has_z = True)
# first, get point coordinates with correct position and resolution, then reproject each:
if my_raster.spatialReference.name != projectCRS.name:
pt1 = findTransformation(pt1, "Point", my_raster.spatialReference, projectCRS, selectedLayer)
@@ -1,13 +1,13 @@
# -*- coding: utf-8 -*-
r'''
import arcpy
class Toolbox(object):
def __init__(self):
"""Define the toolbox (the name of the toolbox is the name of the
.pyt file)."""
self.label = "Speckle Toolbox"
self.alias = "speckle_toolbox_"
self.label = "Speckle something"
self.alias = "speckle_toolbox"
self.tools = [Speckle]
class Speckle(object):
@@ -45,4 +45,4 @@ class Speckle(object):
def execute(self, parameters):
return
'''
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from typing import Any, Callable, List, Optional, Tuple
#r'''
r'''
from collections import defaultdict
import arcpy
@@ -36,7 +36,7 @@ from speckle.ui.project_vars import toolboxInputsClass, speckleInputsClass
from speckle.converter.layers.emptyLayerTemplates import createGroupLayer
from speckle.converter.layers.Layer import VectorLayer
#'''
def traverseObject(
base: Base,
@@ -74,7 +74,7 @@ class Toolbox:
.pyt file)."""
print("___ping_Toolbox")
self.label = "Speckle Tools"
self.alias = "speckle_toolbox_"
self.alias = "speckle_toolbox"
# List of tool classes associated with this toolbox
self.tools = [Speckle]
metrics.set_host_app("ArcGIS")
@@ -758,5 +758,6 @@ class Speckle:
#self.updateParameters(parameters, True)
#self.refresh(parameters)
#__all__ = ["Toolbox", "Speckle"]
#__all__ = ["Toolbox", "Speckle"]
'''
@@ -25,7 +25,7 @@ class speckleInputsClass:
project = None
active_map = None
saved_streams: List[None or Tuple[StreamWrapper, Stream]] = []
saved_streams: List[Optional[Tuple[StreamWrapper, Stream]]] = []
stream_file_path: str = ""
all_layers: List[arcLayer] = []
@@ -44,6 +44,7 @@ class speckleInputsClass:
def __init__(self) -> None:
print("___start speckle inputs________")
self.all_layers = []
try:
aprx = ArcGISProject('CURRENT')
self.project = aprx
@@ -63,7 +64,9 @@ class speckleInputsClass:
f.close()
except: pass
else:
elif len(self.stream_file_path) >10:
f = open(self.stream_file_path, "x")
f.close()
f = open(self.stream_file_path, "w")
content = ""
f.write(content)
@@ -89,6 +92,7 @@ class speckleInputsClass:
streamExists = 0
index = 0
try:
print(url)
sw = StreamWrapper(url)
stream = self.tryGetStream(sw)
@@ -101,7 +105,7 @@ class speckleInputsClass:
streamsTuples.insert(0,(sw, stream))
except SpeckleException as e:
arcpy.AddMessage(str(e.args[0]))
arcpy.AddMessage(str(e.args))
return streamsTuples
else: return []
@@ -126,8 +130,8 @@ class toolboxInputsClass:
instances = []
lat: float = 0.0
lon: float = 0.0
active_stream: None or Stream = None
active_branch: None or Branch = None
active_stream: Optional[Stream] = None
active_branch: Optional[Branch] = None
active_commit = None
selected_layers: List[Any] = []
messageSpeckle: str = ""
@@ -159,7 +163,7 @@ class toolboxInputsClass:
def setProjectStreams(self, wr: StreamWrapper, add = True):
# ERROR 032659 Error queueing metrics request:
# Cannot parse into a stream wrapper class - invalid URL provided.
print("SET proj streamz")
print("SET proj streams")
if os.path.exists(self.stream_file_path):
@@ -180,7 +184,9 @@ class toolboxInputsClass:
f.write(new_content)
f.close()
else:
elif len(self.stream_file_path) >10:
f = open(self.stream_file_path, "x")
f.close()
f = open(self.stream_file_path, "w")
f.write(str(wr.stream_url) + ",")
f.close()
@@ -226,7 +232,9 @@ class toolboxInputsClass:
new_content += pt + "," # add point
f.write(new_content)
f.close()
else:
elif len(self.stream_file_path) >10:
f = open(self.stream_file_path, "x")
f.close()
f = open(self.stream_file_path, "w")
f.write(pt + ",")
f.close()