Page MenuHomec4science

positional_object.py
No OneTemporary

File Metadata

Created
Fri, May 10, 22:24

positional_object.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
""" This class can be used to represent an object with positional information.
"""
# Copyright (C) University of Basel 2019 {{{1
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/> 1}}}
__author__ = "Christian Steiner"
__maintainer__ = __author__
__copyright__ = 'University of Basel'
__email__ = "christian.steiner@unibas.ch"
__status__ = "Development"
__license__ = "GPL v3"
__version__ = "0.0.1"
from lxml import etree as ET
import sys
from .matrix import Matrix
from .attachable_object import AttachableObject
sys.path.append('py2ttl')
from class_spec import SemanticClass
class PositionalObject(AttachableObject,SemanticClass):
"""
This (super) class represents an object with positional information.
Args:
id (int): object id
matrix (datatypes.Matrix): matrix containing information about conversion.
height (float): height of
width (float): width of object
x (float): x position of object
y (float): y position of object
"""
XML_TAG = 'positional-object'
floatKeys = [ 'height', 'width', 'left', 'top', 'bottom']
intKeys = [ ]
stringKeys = [ ]
def __init__(self, node=None, id=0, height=0.0, width=0.0, x=0.0, y=0.0, matrix=None, tag=XML_TAG):
self.floatKeys = []
self.floatKeys += PositionalObject.floatKeys
self.intKeys = []
self.intKeys += PositionalObject.intKeys
self.stringKeys = [ 'id' ]
self.stringKeys += PositionalObject.stringKeys
self.attachable_objects = []
if node is not None:
self.id = str(node.get('id'))
self.height = float(node.get('height'))
self.width = float(node.get('width'))
self.left = float(node.get('left'))
self.top = float(node.get('top'))
self.bottom = float(node.get('bottom'))
self.transform = Matrix(node.get('transform')) if bool(node.get('transform')) and 'matrix(' in node.get('transform') else None
self.tag = node.tag
else:
self.id = str(id)
self.height = round(height, 3)
self.width = round(width, 3)
self.left = round(x, 3)
self.top = round(y, 3)
self.bottom = round(y + height, 3)
self.transform = matrix
self.tag = tag
def attach_object_to_tree(self, target_tree):
"""Attach object to tree.
"""
if target_tree.__class__.__name__ == '_ElementTree':
target_tree = target_tree.getroot()
obj_node = target_tree.xpath('.//' + self.tag + '[@id="%s"]' % self.id)[0] \
if(len(target_tree.xpath('.//' + self.tag + '[@id="%s"]' % self.id)) > 0) \
else ET.SubElement(target_tree, self.tag)
for key in self.floatKeys:
if self.__dict__[key] is not None:
obj_node.set(key.replace('_','-'), str(round(self.__dict__[key], 3)))
for key in self.intKeys + self.stringKeys:
if self.__dict__[key] is not None:
obj_node.set(key.replace('_','-'), str(self.__dict__[key]))
if self.transform is not None and self.transform.isRotationMatrix():
obj_node.set('transform', self.transform.toString())
for attachable_object in self.attachable_objects:
attachable_object.attach_object_to_tree(obj_node)
@classmethod
def get_semantic_dictionary(cls):
""" Creates a semantic dictionary as specified by SemanticClass.
"""
dictionary = {}
class_dict = cls.get_class_dictionary()
properties = {}
for intKey in cls.intKeys:
properties.update(cls.create_semantic_property_dictionary(intKey, int))
for floatKey in cls.floatKeys:
properties.update(cls.create_semantic_property_dictionary(floatKey, float, cardinality=1))
for stringKey in cls.stringKeys:
properties.update(cls.create_semantic_property_dictionary(stringKey, str, cardinality=1))
properties.update(cls.create_semantic_property_dictionary('transform', str))
dictionary.update({'class': class_dict})
dictionary.update({'properties': properties})
return dictionary
@staticmethod
def POSITIONS_OVERLAP_HORIZONTALLY(position_a, position_b):
"""Returns whether position a and b overlap horizontally.
"""
return (position_a.left < position_b.left+position_b.width)\
and (position_a.left+position_a.width > position_b.left)
@staticmethod
def POSITIONS_OVERLAP_VERTICALLY(position_a, position_b):
"""Returns whether position a and b overlap vertically.
"""
return (position_a.top < position_b.bottom)\
and (position_a.bottom > position_b.top)
@staticmethod
def POSITIONS_ARE_STACKED(position_a, position_b):
"""Returns whether position a and b are stacked, i.e. are above each other.
"""
return PositionalObject.POSITIONS_OVERLAP_HORIZONTALLY(position_a, position_b)\
and (not PositionalObject.POSITIONS_OVERLAP_VERTICALLY(position_a, position_b)\
or abs(position_a.top-position_b.top) > (position_a.height/4 + position_b.height/4))

Event Timeline