"""
MathApp classes for representing geometric points
"""
from abc import ABCMeta, abstractmethod
from ggame.mathapp import _MathVisual, MathApp
from ggame.asset import Color, LineStyle, CircleAsset, ImageAsset
[docs]class _Point(_MathVisual, metaclass=ABCMeta):
"""
Abstract base class for all point classes.
:param Asset asset: A valid ggame Asset object
:param tuple(float,float) pos: The position (physical or logical)
"""
_posinputsdef = ["pos"]
_nonposinputsdef = []
def __init__(self, asset, *args, **kwargs):
super().__init__(asset, *args, **kwargs)
self.touchAsset()
self.center = (0.5, 0.5)
def __call__(self):
return self._posinputs.pos()
[docs] def step(self):
"""
Perform periodic processing.
"""
self.touchAsset()
[docs] def physicalPointTouching(self, ppos):
"""
Determine if a physical point is considered to be touching this point.
:param tuple(int,int) ppos: Physical screen coordinates.
:rtype: boolean
:returns: True if touching, False otherwise.
"""
return (
MathApp.distance(ppos, self._pposinputs.pos) # pylint: disable=no-member
< self._sstdinputs.size
)
[docs] def translate(self, pdisp):
"""
Perform necessary processing in response to being moved by the mouse/UI.
:param tuple(int,int) pdisp: Translation vector (x,y) in physical screen
units.
:returns: None
"""
ldisp = MathApp.translatePhysicalToLogical(pdisp)
pos = self._posinputs.pos()
self._posinputs = self._posinputs._replace(
pos=self.eval((pos[0] + ldisp[0], pos[1] + ldisp[1]))
)
self.touchAsset()
[docs] def distanceTo(self, otherpoint):
"""
Compute the distance to another :class:`_Point` object.
:param _Point otherpoint: A reference to the other :class:`_Point`
:rtype: float
:returns: The distance (in logical units) to the other point
"""
try:
return MathApp.distance(self(), otherpoint())
except AttributeError:
return otherpoint # presumably a scalar - use this distance
@abstractmethod
def _buildAsset(self):
pass
[docs]class Point(_Point):
"""
Basic point object representing any point in a geometrical sense.
An instantiated Point object is *callable* and will return a tuple
with its logical position as an (x,y) pair.
:param tuple(float,float) pos: Position in physical or logical units.
:param \\**kwargs:
See below
:Optional Keyword Arguments:
* **positioning** (*str*) One of 'logical' (default) or 'physical'
* **size** (*int*) Radius of the point (in pixels)
* **color** (*Color*) Valid :class:`~ggame.asset.Color` object
* **style** (*LineStyle*) Valid :class:`~ggame.asset.LineStyle` object
Example:
.. literalinclude:: ../examples/pointpoint.py
"""
_defaultsize = 5
_defaultstyle = LineStyle(0, Color(0, 1))
def __init__(self, *args, **kwargs):
super().__init__(
CircleAsset(self._defaultsize, self._defaultstyle, self._defaultcolor),
*args,
**kwargs
)
def _buildAsset(self):
return CircleAsset(
self._stdinputs.size(), self._stdinputs.style(), self._stdinputs.color()
)
[docs]class ImagePoint(_Point):
"""
:class:`~ggame.point.Point` object that uses an image as its on-screen
representation.
:param str url: Location of an image file (png, jpg)
:param \\*args:
See below
:param \\**kwargs:
See below
:Required Arguments:
* **pos** (*tuple(float,float)*) Position in physical or logical units.
:Optional Keyword Arguments:
* **positioning** (*str*) One of 'logical' (default) or 'physical'
* **frame** (*Frame*) The sub-frame location of image within the image file
* **qty** (*int*) The number of sub-frames, when used as a sprite sheet
* **direction** (*str*) One of 'horizontal' (default) or 'vertical'
* **margin** (*int*) Pixels between sub-frames if sprite sheet
"""
def __init__(self, url, *args, **kwargs):
frame = kwargs.get("frame", None)
qty = kwargs.get("qty", 1)
direction = kwargs.get("direction", "horizontal")
margin = kwargs.get("margin", 0)
self._imageasset = ImageAsset(url, frame, qty, direction, margin)
super().__init__(self._imageasset, *args, **kwargs)
def _buildAsset(self):
return self._imageasset
[docs] def physicalPointTouching(self, ppos):
"""
Determine if a physical point is considered to be touching point's
image.
:param tuple(int,int) ppos: Physical screen coordinates.
:rtype: boolean
:returns: True if touching, False otherwise.
"""
self.setExtents() # ensure xmin, xmax are correct
x, y = ppos
return self.xmax >= x >= self.xmin and self.ymax >= y >= self.ymin