Module uim.model.semantics.node
Expand source code
# -*- coding: utf-8 -*-
# Copyright © 2021 Wacom Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import functools
import uuid
from abc import ABC, abstractmethod
from typing import List, Any, Optional
from typing import Tuple
from uim.codec.parser.base import SupportedFormats
from uim.model.base import UUIDIdentifier, InkModelException
from uim.model.inkdata.strokes import Stroke
from uim.model.semantics.structures import BoundingBox
from uim.model.semantics.syntax import CommonViews
class URIBuilder(ABC):
"""
Generates URIs according to the ink model URI scheme.
"""
SCHEME: str = "uim:"
def __init__(self):
pass
@staticmethod
def build_uri(sub_path: str, model_id: uuid.UUID = None):
"""
Build a URI for a model.
Parameters
----------
sub_path: str
Sub path.
model_id: UUID
Unique ID of the model.
Returns
-------
uri - `str`
Model URI
"""
uri: str = URIBuilder.SCHEME
if model_id is not None:
uri += f'{str(model_id)}/'
uri += f'{sub_path}/'
return uri
@staticmethod
def build_named_entity_uri(uimid: uuid.UUID, model_id: uuid.UUID = None) -> str:
"""Creates a URI for the specified named entity identifier.
Parameters
----------
uimid: `UUID`
UUID of a node
model_id: UUID
ID of the model [optional]
Returns
-------
uri: str
URI for a named entity
"""
if not isinstance(uimid, uuid.UUID):
raise InkModelException("The named entity identifier should be a valid UUID.")
return URIBuilder.build_uri('ne', model_id) + str(uimid)
@staticmethod
def build_entity_uri(uimid: uuid.UUID, model_id: uuid.UUID = None) -> str:
"""
Creates a URI for the specified entity view identifier.
Parameters
----------
uimid: `UUID`
UUID of a node
model_id: UUID
ID of the model [optional]
Returns
-------
uri: str
URI for an entity
"""
if not isinstance(uimid, uuid.UUID):
raise InkModelException("The named entity identifier should be a valid UUID.")
return URIBuilder.build_uri('', model_id) + str(uimid)
@staticmethod
def build_node_uri_from(node_uuid: uuid.UUID, view_name: str,
uri_format: SupportedFormats = SupportedFormats.UIM_VERSION_3_1_0) -> str:
"""
Creates a URI for a node in a view.
Parameters
----------
node_uuid: `UUID`
UUID of a node
view_name: `str`
Name of the view
uri_format: `SupportedFormats'
Target format
Returns
-------
uri: str
URI for an node within a specific view
"""
node_uri: str = URIBuilder.build_uri('node')
if view_name == CommonViews.LEGACY_HWR_VIEW.value:
node_uri += 'hwr/' if uri_format == SupportedFormats.UIM_VERSION_3_1_0 else ''
elif view_name == CommonViews.LEGACY_NER_VIEW.value:
node_uri += 'ner/' if uri_format == SupportedFormats.UIM_VERSION_3_1_0 else ''
else:
node_uri += f'{view_name}/'
node_uri += f'{node_uuid}'
return node_uri
@staticmethod
def build_node_uri(ink_node: 'InkNode', uri_format: SupportedFormats) -> str:
"""
Creates a URI for an ink node.
Parameters
----------
ink_node: `InkNode`
Node in a tree
uri_format: `SupportedFormats`
URI format
Returns
-------
uri - `str`
Build a URI for the ink node
"""
if isinstance(ink_node, StrokeGroupNode):
return URIBuilder.build_node_uri_from(ink_node.id, ink_node.view_name, uri_format)
elif isinstance(ink_node, StrokeNode):
stroke_node: StrokeNode = ink_node
node_uri: str = URIBuilder.build_node_uri_from(stroke_node.stroke.id, stroke_node.view_name, uri_format)
if stroke_node.fragment:
node_uri += f'#frag={stroke_node.fragment.from_point_index},{stroke_node.fragment.to_point_index}'
return node_uri
class InkNode(UUIDIdentifier):
"""
c
Node - the node message. Used for the definition of tree-context.
The ink tree is built with a generic node structure. For building the tree the depth attribute reflects the
depth within the tree. For serialization of the tree structure, the depth first pre-order tree serialization is
applied.
Each node has an unique identifier id (uri) which is relevant for the semantic statements as an identifier for the
subject. The groupBoundingBox is optional for `StrokeGroupNode`s and assists with easier visual debugging or
to highlight the relevant area for clickable options.
Parameters
----------
node_id: `UUID`
Node ID as identifier.
:param group_bounding_box: Rectangle -
Bounding box (Group nodes only)
"""
def __init__(self, node_id: uuid.UUID, group_bounding_box: BoundingBox = None):
super(UUIDIdentifier, self).__init__(node_id)
self.__id: uuid.UUID = node_id
self.__group_bounding_box: BoundingBox = group_bounding_box
self.__parent: Optional[StrokeGroupNode] = None
self.__tree: 'InkTree' = None
self.__transient_tag = None
@property
def transient_tag(self) -> str:
"""Transient tag of the node. (`str`)"""
return self.__transient_tag
@transient_tag.setter
def transient_tag(self, value):
self.__transient_tag = value
@property
def tree(self) -> 'InkTree':
"""Reference to the respective `InkTree`. (`InkTree`, read-only)"""
if self.__tree is None and not self.is_root():
self.__tree = self.parent.tree
return self.__tree
@tree.setter
def tree(self, value: 'InkTree'):
self.__tree = value
@property
def root(self) -> 'InkNode':
"""Reference to the root node (`InkNode`) of the `InkTree`. (`InkNode`, read-only)"""
self.__assert_assigned_to_a_tree__()
return self.__tree.root
@property
def parent(self):
"""Reference to the parent node (`InkNode`) of the `InkTree`. (`InkNode`, read-only)"""
return self.__parent
def is_root(self) -> bool:
"""
Check if the node is the root node.
Returns
-------
flag: bool
Flag if the `InkNode` is a root node
"""
return self.__parent is None
@property
def view_name(self) -> str:
"""Name of the associated view. (`str`, read-only)"""
self.__assert_assigned_to_a_tree__()
return self.__tree.name
@property
def uri(self) -> str:
"""URI according to UIM v3.1.0 specification. (`str`, read-only)"""
return self.__generate_uri__()
@property
def uri_legacy(self) -> str:
"""URI according to UIM v3.0.0 specification. (`str`, read-only)"""
return f'uim:node/{self.id}'
@property
def group_bounding_box(self) -> BoundingBox:
"""Bounding box (`StrokeGroupNode`s only). (`str`)"""
return self.__group_bounding_box
@group_bounding_box.setter
def group_bounding_box(self, bbox: BoundingBox):
self.__group_bounding_box = bbox
@abstractmethod
def __generate_uri__(self) -> str:
raise NotImplementedError()
@abstractmethod
def child_nodes_count(self) -> int:
""""
Counts the number of child `InkNode`s.
Returns
-------
number: int
Number of child nodes
"""
pass
def is_assigned_to_a_tree(self) -> bool:
"""
Check if the Node is assigned to a tree.
Returns
-------
assigned: bool
Flag if the Node is assigned to a tree
"""
return self.tree is not None
def __assert_not_owned__(self):
"""
Assert that the node is not assigned to tree.
Raises
------
InkModelException
If `InkNode` already assigned to a tree
"""
if self.is_assigned_to_a_tree():
raise InkModelException('Node already assigned to a tree.')
pass
def __assert_assigned_to_a_tree__(self):
"""
Assert that the node is not assigned to a tree.
Raises
------
InkModelException
If Node not assigned to a tree yet.
"""
if not self.is_assigned_to_a_tree():
raise InkModelException("Node not yet assigned to a tree.")
def __repr__(self):
return '<Node: [id:={}, uri:={}]>'.format(self.id, self.uri)
class StrokeFragment(ABC):
"""
StrokeFragment
==============
Denotes a stroke fragment, to reference fragments of the stroke. Fragments can be used for defining semantic
statements, for instance characters within a word, which requires to assign semantics only on a fragment of
the stroke.
Parameters
----------
from_point_index: int
The index of the first path point, which is relevant for this node.
to_point_index: int
The index of the last path point, which is relevant for this node.
from_t_value: int
The t parameter value of the first point of this node.
to_t_value: int
The t parameter value of the last point of this node.
"""
def __init__(self, from_point_index: int, to_point_index: int, from_t_value: float, to_t_value: float):
if from_point_index < 0:
raise ValueError(". The value of from_point_index must be non-negative")
if to_point_index < from_point_index:
raise ValueError("The value of to_point_index must be greater or equal to from_point_index")
if from_t_value < 0. or from_t_value >= 1.:
raise ValueError("The value of from_t_value must be in the interval [0, 1)")
if (to_t_value <= from_t_value) or (to_t_value > 1.):
raise ValueError("The value of to_t_value must be in the interval (fromTValue, 1]")
self.__from_point_index: int = from_point_index
self.__to_point_index: int = to_point_index
self.__from_t_value: float = from_t_value
self.__to_t_value: float = to_t_value
@property
def from_point_index(self) -> int:
"""Gets the index of the first path point of this node. (`int`)"""
return self.__from_point_index
@from_point_index.setter
def from_point_index(self, value: int):
self.__from_point_index = value
@property
def to_point_index(self) -> int:
"""Gets the index of the last path point of this node. (`int`)"""
return self.__to_point_index
@to_point_index.setter
def to_point_index(self, value: int):
self.__to_point_index = value
@property
def from_t_value(self) -> float:
"""Gets the t parameter value of the first point of this node. (`int`)"""
return self.__from_t_value
@from_t_value.setter
def from_t_value(self, value: float):
self.__from_t_value = value
@property
def to_t_value(self) -> float:
"""Gets the t parameter value of the last point of this node. (`int`)"""
return self.__to_t_value
@to_t_value.setter
def to_t_value(self, value: float):
self.__to_t_value = value
class StrokeNode(InkNode):
"""
StrokeNode
==========
Represents an ´InkNode´ that refers to a Stroke object.
A `StrokeNode` can represent either a whole path or part of a path within the ink model.
Parameters
----------
stroke: `Stroke`
Stroke which is referenced
fragment: `StrokeFragment`
Fragment referencing only parts of the `Stroke`
Examples
--------
>>> from uim.model.ink import InkModel, InkTree
>>> from uim.model.semantics.node import StrokeGroupNode, StrokeNode, StrokeFragment, URIBuilder
>>> # Create the model
>>> ink_model: InkModel = InkModel()
>>> # Assign the group as the root of the main ink tree
>>> ink_model.ink_tree = InkTree()
>>> # First you need a root group to contain the strokes
>>> root: StrokeGroupNode = StrokeGroupNode(UUIDIdentifier.id_generator())
>>> ink_model.ink_tree.root = root
>>>
>>> # Add a node for stroke 0
>>> stroke_node_0: StrokeNode = StrokeNode(stroke_0, StrokeFragment(0, 1, 0.0, 1.0))
>>> root.add(stroke_node_0)
>>>
>>> # Add a node for stroke 1
>>> root.add(StrokeNode(stroke_1, StrokeFragment(0, 1, 0.0, 1.0)))
"""
def __init__(self, stroke: Stroke, fragment: StrokeFragment = None):
super().__init__(node_id=stroke.id)
self.__ref_stroke: Stroke = stroke
self.__fragment: StrokeFragment = fragment
@property
def stroke(self) -> Stroke:
"""References the strokes. (`Stroke`)"""
return self.__ref_stroke
@stroke.setter
def stroke(self, stroke: Stroke):
self.__ref_stroke = stroke
@property
def fragment(self) -> StrokeFragment:
"""`StrokeFragment` that specifies a fragment of the stroke. (`StrokeFragment`)
Notes
-----
If the property value is not null, the stroke node refers to the specified fragment of the stroke.
"""
return self.__fragment
@fragment.setter
def fragment(self, fragment: StrokeFragment):
self.__fragment = fragment
def child_nodes_count(self) -> int:
"""
Number of child nodes.
Returns
-------
num_child_nodes: int
number of children nodes
"""
return 0
def __generate_uri__(self):
return URIBuilder().build_node_uri(self, SupportedFormats.UIM_VERSION_3_1_0)
def __repr__(self):
if self.stroke:
return '<StrokeNode: [stroke id:={}]>'.format(self.stroke.id if self.stroke is not None else '')
class StrokeGroupNode(InkNode):
"""
StrokeGroupNode
===============
A non-leaf node, used to group ink-nodes of type `StrokeNode` and/or `StrokeGroupNode`.
Parameters
----------
uim_id: `UUID`
Identifier of this stroke node.
"""
def __init__(self, uim_id: uuid.UUID):
super().__init__(node_id=uim_id)
self.__children: List[InkNode] = []
def add(self, node: InkNode) -> InkNode:
"""
Adds a child node to this group.
Parameters
-----------
node: `InkNode`
The child node to be added.
Raises
------
InkModelException
If `InkNode` already assigned to a tree or trying to add an ink node as a child, which has already a parent.
"""
node.__assert_not_owned__()
if node.parent is not None:
raise InkModelException(f"Trying to add an ink node as a child, which has already a parent. Node: {node}")
node._InkNode__parent = self
self.__children.append(node)
if node.is_assigned_to_a_tree():
self.tree.register_sub_tree(node)
return node
def child_nodes_count(self) -> int:
"""
Number of child nodes.
Returns
-------
number_of_child_nodes: `int`
Number of child nodes
"""
return len(self.__children)
def child_group_nodes_count(self) -> int:
"""
Number of child group nodes.
Returns
-------
number_of_child_nodes: `int`
Number of child group nodes
"""
count: int = 0
if self.child_nodes_count() > 0:
for n in self.__children:
count = count + 1 if type(n) == StrokeGroupNode else 0
return count
def child_stroke_nodes_count(self) -> int:
"""
Number of child stroke nodes.
Returns
-------
number_of_child_nodes: `int`
Number of child stroke group nodes
"""
count: int = 0
if self.child_nodes_count() > 0:
for n in self.__children:
count = count + 1 if type(n) == StrokeNode else 0
return count
def sort_children(self, lambda_sort_func: Any, reverse: bool = False):
"""
Sorts the children based on a sorting function.
Parameters
----------
lambda_sort_func: Any
Sorting function for children.
reverse: bool
Flag for reversed order [default:=False]
"""
self.__children = sorted(self.__children, key=functools.cmp_to_key(lambda_sort_func), reverse=reverse)
@property
def children(self) -> Tuple[InkNode]:
"""Children of the node. (`Tuple[InkNode]`, read-only)"""
return tuple(self.__children)
def __generate_uri__(self, uri_format: SupportedFormats = SupportedFormats.UIM_VERSION_3_1_0) -> str:
return URIBuilder().build_node_uri(self, uri_format)
def __repr__(self):
return '<StrokeGroupNode: [uri:={}, children:={}]>'.format(self.uri, len(self.children))
Classes
class InkNode (node_id: uuid.UUID, group_bounding_box: BoundingBox = None)
-
c Node - the node message. Used for the definition of tree-context.
The ink tree is built with a generic node structure. For building the tree the depth attribute reflects the depth within the tree. For serialization of the tree structure, the depth first pre-order tree serialization is applied. Each node has an unique identifier id (uri) which is relevant for the semantic statements as an identifier for the subject. The groupBoundingBox is optional for <code><a title="uim.model.semantics.node.StrokeGroupNode" href="#uim.model.semantics.node.StrokeGroupNode">StrokeGroupNode</a></code>s and assists with easier visual debugging or to highlight the relevant area for clickable options. Parameters ---------- node_id: <code>UUID</code> Node ID as identifier. :param group_bounding_box: Rectangle - Bounding box (Group nodes only)
Expand source code
class InkNode(UUIDIdentifier): """ c Node - the node message. Used for the definition of tree-context. The ink tree is built with a generic node structure. For building the tree the depth attribute reflects the depth within the tree. For serialization of the tree structure, the depth first pre-order tree serialization is applied. Each node has an unique identifier id (uri) which is relevant for the semantic statements as an identifier for the subject. The groupBoundingBox is optional for `StrokeGroupNode`s and assists with easier visual debugging or to highlight the relevant area for clickable options. Parameters ---------- node_id: `UUID` Node ID as identifier. :param group_bounding_box: Rectangle - Bounding box (Group nodes only) """ def __init__(self, node_id: uuid.UUID, group_bounding_box: BoundingBox = None): super(UUIDIdentifier, self).__init__(node_id) self.__id: uuid.UUID = node_id self.__group_bounding_box: BoundingBox = group_bounding_box self.__parent: Optional[StrokeGroupNode] = None self.__tree: 'InkTree' = None self.__transient_tag = None @property def transient_tag(self) -> str: """Transient tag of the node. (`str`)""" return self.__transient_tag @transient_tag.setter def transient_tag(self, value): self.__transient_tag = value @property def tree(self) -> 'InkTree': """Reference to the respective `InkTree`. (`InkTree`, read-only)""" if self.__tree is None and not self.is_root(): self.__tree = self.parent.tree return self.__tree @tree.setter def tree(self, value: 'InkTree'): self.__tree = value @property def root(self) -> 'InkNode': """Reference to the root node (`InkNode`) of the `InkTree`. (`InkNode`, read-only)""" self.__assert_assigned_to_a_tree__() return self.__tree.root @property def parent(self): """Reference to the parent node (`InkNode`) of the `InkTree`. (`InkNode`, read-only)""" return self.__parent def is_root(self) -> bool: """ Check if the node is the root node. Returns ------- flag: bool Flag if the `InkNode` is a root node """ return self.__parent is None @property def view_name(self) -> str: """Name of the associated view. (`str`, read-only)""" self.__assert_assigned_to_a_tree__() return self.__tree.name @property def uri(self) -> str: """URI according to UIM v3.1.0 specification. (`str`, read-only)""" return self.__generate_uri__() @property def uri_legacy(self) -> str: """URI according to UIM v3.0.0 specification. (`str`, read-only)""" return f'uim:node/{self.id}' @property def group_bounding_box(self) -> BoundingBox: """Bounding box (`StrokeGroupNode`s only). (`str`)""" return self.__group_bounding_box @group_bounding_box.setter def group_bounding_box(self, bbox: BoundingBox): self.__group_bounding_box = bbox @abstractmethod def __generate_uri__(self) -> str: raise NotImplementedError() @abstractmethod def child_nodes_count(self) -> int: """" Counts the number of child `InkNode`s. Returns ------- number: int Number of child nodes """ pass def is_assigned_to_a_tree(self) -> bool: """ Check if the Node is assigned to a tree. Returns ------- assigned: bool Flag if the Node is assigned to a tree """ return self.tree is not None def __assert_not_owned__(self): """ Assert that the node is not assigned to tree. Raises ------ InkModelException If `InkNode` already assigned to a tree """ if self.is_assigned_to_a_tree(): raise InkModelException('Node already assigned to a tree.') pass def __assert_assigned_to_a_tree__(self): """ Assert that the node is not assigned to a tree. Raises ------ InkModelException If Node not assigned to a tree yet. """ if not self.is_assigned_to_a_tree(): raise InkModelException("Node not yet assigned to a tree.") def __repr__(self): return '<Node: [id:={}, uri:={}]>'.format(self.id, self.uri)
Ancestors
- UUIDIdentifier
- Identifier
- abc.ABC
Subclasses
Class variables
var SEPARATOR : str
Instance variables
var group_bounding_box : BoundingBox
-
Bounding box (
StrokeGroupNode
s only). (str
)Expand source code
@property def group_bounding_box(self) -> BoundingBox: """Bounding box (`StrokeGroupNode`s only). (`str`)""" return self.__group_bounding_box
var parent
-
Expand source code
@property def parent(self): """Reference to the parent node (`InkNode`) of the `InkTree`. (`InkNode`, read-only)""" return self.__parent
var root : InkNode
-
Expand source code
@property def root(self) -> 'InkNode': """Reference to the root node (`InkNode`) of the `InkTree`. (`InkNode`, read-only)""" self.__assert_assigned_to_a_tree__() return self.__tree.root
var transient_tag : str
-
Transient tag of the node. (
str
)Expand source code
@property def transient_tag(self) -> str: """Transient tag of the node. (`str`)""" return self.__transient_tag
var tree : InkTree
-
Reference to the respective
InkTree
. (InkTree
, read-only)Expand source code
@property def tree(self) -> 'InkTree': """Reference to the respective `InkTree`. (`InkTree`, read-only)""" if self.__tree is None and not self.is_root(): self.__tree = self.parent.tree return self.__tree
var uri : str
-
URI according to UIM v3.1.0 specification. (
str
, read-only)Expand source code
@property def uri(self) -> str: """URI according to UIM v3.1.0 specification. (`str`, read-only)""" return self.__generate_uri__()
var uri_legacy : str
-
URI according to UIM v3.0.0 specification. (
str
, read-only)Expand source code
@property def uri_legacy(self) -> str: """URI according to UIM v3.0.0 specification. (`str`, read-only)""" return f'uim:node/{self.id}'
var view_name : str
-
Name of the associated view. (
str
, read-only)Expand source code
@property def view_name(self) -> str: """Name of the associated view. (`str`, read-only)""" self.__assert_assigned_to_a_tree__() return self.__tree.name
Methods
def child_nodes_count(self) ‑> int
-
Expand source code
@abstractmethod def child_nodes_count(self) -> int: """" Counts the number of child `InkNode`s. Returns ------- number: int Number of child nodes """ pass
def is_assigned_to_a_tree(self) ‑> bool
-
Check if the Node is assigned to a tree.
Returns
assigned
:bool
- Flag if the Node is assigned to a tree
Expand source code
def is_assigned_to_a_tree(self) -> bool: """ Check if the Node is assigned to a tree. Returns ------- assigned: bool Flag if the Node is assigned to a tree """ return self.tree is not None
def is_root(self) ‑> bool
-
Expand source code
def is_root(self) -> bool: """ Check if the node is the root node. Returns ------- flag: bool Flag if the `InkNode` is a root node """ return self.__parent is None
Inherited members
class StrokeFragment (from_point_index: int, to_point_index: int, from_t_value: float, to_t_value: float)
-
StrokeFragment
Denotes a stroke fragment, to reference fragments of the stroke. Fragments can be used for defining semantic statements, for instance characters within a word, which requires to assign semantics only on a fragment of the stroke.
Parameters
from_point_index
:int
- The index of the first path point, which is relevant for this node.
to_point_index
:int
- The index of the last path point, which is relevant for this node.
from_t_value
:int
- The t parameter value of the first point of this node.
to_t_value
:int
- The t parameter value of the last point of this node.
Expand source code
class StrokeFragment(ABC): """ StrokeFragment ============== Denotes a stroke fragment, to reference fragments of the stroke. Fragments can be used for defining semantic statements, for instance characters within a word, which requires to assign semantics only on a fragment of the stroke. Parameters ---------- from_point_index: int The index of the first path point, which is relevant for this node. to_point_index: int The index of the last path point, which is relevant for this node. from_t_value: int The t parameter value of the first point of this node. to_t_value: int The t parameter value of the last point of this node. """ def __init__(self, from_point_index: int, to_point_index: int, from_t_value: float, to_t_value: float): if from_point_index < 0: raise ValueError(". The value of from_point_index must be non-negative") if to_point_index < from_point_index: raise ValueError("The value of to_point_index must be greater or equal to from_point_index") if from_t_value < 0. or from_t_value >= 1.: raise ValueError("The value of from_t_value must be in the interval [0, 1)") if (to_t_value <= from_t_value) or (to_t_value > 1.): raise ValueError("The value of to_t_value must be in the interval (fromTValue, 1]") self.__from_point_index: int = from_point_index self.__to_point_index: int = to_point_index self.__from_t_value: float = from_t_value self.__to_t_value: float = to_t_value @property def from_point_index(self) -> int: """Gets the index of the first path point of this node. (`int`)""" return self.__from_point_index @from_point_index.setter def from_point_index(self, value: int): self.__from_point_index = value @property def to_point_index(self) -> int: """Gets the index of the last path point of this node. (`int`)""" return self.__to_point_index @to_point_index.setter def to_point_index(self, value: int): self.__to_point_index = value @property def from_t_value(self) -> float: """Gets the t parameter value of the first point of this node. (`int`)""" return self.__from_t_value @from_t_value.setter def from_t_value(self, value: float): self.__from_t_value = value @property def to_t_value(self) -> float: """Gets the t parameter value of the last point of this node. (`int`)""" return self.__to_t_value @to_t_value.setter def to_t_value(self, value: float): self.__to_t_value = value
Ancestors
- abc.ABC
Instance variables
var from_point_index : int
-
Gets the index of the first path point of this node. (
int
)Expand source code
@property def from_point_index(self) -> int: """Gets the index of the first path point of this node. (`int`)""" return self.__from_point_index
var from_t_value : float
-
Gets the t parameter value of the first point of this node. (
int
)Expand source code
@property def from_t_value(self) -> float: """Gets the t parameter value of the first point of this node. (`int`)""" return self.__from_t_value
var to_point_index : int
-
Gets the index of the last path point of this node. (
int
)Expand source code
@property def to_point_index(self) -> int: """Gets the index of the last path point of this node. (`int`)""" return self.__to_point_index
var to_t_value : float
-
Gets the t parameter value of the last point of this node. (
int
)Expand source code
@property def to_t_value(self) -> float: """Gets the t parameter value of the last point of this node. (`int`)""" return self.__to_t_value
class StrokeGroupNode (uim_id: uuid.UUID)
-
StrokeGroupNode
A non-leaf node, used to group ink-nodes of type
StrokeNode
and/orStrokeGroupNode
.Parameters
uim_id
:UUID
- Identifier of this stroke node.
Expand source code
class StrokeGroupNode(InkNode): """ StrokeGroupNode =============== A non-leaf node, used to group ink-nodes of type `StrokeNode` and/or `StrokeGroupNode`. Parameters ---------- uim_id: `UUID` Identifier of this stroke node. """ def __init__(self, uim_id: uuid.UUID): super().__init__(node_id=uim_id) self.__children: List[InkNode] = [] def add(self, node: InkNode) -> InkNode: """ Adds a child node to this group. Parameters ----------- node: `InkNode` The child node to be added. Raises ------ InkModelException If `InkNode` already assigned to a tree or trying to add an ink node as a child, which has already a parent. """ node.__assert_not_owned__() if node.parent is not None: raise InkModelException(f"Trying to add an ink node as a child, which has already a parent. Node: {node}") node._InkNode__parent = self self.__children.append(node) if node.is_assigned_to_a_tree(): self.tree.register_sub_tree(node) return node def child_nodes_count(self) -> int: """ Number of child nodes. Returns ------- number_of_child_nodes: `int` Number of child nodes """ return len(self.__children) def child_group_nodes_count(self) -> int: """ Number of child group nodes. Returns ------- number_of_child_nodes: `int` Number of child group nodes """ count: int = 0 if self.child_nodes_count() > 0: for n in self.__children: count = count + 1 if type(n) == StrokeGroupNode else 0 return count def child_stroke_nodes_count(self) -> int: """ Number of child stroke nodes. Returns ------- number_of_child_nodes: `int` Number of child stroke group nodes """ count: int = 0 if self.child_nodes_count() > 0: for n in self.__children: count = count + 1 if type(n) == StrokeNode else 0 return count def sort_children(self, lambda_sort_func: Any, reverse: bool = False): """ Sorts the children based on a sorting function. Parameters ---------- lambda_sort_func: Any Sorting function for children. reverse: bool Flag for reversed order [default:=False] """ self.__children = sorted(self.__children, key=functools.cmp_to_key(lambda_sort_func), reverse=reverse) @property def children(self) -> Tuple[InkNode]: """Children of the node. (`Tuple[InkNode]`, read-only)""" return tuple(self.__children) def __generate_uri__(self, uri_format: SupportedFormats = SupportedFormats.UIM_VERSION_3_1_0) -> str: return URIBuilder().build_node_uri(self, uri_format) def __repr__(self): return '<StrokeGroupNode: [uri:={}, children:={}]>'.format(self.uri, len(self.children))
Ancestors
- InkNode
- UUIDIdentifier
- Identifier
- abc.ABC
Class variables
var SEPARATOR : str
Instance variables
var children : Tuple[InkNode]
-
Children of the node. (
Tuple[InkNode]
, read-only)Expand source code
@property def children(self) -> Tuple[InkNode]: """Children of the node. (`Tuple[InkNode]`, read-only)""" return tuple(self.__children)
Methods
def add(self, node: InkNode) ‑> InkNode
-
Adds a child node to this group.
Parameters
node
:InkNode
- The child node to be added.
Raises
InkModelException
- If
InkNode
already assigned to a tree or trying to add an ink node as a child, which has already a parent.
Expand source code
def add(self, node: InkNode) -> InkNode: """ Adds a child node to this group. Parameters ----------- node: `InkNode` The child node to be added. Raises ------ InkModelException If `InkNode` already assigned to a tree or trying to add an ink node as a child, which has already a parent. """ node.__assert_not_owned__() if node.parent is not None: raise InkModelException(f"Trying to add an ink node as a child, which has already a parent. Node: {node}") node._InkNode__parent = self self.__children.append(node) if node.is_assigned_to_a_tree(): self.tree.register_sub_tree(node) return node
def child_group_nodes_count(self) ‑> int
-
Number of child group nodes.
Returns
number_of_child_nodes
:int
- Number of child group nodes
Expand source code
def child_group_nodes_count(self) -> int: """ Number of child group nodes. Returns ------- number_of_child_nodes: `int` Number of child group nodes """ count: int = 0 if self.child_nodes_count() > 0: for n in self.__children: count = count + 1 if type(n) == StrokeGroupNode else 0 return count
def child_nodes_count(self) ‑> int
-
Number of child nodes.
Returns
number_of_child_nodes
:int
- Number of child nodes
Expand source code
def child_nodes_count(self) -> int: """ Number of child nodes. Returns ------- number_of_child_nodes: `int` Number of child nodes """ return len(self.__children)
def child_stroke_nodes_count(self) ‑> int
-
Number of child stroke nodes.
Returns
number_of_child_nodes
:int
- Number of child stroke group nodes
Expand source code
def child_stroke_nodes_count(self) -> int: """ Number of child stroke nodes. Returns ------- number_of_child_nodes: `int` Number of child stroke group nodes """ count: int = 0 if self.child_nodes_count() > 0: for n in self.__children: count = count + 1 if type(n) == StrokeNode else 0 return count
def sort_children(self, lambda_sort_func: Any, reverse: bool = False)
-
Sorts the children based on a sorting function.
Parameters
lambda_sort_func
:Any
- Sorting function for children.
reverse
:bool
- Flag for reversed order [default:=False]
Expand source code
def sort_children(self, lambda_sort_func: Any, reverse: bool = False): """ Sorts the children based on a sorting function. Parameters ---------- lambda_sort_func: Any Sorting function for children. reverse: bool Flag for reversed order [default:=False] """ self.__children = sorted(self.__children, key=functools.cmp_to_key(lambda_sort_func), reverse=reverse)
Inherited members
class StrokeNode (stroke: Stroke, fragment: StrokeFragment = None)
-
StrokeNode
Represents an ´InkNode´ that refers to a Stroke object. A
StrokeNode
can represent either a whole path or part of a path within the ink model.Parameters
stroke
:Stroke
- Stroke which is referenced
fragment
:StrokeFragment
- Fragment referencing only parts of the
Stroke
Examples
>>> from uim.model.ink import InkModel, InkTree >>> from uim.model.semantics.node import StrokeGroupNode, StrokeNode, StrokeFragment, URIBuilder >>> # Create the model >>> ink_model: InkModel = InkModel() >>> # Assign the group as the root of the main ink tree >>> ink_model.ink_tree = InkTree() >>> # First you need a root group to contain the strokes >>> root: StrokeGroupNode = StrokeGroupNode(UUIDIdentifier.id_generator()) >>> ink_model.ink_tree.root = root >>> >>> # Add a node for stroke 0 >>> stroke_node_0: StrokeNode = StrokeNode(stroke_0, StrokeFragment(0, 1, 0.0, 1.0)) >>> root.add(stroke_node_0) >>> >>> # Add a node for stroke 1 >>> root.add(StrokeNode(stroke_1, StrokeFragment(0, 1, 0.0, 1.0)))
Expand source code
class StrokeNode(InkNode): """ StrokeNode ========== Represents an ´InkNode´ that refers to a Stroke object. A `StrokeNode` can represent either a whole path or part of a path within the ink model. Parameters ---------- stroke: `Stroke` Stroke which is referenced fragment: `StrokeFragment` Fragment referencing only parts of the `Stroke` Examples -------- >>> from uim.model.ink import InkModel, InkTree >>> from uim.model.semantics.node import StrokeGroupNode, StrokeNode, StrokeFragment, URIBuilder >>> # Create the model >>> ink_model: InkModel = InkModel() >>> # Assign the group as the root of the main ink tree >>> ink_model.ink_tree = InkTree() >>> # First you need a root group to contain the strokes >>> root: StrokeGroupNode = StrokeGroupNode(UUIDIdentifier.id_generator()) >>> ink_model.ink_tree.root = root >>> >>> # Add a node for stroke 0 >>> stroke_node_0: StrokeNode = StrokeNode(stroke_0, StrokeFragment(0, 1, 0.0, 1.0)) >>> root.add(stroke_node_0) >>> >>> # Add a node for stroke 1 >>> root.add(StrokeNode(stroke_1, StrokeFragment(0, 1, 0.0, 1.0))) """ def __init__(self, stroke: Stroke, fragment: StrokeFragment = None): super().__init__(node_id=stroke.id) self.__ref_stroke: Stroke = stroke self.__fragment: StrokeFragment = fragment @property def stroke(self) -> Stroke: """References the strokes. (`Stroke`)""" return self.__ref_stroke @stroke.setter def stroke(self, stroke: Stroke): self.__ref_stroke = stroke @property def fragment(self) -> StrokeFragment: """`StrokeFragment` that specifies a fragment of the stroke. (`StrokeFragment`) Notes ----- If the property value is not null, the stroke node refers to the specified fragment of the stroke. """ return self.__fragment @fragment.setter def fragment(self, fragment: StrokeFragment): self.__fragment = fragment def child_nodes_count(self) -> int: """ Number of child nodes. Returns ------- num_child_nodes: int number of children nodes """ return 0 def __generate_uri__(self): return URIBuilder().build_node_uri(self, SupportedFormats.UIM_VERSION_3_1_0) def __repr__(self): if self.stroke: return '<StrokeNode: [stroke id:={}]>'.format(self.stroke.id if self.stroke is not None else '')
Ancestors
- InkNode
- UUIDIdentifier
- Identifier
- abc.ABC
Class variables
var SEPARATOR : str
Instance variables
var fragment : StrokeFragment
-
StrokeFragment
that specifies a fragment of the stroke. (StrokeFragment
)Notes
If the property value is not null, the stroke node refers to the specified fragment of the stroke.
Expand source code
@property def fragment(self) -> StrokeFragment: """`StrokeFragment` that specifies a fragment of the stroke. (`StrokeFragment`) Notes ----- If the property value is not null, the stroke node refers to the specified fragment of the stroke. """ return self.__fragment
var stroke : Stroke
-
References the strokes. (
Stroke
)Expand source code
@property def stroke(self) -> Stroke: """References the strokes. (`Stroke`)""" return self.__ref_stroke
Methods
def child_nodes_count(self) ‑> int
-
Number of child nodes.
Returns
num_child_nodes
:int
- number of children nodes
Expand source code
def child_nodes_count(self) -> int: """ Number of child nodes. Returns ------- num_child_nodes: int number of children nodes """ return 0
Inherited members
class URIBuilder
-
Generates URIs according to the ink model URI scheme.
Expand source code
class URIBuilder(ABC): """ Generates URIs according to the ink model URI scheme. """ SCHEME: str = "uim:" def __init__(self): pass @staticmethod def build_uri(sub_path: str, model_id: uuid.UUID = None): """ Build a URI for a model. Parameters ---------- sub_path: str Sub path. model_id: UUID Unique ID of the model. Returns ------- uri - `str` Model URI """ uri: str = URIBuilder.SCHEME if model_id is not None: uri += f'{str(model_id)}/' uri += f'{sub_path}/' return uri @staticmethod def build_named_entity_uri(uimid: uuid.UUID, model_id: uuid.UUID = None) -> str: """Creates a URI for the specified named entity identifier. Parameters ---------- uimid: `UUID` UUID of a node model_id: UUID ID of the model [optional] Returns ------- uri: str URI for a named entity """ if not isinstance(uimid, uuid.UUID): raise InkModelException("The named entity identifier should be a valid UUID.") return URIBuilder.build_uri('ne', model_id) + str(uimid) @staticmethod def build_entity_uri(uimid: uuid.UUID, model_id: uuid.UUID = None) -> str: """ Creates a URI for the specified entity view identifier. Parameters ---------- uimid: `UUID` UUID of a node model_id: UUID ID of the model [optional] Returns ------- uri: str URI for an entity """ if not isinstance(uimid, uuid.UUID): raise InkModelException("The named entity identifier should be a valid UUID.") return URIBuilder.build_uri('', model_id) + str(uimid) @staticmethod def build_node_uri_from(node_uuid: uuid.UUID, view_name: str, uri_format: SupportedFormats = SupportedFormats.UIM_VERSION_3_1_0) -> str: """ Creates a URI for a node in a view. Parameters ---------- node_uuid: `UUID` UUID of a node view_name: `str` Name of the view uri_format: `SupportedFormats' Target format Returns ------- uri: str URI for an node within a specific view """ node_uri: str = URIBuilder.build_uri('node') if view_name == CommonViews.LEGACY_HWR_VIEW.value: node_uri += 'hwr/' if uri_format == SupportedFormats.UIM_VERSION_3_1_0 else '' elif view_name == CommonViews.LEGACY_NER_VIEW.value: node_uri += 'ner/' if uri_format == SupportedFormats.UIM_VERSION_3_1_0 else '' else: node_uri += f'{view_name}/' node_uri += f'{node_uuid}' return node_uri @staticmethod def build_node_uri(ink_node: 'InkNode', uri_format: SupportedFormats) -> str: """ Creates a URI for an ink node. Parameters ---------- ink_node: `InkNode` Node in a tree uri_format: `SupportedFormats` URI format Returns ------- uri - `str` Build a URI for the ink node """ if isinstance(ink_node, StrokeGroupNode): return URIBuilder.build_node_uri_from(ink_node.id, ink_node.view_name, uri_format) elif isinstance(ink_node, StrokeNode): stroke_node: StrokeNode = ink_node node_uri: str = URIBuilder.build_node_uri_from(stroke_node.stroke.id, stroke_node.view_name, uri_format) if stroke_node.fragment: node_uri += f'#frag={stroke_node.fragment.from_point_index},{stroke_node.fragment.to_point_index}' return node_uri
Ancestors
- abc.ABC
Class variables
var SCHEME : str
Static methods
def build_entity_uri(uimid: uuid.UUID, model_id: uuid.UUID = None) ‑> str
-
Creates a URI for the specified entity view identifier.
Parameters
uimid
:UUID
- UUID of a node
model_id
:UUID
- ID of the model [optional]
Returns
uri
:str
- URI for an entity
Expand source code
@staticmethod def build_entity_uri(uimid: uuid.UUID, model_id: uuid.UUID = None) -> str: """ Creates a URI for the specified entity view identifier. Parameters ---------- uimid: `UUID` UUID of a node model_id: UUID ID of the model [optional] Returns ------- uri: str URI for an entity """ if not isinstance(uimid, uuid.UUID): raise InkModelException("The named entity identifier should be a valid UUID.") return URIBuilder.build_uri('', model_id) + str(uimid)
def build_named_entity_uri(uimid: uuid.UUID, model_id: uuid.UUID = None) ‑> str
-
Creates a URI for the specified named entity identifier.
Parameters
uimid
:UUID
- UUID of a node
model_id
:UUID
- ID of the model [optional]
Returns
uri
:str
- URI for a named entity
Expand source code
@staticmethod def build_named_entity_uri(uimid: uuid.UUID, model_id: uuid.UUID = None) -> str: """Creates a URI for the specified named entity identifier. Parameters ---------- uimid: `UUID` UUID of a node model_id: UUID ID of the model [optional] Returns ------- uri: str URI for a named entity """ if not isinstance(uimid, uuid.UUID): raise InkModelException("The named entity identifier should be a valid UUID.") return URIBuilder.build_uri('ne', model_id) + str(uimid)
def build_node_uri(ink_node: InkNode, uri_format: SupportedFormats) ‑> str
-
Creates a URI for an ink node.
Parameters
ink_node
:InkNode
- Node in a tree
uri_format
:SupportedFormats
- URI format
Returns
uri - <code>str</code> Build a URI for the ink node
Expand source code
@staticmethod def build_node_uri(ink_node: 'InkNode', uri_format: SupportedFormats) -> str: """ Creates a URI for an ink node. Parameters ---------- ink_node: `InkNode` Node in a tree uri_format: `SupportedFormats` URI format Returns ------- uri - `str` Build a URI for the ink node """ if isinstance(ink_node, StrokeGroupNode): return URIBuilder.build_node_uri_from(ink_node.id, ink_node.view_name, uri_format) elif isinstance(ink_node, StrokeNode): stroke_node: StrokeNode = ink_node node_uri: str = URIBuilder.build_node_uri_from(stroke_node.stroke.id, stroke_node.view_name, uri_format) if stroke_node.fragment: node_uri += f'#frag={stroke_node.fragment.from_point_index},{stroke_node.fragment.to_point_index}' return node_uri
def build_node_uri_from(node_uuid: uuid.UUID, view_name: str, uri_format: SupportedFormats = SupportedFormats.UIM_VERSION_3_1_0) ‑> str
-
Creates a URI for a node in a view.
Parameters
node_uuid
:UUID
- UUID of a node
view_name
:str
- Name of the view
uri_format
:`SupportedFormats'
- Target format
Returns
uri
:str
- URI for an node within a specific view
Expand source code
@staticmethod def build_node_uri_from(node_uuid: uuid.UUID, view_name: str, uri_format: SupportedFormats = SupportedFormats.UIM_VERSION_3_1_0) -> str: """ Creates a URI for a node in a view. Parameters ---------- node_uuid: `UUID` UUID of a node view_name: `str` Name of the view uri_format: `SupportedFormats' Target format Returns ------- uri: str URI for an node within a specific view """ node_uri: str = URIBuilder.build_uri('node') if view_name == CommonViews.LEGACY_HWR_VIEW.value: node_uri += 'hwr/' if uri_format == SupportedFormats.UIM_VERSION_3_1_0 else '' elif view_name == CommonViews.LEGACY_NER_VIEW.value: node_uri += 'ner/' if uri_format == SupportedFormats.UIM_VERSION_3_1_0 else '' else: node_uri += f'{view_name}/' node_uri += f'{node_uuid}' return node_uri
def build_uri(sub_path: str, model_id: uuid.UUID = None)
-
Build a URI for a model.
Parameters
sub_path
:str
- Sub path.
model_id
:UUID
- Unique ID of the model.
Returns
uri -
str
Model URIExpand source code
@staticmethod def build_uri(sub_path: str, model_id: uuid.UUID = None): """ Build a URI for a model. Parameters ---------- sub_path: str Sub path. model_id: UUID Unique ID of the model. Returns ------- uri - `str` Model URI """ uri: str = URIBuilder.SCHEME if model_id is not None: uri += f'{str(model_id)}/' uri += f'{sub_path}/' return uri