# Source code for pyqtgraph.graphicsItems.CurvePoint

    import weakref
    from math import atan2, degrees

    from ..functions import clip_scalar
    from ..Qt import QtCore, QtWidgets
    from . import ArrowItem
    from .GraphicsObject import GraphicsObject

    __all__ = ['CurvePoint', 'CurveArrow']
    class CurvePoint(GraphicsObject):
        """A GraphicsItem that sets its location to a point on a PlotCurveItem.
        Also rotates to be tangent to the curve.
        The position along the curve is a Qt property, and thus can be easily animated.

        Note: This class does not display anything; see CurveArrow for an applied example
        """

        def __init__(self, curve, index=0, pos=None, rotate=True):
            """Position can be set either as an index referring to the sample number or
            the position 0.0 - 1.0
            If *rotate* is True, then the item rotates to match the tangent of the curve.
            """

            GraphicsObject.__init__(self)
            #QObjectWorkaround.__init__(self)
            self._rotate = rotate
            self.curve = weakref.ref(curve)
            self.setParentItem(curve)
            self.setProperty('position', 0.0)
            self.setProperty('index', 0)

            self.setFlags(self.flags() | self.GraphicsItemFlag.ItemHasNoContents)

            if pos is not None:
                self.setPos(pos)
            else:
                self.setIndex(index)

        def setPos(self, pos):
            self.setProperty('position', float(pos))## cannot use numpy types here, MUST be python float.

        def setIndex(self, index):
            self.setProperty('index', int(index))  ## cannot use numpy types here, MUST be python int.

        def event(self, ev):
            if not isinstance(ev, QtCore.QDynamicPropertyChangeEvent) or self.curve() is None:
                return False

            if ev.propertyName() == 'index':
                index = self.property('index')
                if 'QVariant' in repr(index):
                    index = index.toInt()[0]
            elif ev.propertyName() == 'position':
                index = None
            else:
                return False

            (x, y) = self.curve().getData()
            if index is None:
                #print ev.propertyName(), self.property('position').toDouble()[0], self.property('position').typeName()
                pos = self.property('position')
                if 'QVariant' in repr(pos):   ## need to support 2 APIs  :(
                    pos = pos.toDouble()[0]
                index = (len(x)-1) * clip_scalar(pos, 0.0, 1.0)

            if index != int(index):  ## interpolate floating-point values
                i1 = int(index)
                i2 = clip_scalar(i1+1, 0, len(x)-1)
                s2 = index-i1
                s1 = 1.0-s2
                newPos = (x[i1]*s1+x[i2]*s2, y[i1]*s1+y[i2]*s2)
            else:
                index = int(index)
                i1 = clip_scalar(index-1, 0, len(x)-1)
                i2 = clip_scalar(index+1, 0, len(x)-1)
                newPos = (x[index], y[index])

            p1 = self.parentItem().mapToScene(QtCore.QPointF(x[i1], y[i1]))
            p2 = self.parentItem().mapToScene(QtCore.QPointF(x[i2], y[i2]))
            rads = atan2(p2.y()-p1.y(), p2.x()-p1.x()) ## returns radians
            self.resetTransform()
            if self._rotate:
                self.setRotation(180 + degrees(rads))
            QtWidgets.QGraphicsItem.setPos(self, *newPos)
            return True

        def boundingRect(self):
            return QtCore.QRectF()

        def paint(self, *args):
            pass

        def makeAnimation(self, prop='position', start=0.0, end=1.0, duration=10000, loop=1):
            # In Python 3, a bytes object needs to be used as a property name in
            # QPropertyAnimation. PyQt stopped automatically encoding a str when a
            # QByteArray was expected in v5.5 (see qbytearray.sip).
            if not isinstance(prop, bytes):
                prop = prop.encode('latin-1')
            anim = QtCore.QPropertyAnimation(self, prop)
            anim.setDuration(duration)
            anim.setStartValue(start)
            anim.setEndValue(end)
            anim.setLoopCount(loop)
            return anim

    class CurveArrow(CurvePoint):
        """Provides an arrow that points to any specific sample on a PlotCurveItem.
        Provides properties that can be animated."""

        def __init__(self, curve, index=0, pos=None, **opts):
            CurvePoint.__init__(self, curve, index=index, pos=pos)
            if opts.get('pxMode', True):
                opts['pxMode'] = False
                self.setFlags(self.flags() | self.GraphicsItemFlag.ItemIgnoresTransformations)
            opts['angle'] = 0
            self.arrow = ArrowItem.ArrowItem(**opts)
            self.arrow.setParentItem(self)

        def setStyle(self, **opts):
            return self.arrow.setStyle(**opts)