gpsd-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gpsd-dev] [PATCH 2/2] Adds skyview rotation support to xgps and xgpsspe


From: Fred Wright
Subject: [gpsd-dev] [PATCH 2/2] Adds skyview rotation support to xgps and xgpsspeed.
Date: Thu, 22 Sep 2016 16:28:36 -0700

This adds an optional argument to rotate the skyview display, making
it possible to orient it correctly based on the direction one is
actually facing.  The specified heading is positioned at the top.

This edit does not update contrib/webgps.py, which is somewhat
more complicated to fix due to the Javascript involvement (not to
mention the rather crude argument parsing).

TESTED:
Ran both programs with and without the -r or --rotate option.
---
 xgps      | 37 +++++++++++++++++++------------
 xgpsspeed | 75 +++++++++++++++++++++++++++++++++++++--------------------------
 2 files changed, 67 insertions(+), 45 deletions(-)

diff --git a/xgps b/xgps
index 066401f..44ea062 100755
--- a/xgps
+++ b/xgps
@@ -3,7 +3,7 @@
 '''
 xgps -- test client for gpsd
 
-usage: xgps [-D level] [-hV?] [-l degmfmt] [-u units] [server[:port[:device]]]
+usage: xgps [-D level] [-hV?] [-l degmfmt] [-u units] [-r rotation] 
[server[:port[:device]]]
 '''
 
 # This code runs compatibly under Python 2 and 3.x for x >= 2.
@@ -95,7 +95,7 @@ class SkyView(Gtk.DrawingArea):
     HORIZON_PAD = 40    # How much whitespace to leave around horizon
     SAT_RADIUS = 5      # Diameter of satellite circle
 
-    def __init__(self):
+    def __init__(self, rotate=0.0):
         GObject.GObject.__init__(self)
         self.set_size_request(400, 400)
         self.cr = None   # New cairo context for each expose event
@@ -104,6 +104,7 @@ class SkyView(Gtk.DrawingArea):
         self.connect('draw', self.on_draw)
         self.satellites = []
         self.center_x = self.center_y = self.radius = None
+        self.rotate = rotate
 
     def on_size_allocate(self, _unused, allocation):
         width = allocation.width
@@ -181,6 +182,7 @@ class SkyView(Gtk.DrawingArea):
 
     def pol2cart(self, az, el):
         "Polar to Cartesian coordinates within the horizon circle."
+        az = (az - self.rotate) % 360.0
         az *= (math.pi / 180)  # Degrees to radians
         # Exact spherical projection would be like this:
         # el = sin((90.0 - el) * DEG_2_RAD);
@@ -223,14 +225,14 @@ class SkyView(Gtk.DrawingArea):
         self.draw_line(x1, y1, x2, y2)
 
         # The compass-point letters
-        (x, y) = self.pol2cart(0, 0)
-        self.draw_string(x, y - 10, "N")
-        (x, y) = self.pol2cart(90, 0)
-        self.draw_string(x + 10, y, "E")
-        (x, y) = self.pol2cart(180, 0)
-        self.draw_string(x, y + 10, "S")
-        (x, y) = self.pol2cart(270, 0)
-        self.draw_string(x - 10, y, "W")
+        (x, y) = self.pol2cart(0, -5)
+        self.draw_string(x, y, "N")
+        (x, y) = self.pol2cart(90, -5)
+        self.draw_string(x, y, "E")
+        (x, y) = self.pol2cart(180, -5)
+        self.draw_string(x, y, "S")
+        (x, y) = self.pol2cart(270, -5)
+        self.draw_string(x, y, "W")
 
         # The satellites
         self.cr.set_line_width(2)
@@ -460,8 +462,9 @@ class Base(object):
         ("EPD", lambda s, r: s.update_err_degrees(r, "epd")),
     )
 
-    def __init__(self, deg_type):
+    def __init__(self, deg_type, rotate=0.0):
         self.deg_type = deg_type
+        self.rotate = rotate
         self.conversions = unit_adjustments()
         self.saved_mode = -1
         self.ais_latch = False
@@ -579,7 +582,7 @@ class Base(object):
 
         viewframe = Gtk.Frame(label="Skyview")
         self.satbox.add(viewframe)
-        self.skyview = SkyView()
+        self.skyview = SkyView(self.rotate)
         viewframe.add(self.skyview)
 
         self.rawdisplay = Gtk.Entry()
@@ -869,11 +872,12 @@ class Base(object):
 if __name__ == "__main__":
     try:
         import getopt
-        (options, arguments) = getopt.getopt(sys.argv[1:], "D:hl:u:V?",
+        (options, arguments) = getopt.getopt(sys.argv[1:], "D:hl:u:r:V?",
                                              ['verbose'])
         debug = 0
         degreefmt = 'd'
         unit_system = None
+        rotate = 0.0
         for (opt, val) in options:
             if opt in '-D':
                 debug = int(val)
@@ -881,6 +885,11 @@ if __name__ == "__main__":
                 degreeformat = val
             elif opt == '-u':
                 unit_system = val
+            elif opt == '-r':
+                try:
+                    rotate = float(val)
+                except ValueError:
+                    rotate = 0.0
             elif opt in ('-?', '-h', '--help'):
                 print(__doc__)
                 sys.exit(0)
@@ -902,7 +911,7 @@ if __name__ == "__main__":
             if len(args) >= 3:
                 device = args[2]
 
-        base = Base(deg_type=degreefmt)
+        base = Base(deg_type=degreefmt, rotate=rotate)
         base.set_units(unit_system)
         try:
             daemon = gps.gps(host=host,
diff --git a/xgpsspeed b/xgpsspeed
index 277b575..29a6fc7 100755
--- a/xgpsspeed
+++ b/xgpsspeed
@@ -228,7 +228,7 @@ class NauticalSpeedometer(Speedometer):
     HEADING_SAT_GAP = 0.8
     SAT_SIZE = 10  # radius of the satellite circle in skyview
 
-    def __init__(self, speed_unit=None, maxspeed=100):
+    def __init__(self, speed_unit=None, maxspeed=100, rotate=0.0):
         Speedometer.__init__(self, speed_unit)
         self.connect('size-allocate', self.on_size_allocate)
         self.width = self.height = 0
@@ -240,9 +240,9 @@ class NauticalSpeedometer(Speedometer):
         self.satellites = []
         self.last_heading = 0
         self.maxspeed = int(maxspeed)
+        self.rotate = radians(rotate)
 
-    @staticmethod
-    def polar2xy(radius, angle, polex, poley):
+    def polar2xy(self, radius, angle, polex, poley):
         '''convert Polar coordinate to Cartesian coordinate system
         the y axis in pygtk points downward
         Args:
@@ -250,6 +250,7 @@ class NauticalSpeedometer(Speedometer):
            angle: azimuth from from Polar coordinate system, in radian
            polex and poley are the Cartesian coordinate of the pole
         return a tuple contains (x, y)'''
+        angle = (angle + self.rotate) % (pi * 2)  # Note reversed sense
         return (polex + cos(angle) * radius, poley - sin(angle) * radius)
 
     def on_size_allocate(self, _unused, allocation):
@@ -306,12 +307,12 @@ class NauticalSpeedometer(Speedometer):
         for i in range(11):
             # draw the large ticks
             alpha = (8 - i) * pi / 6
-            self.cr.move_to(*NauticalSpeedometer.polar2xy(rspeed, alpha, x, y))
+            self.cr.move_to(*self.polar2xy(rspeed, alpha, x, y))
             self.cr.set_line_width(radius / 100)
-            self.cr.line_to(*NauticalSpeedometer.polar2xy(rspeed - s_long, 
alpha, x, y))
+            self.cr.line_to(*self.polar2xy(rspeed - s_long, alpha, x, y))
             self.cr.stroke()
             self.cr.set_line_width(radius / 200)
-            xf, yf = NauticalSpeedometer.polar2xy(rspeed + 10, alpha, x, y)
+            xf, yf = self.polar2xy(rspeed + 10, alpha, x, y)
             stxt = (self.maxspeed // 10) * i
             self.draw_text(xf, yf, stxt, fontsize=radius / 15)
 
@@ -319,14 +320,14 @@ class NauticalSpeedometer(Speedometer):
             # middle tick
             alpha = (8 - i) * pi / 6
             beta = (17 - 2 * i) * pi / 12
-            self.cr.move_to(*NauticalSpeedometer.polar2xy(rspeed, beta, x, y))
-            self.cr.line_to(*NauticalSpeedometer.polar2xy(rspeed - s_middle, 
beta, x, y))
+            self.cr.move_to(*self.polar2xy(rspeed, beta, x, y))
+            self.cr.line_to(*self.polar2xy(rspeed - s_middle, beta, x, y))
 
             #  short tick
             for n in range(10):
                 gamma = alpha + n * pi / 60
-                self.cr.move_to(*NauticalSpeedometer.polar2xy(rspeed, gamma, 
x, y))
-                self.cr.line_to(*NauticalSpeedometer.polar2xy(rspeed - 
s_short, gamma, x, y))
+                self.cr.move_to(*self.polar2xy(rspeed, gamma, x, y))
+                self.cr.line_to(*self.polar2xy(rspeed - s_short, gamma, x, y))
 
         # draw the heading arc
         self.cr.new_sub_path()
@@ -342,7 +343,7 @@ class NauticalSpeedometer(Speedometer):
             label = str(n * 90)
             # self.cr.set_source_rgba(0, 1, 0)
             # radius * (1 + NauticalSpeedometer.HEADING_SAT_GAP),
-            tbox_x, tbox_y = NauticalSpeedometer.polar2xy(
+            tbox_x, tbox_y = self.polar2xy(
                 radius * 0.88,
                 (1 - n) * pi / 2,
                 x, y)
@@ -359,13 +360,14 @@ class NauticalSpeedometer(Speedometer):
         self.cr.set_source_rgba(0, 0, 0)
 
         self.cr.arc(x, y, skyradius * 2 / 3, 0, 2 * pi)
+        self.cr.move_to(x + skyradius / 3, y)  # Avoid line connecting circles
         self.cr.arc(x, y, skyradius / 3, 0, 2 * pi)
 
         # draw the cross hair
-        self.cr.move_to(x - skyradius, y)
-        self.cr.line_to(x + skyradius, y)
-        self.cr.move_to(x, y - skyradius)
-        self.cr.line_to(x, y + skyradius)
+        self.cr.move_to(*self.polar2xy(skyradius, 1.5 * pi, x, y))
+        self.cr.line_to(*self.polar2xy(skyradius, 0.5 * pi, x, y))
+        self.cr.move_to(*self.polar2xy(skyradius, 0.0, x, y))
+        self.cr.line_to(*self.polar2xy(skyradius, pi, x, y))
         self.cr.set_line_width(radius / 200)
         self.cr.stroke()
 
@@ -376,22 +378,22 @@ class NauticalSpeedometer(Speedometer):
         # draw the large ticks
         for i in range(12):
             agllong = i * pi / 6
-            self.cr.move_to(*NauticalSpeedometer.polar2xy(radius - long_inset, 
agllong, x, y))
-            self.cr.line_to(*NauticalSpeedometer.polar2xy(radius, agllong, x, 
y))
+            self.cr.move_to(*self.polar2xy(radius - long_inset, agllong, x, y))
+            self.cr.line_to(*self.polar2xy(radius, agllong, x, y))
             self.cr.set_line_width(radius / 100)
             self.cr.stroke()
             self.cr.set_line_width(radius / 200)
 
             # middle tick
             aglmid = (i + 0.5) * pi / 6
-            self.cr.move_to(*NauticalSpeedometer.polar2xy(radius - mid_inset, 
aglmid, x, y))
-            self.cr.line_to(*NauticalSpeedometer.polar2xy(radius, aglmid, x, 
y))
+            self.cr.move_to(*self.polar2xy(radius - mid_inset, aglmid, x, y))
+            self.cr.line_to(*self.polar2xy(radius, aglmid, x, y))
 
             #  short tick
             for n in range(1, 10):
                 aglshrt = agllong + n * pi / 60
-                self.cr.move_to(*NauticalSpeedometer.polar2xy(radius - 
short_inset, aglshrt, x, y))
-                self.cr.line_to(*NauticalSpeedometer.polar2xy(radius, aglshrt, 
x, y))
+                self.cr.move_to(*self.polar2xy(radius - short_inset, aglshrt, 
x, y))
+                self.cr.line_to(*self.polar2xy(radius, aglshrt, x, y))
             self.cr.stroke()
 
     def draw_heading(self, trig_height, heading, radius, x, y):
@@ -419,16 +421,16 @@ class NauticalSpeedometer(Speedometer):
         self.cr.stroke()
 
         # heading text
-        (tbox_x, tbox_y) = NauticalSpeedometer.polar2xy(radius * 1.1, h, x, y)
+        (tbox_x, tbox_y) = self.polar2xy(radius * 1.1, h, x, y)
         self.draw_text(tbox_x, tbox_y, int(heading), fontsize=radius / 15)
 
         # the ship shape, based on test and try
         shiplen = radius * NauticalSpeedometer.HEADING_SAT_GAP / 4
-        xh, yh = NauticalSpeedometer.polar2xy(shiplen * 2.3, h, x, y)
-        xa, ya = NauticalSpeedometer.polar2xy(shiplen * 2.2, h + pi - 0.3, x, 
y)
-        xb, yb = NauticalSpeedometer.polar2xy(shiplen * 2.2, h + pi + 0.3, x, 
y)
-        xc, yc = NauticalSpeedometer.polar2xy(shiplen * 1.4, h - pi / 5, x, y)
-        xd, yd = NauticalSpeedometer.polar2xy(shiplen * 1.4, h + pi / 5, x, y)
+        xh, yh = self.polar2xy(shiplen * 2.3, h, x, y)
+        xa, ya = self.polar2xy(shiplen * 2.2, h + pi - 0.3, x, y)
+        xb, yb = self.polar2xy(shiplen * 2.2, h + pi + 0.3, x, y)
+        xc, yc = self.polar2xy(shiplen * 1.4, h - pi / 5, x, y)
+        xd, yd = self.polar2xy(shiplen * 1.4, h + pi / 5, x, y)
 
         self.cr.set_source_rgba(0, 0.3, 0.2, 0.5)
         self.cr.move_to(xa, ya)
@@ -460,7 +462,7 @@ class NauticalSpeedometer(Speedometer):
         self.cr.set_line_width(2)
         self.cr.set_source_rgb(0, 0, 0)
 
-        x0, y0 = NauticalSpeedometer.polar2xy(radius * (90 - el) // 90, h, x, 
y)
+        x0, y0 = self.polar2xy(radius * (90 - el) // 90, h, x, y)
 
         self.cr.new_sub_path()
         if gps.is_sbas(satsoup['PRN']):
@@ -515,7 +517,7 @@ class NauticalSpeedometer(Speedometer):
 
 class Main(object):
     def __init__(self, host='localhost', port='2947', device=None, debug=0,
-                 speed_unit=None, maxspeed=0, nautical=False):
+                 speed_unit=None, maxspeed=0, nautical=False, rotate=0.0):
         self.host = host
         self.port = port
         self.device = device
@@ -523,6 +525,7 @@ class Main(object):
         self.speed_unit = speed_unit
         self.maxspeed = maxspeed
         self.nautical = nautical
+        self.rotate = rotate
         self.window = Gtk.Window(Gtk.WindowType.TOPLEVEL)
         if not self.window.get_display():
             raise Exception("Can't open display")
@@ -531,7 +534,8 @@ class Main(object):
             self.window.set_size_request(500, 550)
             self.widget = NauticalSpeedometer(
                 speed_unit=self.speed_unit,
-                maxspeed=self.maxspeed)
+                maxspeed=self.maxspeed,
+                rotate=self.rotate)
         else:
             self.widget = LandSpeedometer(speed_unit=self.speed_unit)
         self.window.connect('delete_event', self.delete_event)
@@ -735,6 +739,14 @@ if __name__ == '__main__':
         type='int',
         help='Set level of debug. Must be integer. [Default 0]'
     )
+    parser.add_option(
+        '--rotate',
+        dest='rotate',
+        default=0,
+        action='store',
+        type='float',
+        help='Rotation of skyview ("up" direction) in degrees. [Default 0]'
+    )
     (options, args) = parser.parse_args()
     if args:
         arg = args[0].split(':')
@@ -755,5 +767,6 @@ if __name__ == '__main__':
         speed_unit=options.speedunits,
         maxspeed=options.maxspeed,
         nautical=options.nautical,
-        debug=options.debug
+        debug=options.debug,
+        rotate=options.rotate,
     ).run()
-- 
2.9.3




reply via email to

[Prev in Thread] Current Thread [Next in Thread]