Skip to content
Snippets Groups Projects
polar_tracker_widget.py 4.53 KiB
Newer Older
# -*- coding: utf-8 -*-
"""
PolarTracker Widget Class.

Contains parametric graph capable of plotting a tracked object's path in the
polar coordinate system.

Author: Jason Merlo, Stavros Vakalis
Maintainer: Jason Merlo (merlojas@msu.edu)
"""
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui, QtCore
import numpy as np              # Used for numerical operations
import platform                 # Get OS for DPI scaling
from pyratk.datatypes.geometry import Point, Circle


class PolarTrackerWidget(pg.GraphicsLayoutWidget):
    def __init__(self, tracker, max_range=20):
        super().__init__()
        """
        Initialize polar tracker widget.

        tracker - Tracker object
            Note:   Tracker requires list of namedtouples named `detections`.
                    The namedtouple must contain:
                        - location (Point): location of detection
                        - power (float): power of detection
                        - doppler (float): Doppler velocity of detection
                        - velocity (Point): Velocity vector (if tracked)
        """

        # Copy arguments to member variables
        self.tracker = tracker
        self.max_range = max_range

        # Add plots to layout
        self.plot = self.addPlot()

        # Add polar grid lines
        self.plot.addLine(x=0, pen=0.2)
        self.plot.addLine(y=0, pen=0.2)

        for r in range(2, self.max_range*2, 2):
            circle = pg.QtGui.QGraphicsEllipseItem(-r, -r, r * 2, r * 2)
            circle.setPen(pg.mkPen(0.2))
            self.plot.addItem(circle)

        # Add radar location marker plot
        # self.radar_loc_plot = pg.ScatterPlotItem(
        #     size=10, pen=pg.mkPen(None), brush=pg.mkBrush(255, 255, 0, 255))

        # for radar in self.tracker.radar_array:
        #     loc = (radar.loc.x, radar.loc.y)
        #     self.radar_loc_plot.addPoints(pos=[loc])

        # self.plot.addItem(self.radar_loc_plot)

        # Add radar detection marker plot
        self.det_loc_plot = pg.ScatterPlotItem(
            size=10, pen=pg.mkPen(None), brush=pg.mkBrush(255, 255, 0, 255))

        self.plot.addItem(self.det_loc_plot)

        # Set up plot
        self.plot.setLimits(yMin=0)
        self.plot.setRange(yRange=[0, self.max_range], xRange=[-self.max_range, self.max_range])
        self.plot.setAspectLocked(True)
            # xMin=-self.max_range, xMax=self.max_range)

        self.plot.setLabel('left', text='Downrange', units='m')
        self.plot.setLabel('bottom', text='Crossrange', units='m')
        self.plot.setTitle('Polar Tracker')

        # Remove extra margins around plot
        self.ci.layout.setContentsMargins(0, 0, 0, 0)

    def update(self):
        '''
        Draw detections on graph.
        '''
        self.det_loc_plot.clear()
        for det in self.tracker.detections:
            R = det.location.p[0]
            theta = det.location.p[1]

            x = R * np.cos(theta)
            y = R * np.sin(theta)

            self.det_loc_plot.addPoints(pos=[Point(x, y)])

    def reset(self):
        # self.tracker.reset()
        self.update()

    # === UTILITY FUNCTIONS ===================================================
    def draw_circle(self, curve, cir, num_pts=100, color="AAFFFF16"):
        '''
        adds a Circle, c, to the plot
        '''
        x_list = []
        y_list = []

        for i in range(num_pts):
            ang = 2 * np.pi * (i / num_pts)
            x = (np.cos(ang) * cir.r) + cir.c.x
            y = (np.sin(ang) * cir.r) + cir.c.y
            x_list.append(x)
            y_list.append(y)

        # append first point to end to 'close' circle
        x_list.append(x_list[0])
        y_list.append(y_list[0])

        x_pts = np.array(x_list)
        y_pts = np.array(y_list)

        curve.setData(x=x_pts, y=y_pts, pen=pg.mkPen(
            {'color': color, 'width': 3}))


    def draw_triangle(self, curve, pts, color="AAFFFF16"):
        """Create triangle object from points."""
        curve.clear()
        for pt in pts:
            curve.append(pt)
        curve.append(pts[0])

    def ppm(self):
        '''
        pixels per meter
        '''
        os = platform.system().lower()
        if os == 'windows':
            pixels = self.frameGeometry().width() - 55.75
            meters = self.plot.vb.viewRange(
            )[0][1] - self.plot.vb.viewRange()[0][0]
        elif os == 'darwin':
            pixels = self.frameGeometry().width() - 55.75
            meters = self.plot.vb.viewRange(
            )[0][1] - self.plot.vb.viewRange()[0][0]
        return pixels / meters