def setMarkerLocation(self, element: Element, xi: list):
     """
     If the annotation group is a created marker point, set its element:xi location.
     If the marker also has a materialCoordinatesField, it is updated to the value
     at the supplied element:xi location.
     :param element: Element to set location in
     :param xi: xi coordinates (list of float)
     """
     assert self._isMarker
     fieldmodule = self._group.getFieldmodule()
     mesh = get_highest_dimension_mesh(fieldmodule)
     assert mesh.containsElement(
         element), "Invalid element, not in highest dimension mesh"
     assert isinstance(xi, list) and (len(xi) >= mesh.getDimension())
     with ChangeManager(fieldmodule):
         markerLocation = getAnnotationMarkerLocationField(
             fieldmodule, mesh)
         fieldcache = fieldmodule.createFieldcache()
         nodes = fieldmodule.findNodesetByFieldDomainType(
             Field.DOMAIN_TYPE_NODES)
         markerNode = self.getNodesetGroup(
             nodes).createNodeiterator().next()
         fieldcache.setNode(markerNode)
         markerLocation.assignMeshLocation(fieldcache, element, xi)
         if self._markerMaterialCoordinatesField:
             fieldcache.setMeshLocation(element, xi)
             result, materialCoordinates = self._markerMaterialCoordinatesField.evaluateReal(
                 fieldcache,
                 self._markerMaterialCoordinatesField.getNumberOfComponents(
                 ))
             fieldcache.setNode(markerNode)
             self._markerMaterialCoordinatesField.assignReal(
                 fieldcache, materialCoordinates)
 def _markerFromDict(self, nodeIdentifier, markerDct: dict):
     """
     Define a new marker point node with nodeIdentifier and fields defined as in markerDct.
     Warn but do nothing if node with that identifier exists.
     :param nodeIdentifier:
     :param markerDct: A dict mapping names of fields to values, e.g.
     {
         "heart coordinates": [11.5, 16.2, 7.6],
         "marker_location": [5, [0.0, 0.0, 1.0]]
     }
     """
     assert not self._isMarker
     fieldmodule = self._group.getFieldmodule()
     nodes = fieldmodule.findNodesetByFieldDomainType(
         Field.DOMAIN_TYPE_NODES)
     node = nodes.findNodeByIdentifier(nodeIdentifier)
     if node.isValid():
         print("Error: Read annotation group " + self._name + ".  "\
               "Marker point node " + str(nodeIdentifier) + " already exists", file=sys.stderr)
         return
     mesh = get_highest_dimension_mesh(fieldmodule)
     if not mesh:
         print("Error: Read annotation group " + self._name +
               ".  Marker cannot be made for empty mesh",
               file=sys.stderr)
         return
     with ChangeManager(fieldmodule):
         materialCoordinatesField = None
         materialCoordinates = None
         element = None
         xi = None
         for key in markerDct.keys():
             if key != "marker_location":
                 fieldName = key
                 materialCoordinatesField = fieldmodule.findFieldByName(
                     fieldName).castFiniteElement()
                 materialCoordinates = markerDct[fieldName]
                 if materialCoordinatesField.isValid() and isinstance(
                         materialCoordinates, list):
                     break
                 print("Error: Read annotation group " + self._name + ".  " \
                       "Invalid marker material coordinates field " + fieldName + " or value.", file=sys.stderr)
                 materialCoordinatesField = None
                 materialCoordinates = None
                 break
         if not materialCoordinatesField:
             element_xi = markerDct.get("marker_location")
             if not element_xi:
                 print("Error: Read annotation group " + self._name + ".  " \
                       "Marker missing marker_location entry", file=sys.stderr)
                 return
             elementIdentifier, xi = element_xi
             element = mesh.findElementByIdentifier(elementIdentifier)
             if not element.isValid():
                 print("Error: Read annotation group " + self._name + ".  " \
                       "Marker element " + str(elementIdentifier) + " not found", file=sys.stderr)
                 return
         self.createMarkerNode(nodeIdentifier, materialCoordinatesField,
                               materialCoordinates, element, xi)
 def getMarkerLocation(self):
     """
     If the annotation is a created marker point, get its element:xi location.
     :return: Zinc Element, xi (list of float)
     """
     assert self._isMarker
     fieldmodule = self._group.getFieldmodule()
     mesh = get_highest_dimension_mesh(fieldmodule)
     markerLocation = getAnnotationMarkerLocationField(fieldmodule, mesh)
     fieldcache = fieldmodule.createFieldcache()
     nodes = fieldmodule.findNodesetByFieldDomainType(
         Field.DOMAIN_TYPE_NODES)
     markerNode = self.getNodesetGroup(nodes).createNodeiterator().next()
     fieldcache.setNode(markerNode)
     element, xi = markerLocation.evaluateMeshLocation(
         fieldcache, mesh.getDimension())
     if not isinstance(xi, list):
         xi = [xi]  # workaround for Zinc 1-D xi being a plain float
     return element, xi
 def setMarkerMaterialCoordinates(self,
                                  materialCoordinatesField,
                                  materialCoordinates=None):
     """
     Also updates the marker location when this is assigned, forcing it to be within the mesh.
     The material coordinates are then recalculated to be in the mesh.
     Some approximations may occur if the point is outside the mesh - user beware.
     :param materialCoordinatesField: Material coordinates field to set or change to, or None to remove
     material coordinates field so marker point only has an element:xi location. Must be defined on elements
     of highest dimension mesh.
     :param materialCoordinates: If None, evaluate materialCoordinatesField at current marker location.
     """
     assert self._isMarker
     if not (self._markerMaterialCoordinatesField
             or materialCoordinatesField):
         return
     fieldmodule = self._group.getFieldmodule()
     mesh = get_highest_dimension_mesh(fieldmodule)
     nodes = fieldmodule.findNodesetByFieldDomainType(
         Field.DOMAIN_TYPE_NODES)
     markerNode = self.getNodesetGroup(nodes).createNodeiterator().next()
     with ChangeManager(fieldmodule):
         oldMaterialCoordinatesField = self._markerMaterialCoordinatesField
         if materialCoordinatesField != oldMaterialCoordinatesField:
             nodetemplate = nodes.createNodetemplate()
             if self._markerMaterialCoordinatesField:
                 assert RESULT_OK == nodetemplate.undefineField(
                     self._markerMaterialCoordinatesField)
             if materialCoordinatesField:
                 assert RESULT_OK == nodetemplate.defineField(
                     materialCoordinatesField)
             assert RESULT_OK == markerNode.merge(nodetemplate)
             self._markerMaterialCoordinatesField = materialCoordinatesField
         if materialCoordinatesField:
             if materialCoordinates is not None:
                 # find nearest location in mesh
                 constCoordinates = fieldmodule.createFieldConstant(
                     materialCoordinates)
                 findMeshLocation = fieldmodule.createFieldFindMeshLocation(
                     constCoordinates, materialCoordinatesField, mesh)
                 fieldcache = fieldmodule.createFieldcache()
                 fieldcache.setNode(markerNode)
                 element, xi = findMeshLocation.evaluateMeshLocation(
                     fieldcache, mesh.getDimension())
                 if not element.isValid():
                     self.setMarkerMaterialCoordinates(
                         oldMaterialCoordinatesField)
                     print(
                         "AnnotationGroup setMarkerMaterialCoordinates.  Field is not defined on mesh. Reverting."
                     )
                     return
                 if not isinstance(xi, list):
                     xi = [
                         xi
                     ]  # workaround for Zinc 1-D xi being a plain float
                 del findMeshLocation
                 del constCoordinates
             else:
                 element, xi = self.getMarkerLocation()
             # use this function to reassign material coordinates to be within mesh
             self.setMarkerLocation(element, xi)
 def createMarkerNode(self,
                      startNodeIdentifier=1,
                      materialCoordinatesField: FieldFiniteElement = None,
                      materialCoordinates=None,
                      element=None,
                      xi=[0.0, 0.0, 0.0]):
     """
     Convert annotation group into a marker point annotation.
     Important: annotation group must currently be empty, and elements must exist.
     The marker node is added to the marker group in addition to this group.
     Raises an exception if marker creation cannot be achieved.
     :param startNodeIdentifier: First unused node identifier >= this may use for marker node. Incremented until
     an unused node identifier is found for the marker node.
     :param materialCoordinatesField: Material coordinates field to define location of marker point in.
     Must be a finite element type field for which isTypeCoordinates() is True, with up to 3 components,
     and at least as many components as the highest mesh dimension.
     Only one of materialCoordinatesField or element may be specified.
     :param materialCoordinates: The coordinates to assign to the materialCoordinatesField, if field supplied.
     The element:xi coordinates are computed from it.
     :param element: Optional element to set initial location from; must be in highest dimension mesh.
     Only one of materialCoordinatesField or element may be specified.
     If neither is specified the first element in the highest dimension mesh is used.
     :param xi: If element is supplied or first is assumed, the xi coordinates to embed at.
     :return: Zinc Node representing marker point, with either default location in first element or that supplied.
     """
     assert not self._isMarker
     assert self._group.isEmpty(
     ), "Can only create marker in empty annotation group"
     fieldmodule = self._group.getFieldmodule()
     mesh = get_highest_dimension_mesh(fieldmodule)
     assert mesh, "Can only create marker point if there is a mesh with elements"
     assert not (element and materialCoordinatesField)
     if materialCoordinatesField:
         coordinatesCount = materialCoordinatesField.getNumberOfComponents()
         assert materialCoordinates and (len(materialCoordinates) >= coordinatesCount) and \
                materialCoordinatesField.castFiniteElement().isValid() and \
                materialCoordinatesField.isTypeCoordinate() and (mesh.getDimension() <= coordinatesCount <= 3)
     nodes = fieldmodule.findNodesetByFieldDomainType(
         Field.DOMAIN_TYPE_NODES)
     nodeIdentifier = get_next_unused_node_identifier(
         nodes, startNodeIdentifier)
     with ChangeManager(fieldmodule):
         markerGroup = getAnnotationMarkerGroup(fieldmodule)
         markerNodeGroup = markerGroup.getFieldNodeGroup(nodes)
         if not markerNodeGroup.isValid():
             markerNodeGroup = markerGroup.createFieldNodeGroup(nodes)
         markerNodesetGroup = markerNodeGroup.getNodesetGroup()
         markerLocation = getAnnotationMarkerLocationField(
             fieldmodule, mesh)
         markerName = getAnnotationMarkerNameField(fieldmodule)
         nodetemplate = nodes.createNodetemplate()
         if materialCoordinatesField:
             assert RESULT_OK == nodetemplate.defineField(
                 materialCoordinatesField)
         assert RESULT_OK == nodetemplate.defineField(markerLocation)
         assert RESULT_OK == nodetemplate.defineField(markerName)
         markerNode = nodes.createNode(nodeIdentifier, nodetemplate)
         assert RESULT_OK == self.getNodesetGroup(nodes).addNode(markerNode)
         assert RESULT_OK == markerNodesetGroup.addNode(markerNode)
         self._isMarker = True
         self._markerGroup = markerGroup  # maintain reference so group is not destroyed
         # assign marker name to be same as this group's name. This needs to be maintained. See setName()
         fieldcache = fieldmodule.createFieldcache()
         fieldcache.setNode(markerNode)
         markerName.assignString(fieldcache, self._name)
         if materialCoordinatesField:
             self.setMarkerMaterialCoordinates(materialCoordinatesField,
                                               materialCoordinates)
         else:
             if not element:
                 element = mesh.createElementiterator().next()
             self.setMarkerLocation(element, xi)
     return markerNode