helper.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. r"""web_helper is a module that provides access to functions that helps to build
  2. new protocols and process ParaView data structure into web friendly ones.
  3. """
  4. import sys
  5. import os
  6. import traceback
  7. # import paraview modules.
  8. import paraview
  9. from paraview import simple, servermanager
  10. from paraview.servermanager import ProxyProperty
  11. from paraview.modules.vtkRemotingViews import vtkSMPVRepresentationProxy
  12. # =============================================================================
  13. # Pipeline management
  14. # =============================================================================
  15. class Pipeline:
  16. """
  17. Define a data structure that represent a pipeline as a tree.
  18. This provide also methods to get the data structure for the web environment
  19. """
  20. # --------------------------------------------------------------------------
  21. def __init__(self, name):
  22. self.root_node = {"name": name, "icon": "server", "children": []}
  23. self.parent_ids = {"0": "0"}
  24. self.children_ids = {"0": []}
  25. # --------------------------------------------------------------------------
  26. def clear(self):
  27. """
  28. Clear the pipeline tree.
  29. """
  30. self.root_node["children"] = []
  31. self.parent_ids = {"0": "0"}
  32. self.children_ids = {"0": []}
  33. # --------------------------------------------------------------------------
  34. def addNode(self, parent_id, node_id):
  35. """
  36. Add node into the pipeline tree.
  37. """
  38. pid = str(parent_id)
  39. nid = str(node_id)
  40. # Add child
  41. if pid in self.children_ids:
  42. self.children_ids[pid].append(nid)
  43. else:
  44. self.children_ids[pid] = [nid]
  45. # Add parent
  46. self.parent_ids[nid] = pid
  47. # --------------------------------------------------------------------------
  48. def removeNode(self, id):
  49. """
  50. Remove a node from the pipeline tree.
  51. """
  52. nid = str(id)
  53. pid = self.parent_ids[nid]
  54. if pid:
  55. del self.parent_ids[nid]
  56. self.children_ids[pid].remove(nid)
  57. # --------------------------------------------------------------------------
  58. def isEmpty(self):
  59. return len(self.parent_ids) == 1
  60. # --------------------------------------------------------------------------
  61. def getRootNode(self, view=None):
  62. """
  63. Create a tree structure of the pipeline with the current proxy state.
  64. """
  65. self.root_node["children"] = []
  66. self.__fill_children(self.root_node, self.children_ids["0"], view)
  67. return self.root_node
  68. # --------------------------------------------------------------------------
  69. def __fill_children(self, nodeToFill, childrenIds, view=None):
  70. for id in childrenIds:
  71. node = getProxyAsPipelineNode(id, view)
  72. nid = str(node["proxy_id"])
  73. if "children" in nodeToFill:
  74. nodeToFill["children"].append(node)
  75. else:
  76. nodeToFill["children"] = [node]
  77. if nid in self.children_ids:
  78. self.__fill_children(node, self.children_ids[nid])
  79. # =============================================================================
  80. # Proxy management
  81. # =============================================================================
  82. def idToProxy(id):
  83. """
  84. Return the proxy that match the given proxy ID.
  85. """
  86. remoteObject = simple.servermanager.ActiveConnection.Session.GetRemoteObject(
  87. int(id)
  88. )
  89. if remoteObject:
  90. return simple.servermanager._getPyProxy(remoteObject)
  91. return None
  92. # --------------------------------------------------------------------------
  93. def getParentProxyId(proxy):
  94. """
  95. Return '0' if the given proxy has no Input otherwise will return
  96. the parent proxy id as a String.
  97. """
  98. if proxy and proxy.GetProperty("Input"):
  99. parentProxy = proxy.GetProperty("Input").GetProxy(0)
  100. if parentProxy:
  101. return parentProxy.GetGlobalIDAsString()
  102. return "0"
  103. # --------------------------------------------------------------------------
  104. def getProxyAsPipelineNode(id, view=None):
  105. """
  106. Create a representation for that proxy so it can be used within a pipeline
  107. browser.
  108. """
  109. pxm = servermanager.ProxyManager()
  110. proxy = idToProxy(id)
  111. rep = simple.GetDisplayProperties(proxy)
  112. nbActiveComp = 1
  113. pointData = []
  114. searchArray = ("POINTS" == rep.ColorArrayName[0]) and (
  115. len(rep.ColorArrayName[1]) > 0
  116. )
  117. if servermanager.ActiveConnection.GetNumberOfDataPartitions() > 1:
  118. info = {
  119. "lutId": "vtkProcessId_1",
  120. "name": "vtkProcessId",
  121. "size": 1,
  122. "range": [
  123. 0,
  124. servermanager.ActiveConnection.GetNumberOfDataPartitions() - 1,
  125. ],
  126. }
  127. pointData.append(info)
  128. # FIXME seb
  129. # dataInfo = rep.GetRepresentedDataInformation()
  130. # pointData = dataInfo.GetPointDataInformation()
  131. # cellData = dataInfo.GetCellDataInformation()
  132. # for idx in pointData.GetNumberOfArrays():
  133. # info = pointData.GetArrayInformation(idx)
  134. # nbComponents = info.GetNumberOfComponents()
  135. # if searchArray and array.Name == rep.ColorArrayName:
  136. # nbActiveComp = nbComponents
  137. # rangeOn = (nbComponents == 3 if -1 else 0)
  138. # info = { \
  139. # 'lutId': info.GetName() + '_' + str(nbComponents), \
  140. # 'name': info.GetName, \
  141. # 'size': nbComponents, \
  142. # 'range': info.GetRange(rangeOn) }
  143. # pointData.append(info)
  144. for array in proxy.GetPointDataInformation():
  145. nbComponents = array.GetNumberOfComponents()
  146. if searchArray and array.Name == rep.ColorArrayName[1]:
  147. nbActiveComp = nbComponents
  148. rangeOn = nbComponents == 1 if 0 else -1
  149. info = {
  150. "lutId": array.Name + "_" + str(nbComponents),
  151. "name": array.Name,
  152. "size": nbComponents,
  153. "range": array.GetRange(rangeOn),
  154. }
  155. pointData.append(info)
  156. cellData = []
  157. searchArray = ("CELLS" == rep.ColorArrayName[0]) and (
  158. len(rep.ColorArrayName[1]) > 0
  159. )
  160. for array in proxy.GetCellDataInformation():
  161. nbComponents = array.GetNumberOfComponents()
  162. if searchArray and array.Name == rep.ColorArrayName[1]:
  163. nbActiveComp = nbComponents
  164. rangeOn = nbComponents == 1 if 0 else -1
  165. info = {
  166. "lutId": array.Name + "_" + str(nbComponents),
  167. "name": array.Name,
  168. "size": nbComponents,
  169. "range": array.GetRange(rangeOn),
  170. }
  171. cellData.append(info)
  172. state = getProxyAsState(proxy.GetGlobalID())
  173. showScalarbar = (
  174. 1
  175. if view
  176. and vtkSMPVRepresentationProxy.IsScalarBarVisible(rep.SMProxy, view.SMProxy)
  177. else 0
  178. )
  179. repName = "Hide"
  180. if rep.Visibility == 1:
  181. repName = rep.Representation
  182. return {
  183. "proxy_id": proxy.GetGlobalID(),
  184. "name": pxm.GetProxyName("sources", proxy),
  185. "bounds": proxy.GetDataInformation().GetBounds(),
  186. "pointData": pointData,
  187. "cellData": cellData,
  188. "activeData": str(rep.ColorArrayName[0]) + ":" + str(rep.ColorArrayName[1]),
  189. "diffuseColor": str(rep.DiffuseColor),
  190. "showScalarBar": showScalarbar,
  191. "representation": repName,
  192. "state": state,
  193. "children": [],
  194. }
  195. # --------------------------------------------------------------------------
  196. def getProxyAsState(id):
  197. """
  198. Return a json representation of the given proxy state.
  199. Example of the state of the Clip filter
  200. {
  201. proxy_id: 234,
  202. ClipType: {
  203. proxy_id: 235,
  204. Normal: [0,0,1],
  205. Origin: [0,0,0],
  206. InsideOut: 0
  207. }
  208. }
  209. """
  210. proxy_id = int(id)
  211. proxy = idToProxy(proxy_id)
  212. state = {
  213. "proxy_id": proxy_id,
  214. "type": "proxy",
  215. "domains": getProxyDomains(proxy_id),
  216. }
  217. properties = {}
  218. allowedTypes = [int, float, list, str]
  219. if proxy:
  220. for property in proxy.ListProperties():
  221. propertyName = proxy.GetProperty(property).Name
  222. if propertyName in ["Refresh", "Input"] or propertyName.__contains__(
  223. "Info"
  224. ):
  225. continue
  226. data = proxy.GetProperty(property).GetData()
  227. if type(data) in allowedTypes:
  228. properties[propertyName] = data
  229. continue
  230. # Not a simple property
  231. # Need more investigation
  232. prop = proxy.GetProperty(property)
  233. pythonProp = servermanager._wrap_property(proxy, prop)
  234. proxyList = []
  235. try:
  236. proxyList = pythonProp.Available
  237. except:
  238. pass
  239. if len(proxyList) and prop.GetNumberOfProxies() == 1:
  240. listdomain = prop.FindDomain("vtkSMProxyListDomain")
  241. if listdomain:
  242. proxyPropertyValue = prop.GetProxy(0)
  243. for i in range(listdomain.GetNumberOfProxies()):
  244. if listdomain.GetProxy(i) == proxyPropertyValue:
  245. properties[propertyName] = proxyList[i]
  246. # Add selected proxy in list of prop to edit
  247. properties[propertyName + "_internal"] = getProxyAsState(
  248. listdomain.GetProxy(i).GetGlobalID()
  249. )
  250. elif type(prop) == ProxyProperty:
  251. try:
  252. subProxyId = proxy.GetProperty(property).GetData().GetGlobalID()
  253. properties[propertyName] = getProxyAsState(subProxyId)
  254. except:
  255. print("Error on", property, propertyName)
  256. print("Skip property: ", str(type(data)))
  257. print(data)
  258. state["properties"] = properties
  259. return state
  260. # --------------------------------------------------------------------------
  261. def updateProxyProperties(proxy, properties):
  262. """
  263. Loop over the properties object and update the mapping properties
  264. to the given proxy.
  265. """
  266. try:
  267. allowedProperties = proxy.ListProperties()
  268. for key in properties:
  269. validKey = servermanager._make_name_valid(key)
  270. if validKey in allowedProperties:
  271. value = removeUnicode(properties[key])
  272. property = servermanager._wrap_property(
  273. proxy, proxy.GetProperty(validKey)
  274. )
  275. if (
  276. property.FindDomain("vtkSMProxyListDomain")
  277. and len(value) == 1
  278. and type(value[0]) == str
  279. ):
  280. try:
  281. idx = property.GetAvailable().index(value[0])
  282. proxyToSet = servermanager._getPyProxy(
  283. property.FindDomain("vtkSMProxyListDomain").GetProxy(idx)
  284. )
  285. property.SetData(proxyToSet)
  286. except:
  287. traceback.print_stack()
  288. pass
  289. elif value == "vtkProcessId":
  290. property.SetElement(0, value)
  291. else:
  292. property.SetData(value)
  293. except:
  294. traceback.print_stack()
  295. # --------------------------------------------------------------------------
  296. def removeUnicode(value):
  297. return value
  298. # =============================================================================
  299. # XML and Proxy Definition for GUI generation
  300. # =============================================================================
  301. def getProxyDomains(id):
  302. """
  303. Return a json based structured based on the proxy XML.
  304. """
  305. jsonDefinition = {}
  306. proxy = idToProxy(id)
  307. xmlElement = servermanager.ActiveConnection.Session.GetProxyDefinitionManager().GetCollapsedProxyDefinition(
  308. proxy.GetXMLGroup(), proxy.GetXMLName(), None
  309. )
  310. nbChildren = xmlElement.GetNumberOfNestedElements()
  311. for i in range(nbChildren):
  312. xmlChild = xmlElement.GetNestedElement(i)
  313. name = xmlChild.GetName()
  314. if name.__contains__("Property"):
  315. propName = xmlChild.GetAttribute("name")
  316. jsonDefinition[propName] = extractProperty(proxy, xmlChild)
  317. jsonDefinition[propName]["order"] = i
  318. # Look for proxy properties and their domain
  319. orderIndex = nbChildren
  320. for property in proxy.ListProperties():
  321. if property == "Input":
  322. continue
  323. if type(proxy.GetProperty(property)) == ProxyProperty:
  324. try:
  325. subProxyId = proxy.GetProperty(property).GetData().GetGlobalID()
  326. subDomain = getProxyDomains(subProxyId)
  327. for key in subDomain:
  328. jsonDefinition[key] = subDomain[key]
  329. jsonDefinition[key]["order"] = orderIndex
  330. orderIndex = orderIndex + 1
  331. except:
  332. print("(Def) Error on", property, ", skipping it...")
  333. # print ("(Def) Skip property: ", str(type(data)))
  334. return jsonDefinition
  335. def extractProperty(proxy, xmlPropertyElement):
  336. propInfo = {}
  337. propInfo["name"] = xmlPropertyElement.GetAttribute("name")
  338. propInfo["label"] = xmlPropertyElement.GetAttribute("label")
  339. if xmlPropertyElement.GetAttribute("number_of_elements") != None:
  340. propInfo["size"] = xmlPropertyElement.GetAttribute("number_of_elements")
  341. propInfo["type"] = xmlPropertyElement.GetName()[:-14]
  342. propInfo["panel_visibility"] = xmlPropertyElement.GetAttribute("panel_visibility")
  343. propInfo["number_of_elements"] = xmlPropertyElement.GetAttribute(
  344. "number_of_elements"
  345. )
  346. propInfo["domains"] = []
  347. if xmlPropertyElement.GetAttribute("default_values") != None:
  348. propInfo["default_values"] = xmlPropertyElement.GetAttribute("default_values")
  349. nbChildren = xmlPropertyElement.GetNumberOfNestedElements()
  350. for i in range(nbChildren):
  351. xmlChild = xmlPropertyElement.GetNestedElement(i)
  352. name = xmlChild.GetName()
  353. if name.__contains__("Domain"):
  354. propInfo["domains"].append(extractDomain(proxy, propInfo["name"], xmlChild))
  355. return propInfo
  356. def extractDomain(proxy, propertyName, xmlDomainElement):
  357. domainObj = {}
  358. name = xmlDomainElement.GetName()
  359. domainObj["type"] = name[:-6]
  360. # Handle Range
  361. if name.__contains__("RangeDomain"):
  362. if xmlDomainElement.GetAttribute("min") != None:
  363. domainObj["min"] = xmlDomainElement.GetAttribute("min")
  364. if xmlDomainElement.GetAttribute("max") != None:
  365. domainObj["max"] = xmlDomainElement.GetAttribute("max")
  366. # Handle Enum
  367. if name.__contains__("EnumerationDomain"):
  368. domainObj["enum"] = []
  369. nbChildren = xmlDomainElement.GetNumberOfNestedElements()
  370. for i in range(nbChildren):
  371. xmlChild = xmlDomainElement.GetNestedElement(i)
  372. if xmlChild.GetName() == "Entry":
  373. domainObj["enum"].append(
  374. {
  375. "text": xmlChild.GetAttribute("text"),
  376. "value": xmlChild.GetAttribute("value"),
  377. }
  378. )
  379. # Handle ArrayListDomain
  380. if name.__contains__("ArrayListDomain"):
  381. dataType = xmlDomainElement.GetAttribute("attribute_type")
  382. if dataType == "Scalars":
  383. domainObj["nb_components"] = 1
  384. elif dataType == "Vectors":
  385. domainObj["nb_components"] = 3
  386. else:
  387. domainObj["nb_components"] = -1
  388. # Handle ProxyListDomain
  389. if name.__contains__("ProxyListDomain"):
  390. domainObj["list"] = proxy.GetProperty(propertyName).Available
  391. # Handle Bounds
  392. if name.__contains__("BoundsDomain"):
  393. for attrName in ["default_mode", "mode", "scale_factor"]:
  394. try:
  395. attrValue = xmlDomainElement.GetAttribute(attrName)
  396. if attrValue:
  397. domainObj[attrName] = attrValue
  398. except:
  399. pass
  400. return domainObj
  401. # =============================================================================
  402. # File Management
  403. # =============================================================================
  404. def listFiles(pathToList):
  405. """
  406. Create a tree structure of the given directory that will be understand by
  407. the pipelineBrowser widget.
  408. The provided path should not have a trailing '/'.
  409. return {
  410. children: [
  411. { name: 'fileName.vtk', path: '/full_path/to_file/fileName.vtk' },
  412. { name: 'directoryName', path: '/full_path/to_file/directoryName', children: [] }
  413. ]
  414. }
  415. """
  416. global fileList
  417. if pathToList[-1] == "/":
  418. pathToList = pathToList[:-1]
  419. nodeTree = {}
  420. nodeTree[pathToList] = {"children": []}
  421. for path, directories, files in os.walk(pathToList):
  422. parent = nodeTree[path]
  423. for directory in directories:
  424. child = {
  425. "name": directory,
  426. "path": (path + "/" + directory),
  427. "children": [],
  428. }
  429. nodeTree[path + "/" + directory] = child
  430. parent["children"].append(child)
  431. for filename in files:
  432. child = {"name": filename, "path": (path + "/" + filename)}
  433. nodeTree[path + "/" + filename] = child
  434. parent["children"].append(child)
  435. fileList = nodeTree[pathToList]["children"]
  436. return fileList
  437. # =============================================================================
  438. # Apply domains
  439. # =============================================================================
  440. def apply_domains(parentProxy, proxy_id):
  441. """
  442. Handle bounds domain
  443. """
  444. proxy = idToProxy(proxy_id)
  445. # Call recursively on each sub-proxy if any
  446. for property_name in proxy.ListProperties():
  447. prop = proxy.GetProperty(property_name)
  448. if prop.IsA("vtkSMProxyProperty"):
  449. try:
  450. if len(prop.Available) and prop.GetNumberOfProxies() == 1:
  451. listdomain = prop.FindDomain("vtkSMProxyListDomain")
  452. if listdomain:
  453. for i in range(listdomain.GetNumberOfProxies()):
  454. internal_proxy = listdomain.GetProxy(i)
  455. apply_domains(
  456. parentProxy, internal_proxy.GetGlobalIDAsString()
  457. )
  458. except:
  459. exc_type, exc_obj, exc_tb = sys.exc_info()
  460. print("Unexpected error:", exc_type, " line: ", exc_tb.tb_lineno)
  461. # Reset all properties to leverage domain capabilities
  462. for prop_name in proxy.ListProperties():
  463. try:
  464. prop = proxy.GetProperty(prop_name)
  465. iter = prop.NewDomainIterator()
  466. iter.Begin()
  467. while not iter.IsAtEnd():
  468. domain = iter.GetDomain()
  469. iter.Next()
  470. try:
  471. if domain.IsA("vtkSMBoundsDomain"):
  472. domain.SetDomainValues(
  473. parentProxy.GetDataInformation().GetBounds()
  474. )
  475. except AttributeError as attrErr:
  476. print("Caught exception setting domain values in apply_domains:")
  477. print(attrErr)
  478. prop.ResetToDefault()
  479. # Need to UnRegister to handle the ref count from the NewDomainIterator
  480. iter.UnRegister(None)
  481. except:
  482. exc_type, exc_obj, exc_tb = sys.exc_info()
  483. print("Unexpected error:", exc_type, " line: ", exc_tb.tb_lineno)
  484. proxy.UpdateVTKObjects()