fgmapping 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,20 @@
1
+ require "hud-widget"
2
+
3
+ # Class MainDlg ############################################
4
+ class HudWidget < Qt::Widget
5
+ attr_reader :w
6
+
7
+ def initialize parent=nil
8
+ super
9
+ @w=Ui::HudWidget.new
10
+ @w.setupUi(self)
11
+ @parent=parent
12
+
13
+ end
14
+
15
+ def pBexit_clicked()
16
+ p @w.pBexit.text
17
+ @parent.close
18
+ end
19
+ end
20
+
@@ -0,0 +1,172 @@
1
+ =begin
2
+ ** Form generated from reading ui file 'hud-widget.ui'
3
+ **
4
+ ** Created: Fr. Jun 11 14:41:10 2010
5
+ ** by: Qt User Interface Compiler version 4.6.2
6
+ **
7
+ ** WARNING! All changes made in this file will be lost when recompiling ui file!
8
+ =end
9
+
10
+ class Ui_HudWidget
11
+ attr_reader :verticalLayout
12
+ attr_reader :lBspeed
13
+ attr_reader :lBdistance
14
+ attr_reader :gridLayout
15
+ attr_reader :label_4
16
+ attr_reader :lBalt
17
+ attr_reader :label_3
18
+ attr_reader :lBheading
19
+ attr_reader :label_6
20
+ attr_reader :lBlat
21
+ attr_reader :label_5
22
+ attr_reader :lBlon
23
+
24
+ def setupUi(hudWidget)
25
+ if hudWidget.objectName.nil?
26
+ hudWidget.objectName = "hudWidget"
27
+ end
28
+ hudWidget.resize(161, 130)
29
+ @sizePolicy = Qt::SizePolicy.new(Qt::SizePolicy::MinimumExpanding, Qt::SizePolicy::MinimumExpanding)
30
+ @sizePolicy.setHorizontalStretch(0)
31
+ @sizePolicy.setVerticalStretch(0)
32
+ @sizePolicy.heightForWidth = hudWidget.sizePolicy.hasHeightForWidth
33
+ hudWidget.sizePolicy = @sizePolicy
34
+ @palette = Qt::Palette.new
35
+ brush = Qt::Brush.new(Qt::Color.new(255, 255, 255, 255))
36
+ brush.style = Qt::SolidPattern
37
+ @palette.setBrush(Qt::Palette::Active, Qt::Palette::Base, brush)
38
+ brush1 = Qt::Brush.new(Qt::Color.new(224, 223, 222, 100))
39
+ brush1.style = Qt::SolidPattern
40
+ @palette.setBrush(Qt::Palette::Active, Qt::Palette::Window, brush1)
41
+ @palette.setBrush(Qt::Palette::Inactive, Qt::Palette::Base, brush)
42
+ @palette.setBrush(Qt::Palette::Inactive, Qt::Palette::Window, brush1)
43
+ @palette.setBrush(Qt::Palette::Disabled, Qt::Palette::Base, brush1)
44
+ @palette.setBrush(Qt::Palette::Disabled, Qt::Palette::Window, brush1)
45
+ hudWidget.palette = @palette
46
+ @verticalLayout = Qt::VBoxLayout.new(hudWidget)
47
+ @verticalLayout.objectName = "verticalLayout"
48
+ @lBspeed = Qt::Label.new(hudWidget)
49
+ @lBspeed.objectName = "lBspeed"
50
+ @sizePolicy1 = Qt::SizePolicy.new(Qt::SizePolicy::Preferred, Qt::SizePolicy::MinimumExpanding)
51
+ @sizePolicy1.setHorizontalStretch(0)
52
+ @sizePolicy1.setVerticalStretch(0)
53
+ @sizePolicy1.heightForWidth = @lBspeed.sizePolicy.hasHeightForWidth
54
+ @lBspeed.sizePolicy = @sizePolicy1
55
+ @font = Qt::Font.new
56
+ @font.pointSize = 18
57
+ @font.bold = true
58
+ @font.weight = 75
59
+ @font.styleStrategy = Qt::Font::PreferAntialias
60
+ @lBspeed.font = @font
61
+ @lBspeed.frameShape = Qt::Frame::Panel
62
+ @lBspeed.frameShadow = Qt::Frame::Sunken
63
+ @lBspeed.alignment = Qt::AlignCenter
64
+
65
+ @verticalLayout.addWidget(@lBspeed)
66
+
67
+ @lBdistance = Qt::Label.new(hudWidget)
68
+ @lBdistance.objectName = "lBdistance"
69
+ @sizePolicy1.heightForWidth = @lBdistance.sizePolicy.hasHeightForWidth
70
+ @lBdistance.sizePolicy = @sizePolicy1
71
+ @lBdistance.font = @font
72
+ @lBdistance.frameShape = Qt::Frame::Panel
73
+ @lBdistance.frameShadow = Qt::Frame::Sunken
74
+ @lBdistance.alignment = Qt::AlignCenter
75
+
76
+ @verticalLayout.addWidget(@lBdistance)
77
+
78
+ @gridLayout = Qt::GridLayout.new()
79
+ @gridLayout.objectName = "gridLayout"
80
+ @label_4 = Qt::Label.new(hudWidget)
81
+ @label_4.objectName = "label_4"
82
+ @font1 = Qt::Font.new
83
+ @font1.family = "DejaVu Sans"
84
+ @font1.pointSize = 9
85
+ @label_4.font = @font1
86
+
87
+ @gridLayout.addWidget(@label_4, 0, 0, 1, 1)
88
+
89
+ @lBalt = Qt::Label.new(hudWidget)
90
+ @lBalt.objectName = "lBalt"
91
+ @lBalt.font = @font1
92
+ @lBalt.frameShape = Qt::Frame::Panel
93
+ @lBalt.frameShadow = Qt::Frame::Sunken
94
+
95
+ @gridLayout.addWidget(@lBalt, 0, 1, 1, 1)
96
+
97
+ @label_3 = Qt::Label.new(hudWidget)
98
+ @label_3.objectName = "label_3"
99
+ @label_3.font = @font1
100
+
101
+ @gridLayout.addWidget(@label_3, 0, 2, 1, 1)
102
+
103
+ @lBheading = Qt::Label.new(hudWidget)
104
+ @lBheading.objectName = "lBheading"
105
+ @lBheading.font = @font1
106
+ @lBheading.frameShape = Qt::Frame::Panel
107
+ @lBheading.frameShadow = Qt::Frame::Sunken
108
+
109
+ @gridLayout.addWidget(@lBheading, 0, 3, 1, 1)
110
+
111
+ @label_6 = Qt::Label.new(hudWidget)
112
+ @label_6.objectName = "label_6"
113
+ @label_6.font = @font1
114
+
115
+ @gridLayout.addWidget(@label_6, 1, 0, 1, 1)
116
+
117
+ @lBlat = Qt::Label.new(hudWidget)
118
+ @lBlat.objectName = "lBlat"
119
+ @lBlat.font = @font1
120
+ @lBlat.frameShape = Qt::Frame::Panel
121
+ @lBlat.frameShadow = Qt::Frame::Sunken
122
+
123
+ @gridLayout.addWidget(@lBlat, 1, 1, 1, 1)
124
+
125
+ @label_5 = Qt::Label.new(hudWidget)
126
+ @label_5.objectName = "label_5"
127
+ @label_5.font = @font1
128
+
129
+ @gridLayout.addWidget(@label_5, 1, 2, 1, 1)
130
+
131
+ @lBlon = Qt::Label.new(hudWidget)
132
+ @lBlon.objectName = "lBlon"
133
+ @lBlon.font = @font1
134
+ @lBlon.frameShape = Qt::Frame::Panel
135
+ @lBlon.frameShadow = Qt::Frame::Sunken
136
+
137
+ @gridLayout.addWidget(@lBlon, 1, 3, 1, 1)
138
+
139
+
140
+ @verticalLayout.addLayout(@gridLayout)
141
+
142
+
143
+ retranslateUi(hudWidget)
144
+
145
+ Qt::MetaObject.connectSlotsByName(hudWidget)
146
+ end # setupUi
147
+
148
+ def setup_ui(hudWidget)
149
+ setupUi(hudWidget)
150
+ end
151
+
152
+ def retranslateUi(hudWidget)
153
+ hudWidget.windowTitle = Qt::Application.translate("HudWidget", "Form", nil, Qt::Application::UnicodeUTF8)
154
+ @lBspeed.text = ''
155
+ @lBdistance.text = ''
156
+ @label_4.text = Qt::Application.translate("HudWidget", "Alt:", nil, Qt::Application::UnicodeUTF8)
157
+ @label_3.text = Qt::Application.translate("HudWidget", "Head:", nil, Qt::Application::UnicodeUTF8)
158
+ @label_6.text = Qt::Application.translate("HudWidget", "Lat:", nil, Qt::Application::UnicodeUTF8)
159
+ @label_5.text = Qt::Application.translate("HudWidget", "Lon:", nil, Qt::Application::UnicodeUTF8)
160
+ end # retranslateUi
161
+
162
+ def retranslate_ui(hudWidget)
163
+ retranslateUi(hudWidget)
164
+ end
165
+
166
+ end
167
+
168
+ module Ui
169
+ class HudWidget < Ui_HudWidget
170
+ end
171
+ end # module Ui
172
+
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ ##################################################
3
+ # Flightgear Mapping
4
+ #
5
+ # Provide a real-time map of flight position in Flightgear. It is based on tiles from Openstreetmap,
6
+ # downloads them in the background, provides navigation aids and runways, allows setting of waypoints
7
+ # and tracks the flight.
8
+ #
9
+ # License
10
+ # GPL V2
11
+ #
12
+ # Author Michael Meltner (mmeltner@gmail.com)
13
+ ##################################################
14
+
15
+ Dir.chdir(File.dirname(__FILE__))
16
+
17
+ load "waypoint.rb"
18
+
@@ -0,0 +1,1117 @@
1
+ ##################################################
2
+ # Flightgear Mapping
3
+ #
4
+ # Provide a real-time map of flight position in Flightgear. It is based on tiles from Openstreetmap,
5
+ # downloads them in the background, provides navigation aids and runways, allows setting of waypoints
6
+ # and tracks the flight.
7
+ #
8
+ # License
9
+ # GPL V2
10
+ #
11
+ # Author Michael Meltner (mmeltner@gmail.com)
12
+ ##################################################
13
+
14
+ require 'net/http'
15
+ require "main-dlg"
16
+ require "tile"
17
+ require "resources"
18
+ require 'socket'
19
+ require "hud-impl"#
20
+ # Author Michael Meltner (mmeltner@gmail.com)
21
+
22
+ require "nodeinfo-impl"
23
+ require 'navaid.rb'
24
+ require "xml"
25
+ begin
26
+ require "ap"
27
+ rescue LoadError
28
+ def ap(*k)
29
+ p k
30
+ end
31
+ end
32
+
33
+ OFFSET_FLAG_X = 3
34
+ OFFSET_FLAG_Y = 21
35
+ OFFSET_PIN_X = 1
36
+ OFFSET_PIN_Y = 23
37
+ OFFSET_FLAG_COUNTER_X = 5
38
+ OFFSET_FLAG_COUNTER_Y = -8
39
+ ILSSIZE = 140 # in pixel
40
+ ILSCONEANGLE = 10 # in degree
41
+ ILSTEXTOFFSET = 10 # in pixel
42
+
43
+ Z_VALUE_TILES = 0
44
+ Z_VALUE_TRACK = 1
45
+ Z_VALUE_TRACK_COLORED = 2
46
+ Z_VALUE_WAYPOINT = 3
47
+ Z_VALUE_ORIGIN = 4
48
+ Z_VALUE_ROSE = 5
49
+ Z_VALUE_POINTERTOORIGIN = 6
50
+ Z_VALUE_POINTER = 7
51
+ Z_VALUE_NAV = 8
52
+ Z_VALUE_HUD = 10
53
+ SCALE_SVG = 0.3
54
+
55
+ COLORRANGE_DEG = 120.0
56
+ COLOROFFSET_DEG = 240.0
57
+
58
+ MINSPEED = 0.3 # minimum speed required for heading marker to appear, in m/s
59
+ FS_READ_INTERVAL = 100 # enter GUI refresh loop every 100ms
60
+ TICKSTOSKIP = 20
61
+ AUTOSAVE_INTERVAL = 10 * 60 * 1000 # autosave interval for tracks
62
+ HOVER_TIMER = 2000 # time until HUD widget disappears
63
+ MAXVORSTODISPLAY = 500 # maximum number of nav-aids to display on map
64
+ MAXILSTODISPLAY = 200
65
+
66
+ FS_PORT = 2948
67
+
68
+
69
+ #LATSTARTUP = 49.462126667
70
+ #LONSTARTUP = 11.121691667
71
+ LATSTARTUP = 50.0368400387281
72
+ LONSTARTUP = 8.55965957641601
73
+
74
+ MAPSDIR = ENV['HOME'] + "/.OpenstreetmapTiles"
75
+
76
+ #GC.disable
77
+
78
+ # Class MainDlg ############################################
79
+ class MainDlg < Qt::Widget
80
+ attr_reader :node, :scene_tiles, :scene, :toffset_x, :offset_y, :menu, :waypoints, \
81
+ :flag, :zoom, :mytracks, :mytrack_current, :w
82
+ attr_writer :node, :scene_tiles, :offset_x, :offset_y, :waypoints, :mytrack_current, :w
83
+ attr_accessor :metricUnit
84
+
85
+ slots "pBexit_clicked()", "pBdo_clicked()", "pBplus_clicked()", "pBminus_clicked()", \
86
+ "cBpointorigin_clicked()", "pBrecordTrack_toggled(bool)", "wakeupTimer()", "autosaveTimer()", \
87
+ 'cBvor_clicked()', 'cBndb_clicked()', 'cBrw_clicked()'
88
+
89
+ def initialize(parent, arg)
90
+ super(parent)
91
+ @w=Ui::MainDlg.new
92
+ @w.setupUi(self)
93
+ @parent=parent
94
+
95
+ @cfg=Qt::Settings.new("MMeltnerSoft", "fg_map")
96
+ @metricUnit = @cfg.value("metricUnit",Qt::Variant.new(true)).toBool
97
+ @zoom = @cfg.value("zoom",Qt::Variant.new(13)).toInt
98
+ @lat = @cfg.value("lat",Qt::Variant.new(LATSTARTUP)).toDouble
99
+ @lon = @cfg.value("lon",Qt::Variant.new(LONSTARTUP)).toDouble
100
+ @w.cBrw.setChecked(@cfg.value("rwChecked",Qt::Variant.new(false)).toBool)
101
+ @w.cBndb.setChecked(@cfg.value("nbdChecked",Qt::Variant.new(false)).toBool)
102
+ @w.cBvor.setChecked(@cfg.value("vorChecked",Qt::Variant.new(true)).toBool)
103
+
104
+ @flag=Qt::Pixmap.new(":/icons/flag-blue.png")
105
+ @pin=Qt::Pixmap.new(":/icons/wpttemp-red.png")
106
+ @linepen = Qt::Pen.new
107
+ @linepen.setWidth(5)
108
+ @colors={:index => 0, :selection => ["Red", "Yellow", "Green"]}
109
+ @graphicsSceneFont = Qt::Font.new("Helvetica", 7)
110
+ @graphicsSceneBrush = Qt::Brush.new(Qt::Color.new(255, 255, 255, 150))
111
+ @ilsBrush = Qt::Brush.new(Qt::Color.new(0, 0, 0, 150))
112
+ @noPen = Qt::Pen.new(Qt::NoPen)
113
+
114
+ @wakeupTimer = Qt::Timer.new( self )
115
+ Qt::Object.connect( @wakeupTimer, SIGNAL('timeout()'), self, SLOT('wakeupTimer()') )
116
+ @wakeupTimer.start( FS_READ_INTERVAL )
117
+ @wakeupCounter = 0
118
+ @autosaveTimer = Qt::Timer.new( self )
119
+ Qt::Object.connect( @autosaveTimer, SIGNAL('timeout()'), self, SLOT('autosaveTimer()') )
120
+ @autosaveTimer.start( AUTOSAVE_INTERVAL )
121
+
122
+ @offset_x=@offset_y=0
123
+ @fs_ans=[]
124
+ @fs_queries=["/position/latitude-deg", "/position/longitude-deg", "/position/ground-elev-m",
125
+ "/orientation/heading-deg", "/velocities/groundspeed-kt"]
126
+
127
+ @waypoints=Way.new(nil,'user', Time.now, "Blue")
128
+ @mytracks=[]
129
+ @mytrack_current=-1
130
+ @prev_track_node = nil
131
+ @posnode = Node.new(1, Time.now, @lon, @lat)
132
+
133
+ @node = Node.new(1, Time.now, @lon, @lat, 0, @zoom)
134
+ @rot = 0
135
+ @remainingTiles = 0
136
+ @httpThreads = Array.new
137
+
138
+ @navs = Navaid.new(arg)
139
+
140
+ @httpMutex = Mutex.new
141
+
142
+ @scene=Qt::GraphicsScene.new()
143
+ @w.gVmap.setScene(@scene)
144
+ @w.lBzoom.setText(@zoom.to_s)
145
+ vorGraphic=Qt::GraphicsSvgItem.new(":/icons/vor.svg")
146
+ vorGraphic.setElementId("VOR")
147
+ boundingrect = vorGraphic.boundingRect
148
+ @vor_offsetx = boundingrect.right / 2
149
+ @vor_offsety = boundingrect.bottom / 2
150
+
151
+ begin
152
+ @fs_socket = TCPSocket.open('localhost', FS_PORT)
153
+ @fs_socket.puts "reset"
154
+ rescue
155
+ #swallow all errors
156
+ end
157
+
158
+ if FileTest.directory?(MAPSDIR) then
159
+ $MAPSHOME = MAPSDIR
160
+ else
161
+ resp = Qt::MessageBox::question(nil, "No local Map Directory found.", "Create one?", Qt::MessageBox::No, Qt::MessageBox::Yes)
162
+ if resp == Qt::MessageBox::Yes then
163
+ Dir.mkdir(MAPSDIR)
164
+ $MAPSHOME = MAPSDIR
165
+ else
166
+ $MAPSHOME = "./"
167
+ end
168
+ end
169
+ puts "Map Directory located here: \"#{$MAPSHOME}\""
170
+ end
171
+
172
+ def get_data(path)
173
+ r=@fs_ans.detect do |f|
174
+ f.include?(path)
175
+ end
176
+ r =~ /-?\d+\.\d+/
177
+ return $&.to_f
178
+ end
179
+
180
+ def putflag(x,y,i,node)
181
+ flag=FlagGraphicsPixmapItem.new(@flag)
182
+ flag.setOffset(x - OFFSET_FLAG_X, y - OFFSET_FLAG_Y)
183
+ t=Qt::GraphicsTextItem.new(i.to_s, flag)
184
+ t.setPos(x + OFFSET_FLAG_COUNTER_X, y + OFFSET_FLAG_COUNTER_Y)
185
+ flag.setZValue(Z_VALUE_WAYPOINT)
186
+ tooltip=("Lon: %.3f�"%node.lon)+("\nLat: %.3f�"%node.lat)
187
+ if node.elevation>0 then
188
+ tooltip += ("\nElevation: %.1fm" % node.elevation)
189
+ end
190
+ flag.setToolTip(tooltip)
191
+ @scene.addItem(flag)
192
+ end
193
+
194
+ def nextcolor
195
+ col=@colors[:selection][@colors[:index]]
196
+ if col.nil? then
197
+ col=@colors[:selection][0]
198
+ @colors[:index] = 0
199
+ else
200
+ @colors[:index] += 1
201
+ end
202
+ return col
203
+ end
204
+
205
+ def savetrack(items, warn=true)
206
+ if items[0].nil? or items[0].nodes.length == 0 then
207
+ Qt::MessageBox::warning(nil, "Warning", "No data recorded yet.") if warn
208
+ else
209
+ begin
210
+ Dir.mkdir($MAPSHOME + "/tracks")
211
+ rescue Errno::EEXIST
212
+ # just swallow error
213
+ end
214
+
215
+ doc = XML::Document.new()
216
+ doc.root = XML::Node.new('gpx')
217
+ doc.root["xmlns"] = "http://www.topografix.com/GPX/1/1"
218
+ doc.root["creator"] = "ruby-tracker"
219
+ doc.root["version"] = "1.1"
220
+ doc.root["xmlns:xsi"] = "http://www.w3.org/2001/XMLSchema-instance"
221
+ doc.root["xsi:schemaLocation"] = "http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"
222
+
223
+ tracknode = XML::Node.new("trk")
224
+ doc.root << tracknode
225
+ items.each{|track|
226
+ segnode = XML::Node.new("trkseg")
227
+ tracknode << segnode
228
+ track.nodes.each{|n|
229
+ trackpoint = XML::Node.new("trkpt")
230
+ trackpoint["lat"] = n.lat.to_s.gsub(",",".")
231
+ trackpoint["lon"] = n.lon.to_s.gsub(",",".")
232
+ trackpoint << XML::Node.new("ele", n.elevation.to_s.gsub(",","."))
233
+ trackpoint << XML::Node.new("time", n.toGPStime)
234
+ segnode << trackpoint
235
+ }
236
+ }
237
+ File.open($MAPSHOME + "/tracks/" + items.first.nodes.first.toGPStime + ".gpx", "w+"){|f|
238
+ f.puts doc.inspect
239
+ }
240
+ end
241
+ end
242
+
243
+ def loadtrack(title)
244
+ fn=Qt::FileDialog::getOpenFileName(nil, title, $MAPSHOME + "/tracks/", "Track-Data (*.gpx *.log);;All (*)")
245
+ if !fn.nil? then
246
+ success = false
247
+ doc = XML::Document.file(fn)
248
+ doc.find('/ns:gpx/ns:trk', "ns:http://www.topografix.com/GPX/1/1").each{|trk|
249
+ @mytrack_current -= 1
250
+ trk.find("ns:trkseg", "ns:http://www.topografix.com/GPX/1/1").each{|seg|
251
+ ns = XML::Namespace.new(seg, 'ns', 'http://www.topografix.com/GPX/1/1')
252
+ seg.namespaces.namespace=ns
253
+ @mytrack_current += 1
254
+ if @mytracks[@mytrack_current].nil? then
255
+ @mytracks[@mytrack_current] = Way.new(1, 'user', Time.now, nextcolor)
256
+ @prev_track_node = nil
257
+ end
258
+ track=@mytracks[@mytrack_current]
259
+ track.nodes.clear
260
+ xpat_time = XML::XPath::Expression.new("ns:time")
261
+ xpat_elevation = XML::XPath::Expression.new("ns:ele")
262
+ seg.find("ns:trkpt", "ns:http://www.topografix.com/GPX/1/1").each{|tpt|
263
+ track << Node.new(nil, tpt.find_first(xpat_time).content, tpt["lon"].to_f, \
264
+ tpt["lat"].to_f, tpt.find_first(xpat_elevation).content.to_f)
265
+ success = true
266
+ }
267
+ }
268
+ }
269
+ if success then
270
+ movemap(@node, true)
271
+ else
272
+ Qt::MessageBox::warning(nil, "Warning", "No data found in file.")
273
+ end
274
+ return success
275
+ end
276
+ end
277
+
278
+ def loadwaypoint(title)
279
+ fn=Qt::FileDialog::getOpenFileName(nil, title, $MAPSHOME + "/waypoints/", "Waypoint-Data (*.gpx *.log);;All (*)")
280
+ if !fn.nil? then
281
+ success = false
282
+ doc = XML::Document.file(fn)
283
+ @waypoints = Way.new(nil,'user', Time.now, "Blue")
284
+ doc.find("/ns:gpx/ns:wpt", "ns:http://www.topografix.com/GPX/1/1").each{ |wpt|
285
+ ns = XML::Namespace.new(wpt, 'ns', 'http://www.topografix.com/GPX/1/1')
286
+ wpt.namespaces.namespace = ns
287
+ xpat_time = XML::XPath::Expression.new("ns:time")
288
+ xpat_elevation = XML::XPath::Expression.new("ns:ele")
289
+ @waypoints << Node.new(nil, wpt.find_first(xpat_time).content, wpt["lon"].to_f, \
290
+ wpt["lat"].to_f, wpt.find_first(xpat_elevation).content.to_f)
291
+ success = true
292
+ }
293
+ if success then
294
+ movemap(@node, true)
295
+ else
296
+ Qt::MessageBox::warning(nil, "Warning", "No data found in file.")
297
+ end
298
+ return success
299
+ end
300
+ end
301
+
302
+ def saveWaypoints(waypoints)
303
+ if waypoints.length == 0 then
304
+ Qt::MessageBox::warning(nil, "Warning", "No waypoints set yet.") if warn
305
+ else
306
+ begin
307
+ Dir.mkdir($MAPSHOME + "/waypoints")
308
+ rescue Errno::EEXIST
309
+ # just swallow error
310
+ end
311
+
312
+ doc = XML::Document.new()
313
+ doc.root = XML::Node.new('gpx')
314
+ doc.root["xmlns"] = "http://www.topografix.com/GPX/1/1"
315
+ doc.root["creator"] = "ruby-tracker"
316
+ doc.root["version"] = "1.1"
317
+ doc.root["xmlns:xsi"] = "http://www.w3.org/2001/XMLSchema-instance"
318
+ doc.root["xsi:schemaLocation"] = "http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"
319
+
320
+ waypoints[0].nodes.each{|n|
321
+ if !n.nil? then
322
+ wpnode = XML::Node.new("wpt")
323
+ doc.root << wpnode
324
+ wpnode["lat"] = n.lat.to_s.gsub(",",".")
325
+ wpnode["lon"] = n.lon.to_s.gsub(",",".")
326
+ wpnode << XML::Node.new("ele", n.elevation.to_s.gsub(",","."))
327
+ wpnode << XML::Node.new("time", n.toGPStime)
328
+ end
329
+ }
330
+ fn=Qt::FileDialog::getSaveFileName(nil, "Save Waypoint File", $MAPSHOME + "/waypoints/", "Waypoint-Data (*.gpx *.log);;All (*)","*.gpx")
331
+
332
+ if !fn.nil? then
333
+ if fn !~ /\.gpx$/ then
334
+ fn += ".gpx"
335
+ end
336
+ File.open(fn, "w+"){|f|
337
+ f.puts doc.inspect
338
+ }
339
+ end
340
+ end
341
+ end
342
+
343
+ def zoomplus
344
+ @httpThreads.each do |th|
345
+ th.kill
346
+ end
347
+ @httpThreads = Array.new
348
+ @remainingTiles = 0
349
+ @scene.removeItem(@warningText)
350
+
351
+ @zoom += 1
352
+ @zoom=17 if @zoom>17
353
+ @zoom=3 if @zoom<3
354
+ @w.lBzoom.setText(@zoom.to_s)
355
+ @node.zoom(@zoom)
356
+ @offset_x *= 2
357
+ @offset_y *= 2
358
+ movemap(@node, true)
359
+ end
360
+
361
+ def zoomminus
362
+ @httpThreads.each do |th|
363
+ th.kill
364
+ end
365
+ @remainingTiles = 0
366
+ @httpThreads = Array.new
367
+ @scene.removeItem(@warningText)
368
+
369
+ @zoom -= 1
370
+ @zoom=17 if @zoom>17
371
+ @zoom=3 if @zoom<3
372
+ @w.lBzoom.setText(@zoom.to_s)
373
+ @node.zoom(@zoom)
374
+ @offset_x /= 2
375
+ @offset_y /= 2
376
+ movemap(@node, true)
377
+ end
378
+
379
+ def addTileToScene(f, origin_x, origin_y)
380
+ pmi=TileGraphicsPixmapItem.new(Qt::Pixmap.new(f))
381
+ @scene_tiles << f
382
+ f =~ /\/(\d*)\/(\d*)\/(\d*)/
383
+ x = $2.to_i
384
+ y = $3.to_i
385
+ # p x - origin_x,y - origin_y
386
+ pmi.setOffset((x - origin_x)*256, (y - origin_y)*256)
387
+ pmi.setZValue(Z_VALUE_TILES)
388
+ @scene.addItem(pmi)
389
+ end
390
+
391
+ def addNavToScene(vor, origin_x, origin_y)
392
+ vorGraphic = Qt::GraphicsSvgItem.new(":/icons/vor.svg")
393
+ vorGraphic.setElementId(vor.type)
394
+ vorGraphic.setTransform(Qt::Transform.new.translate(-@vor_offsetx, -@vor_offsety))
395
+ vorGraphic.setZValue(Z_VALUE_NAV)
396
+ @scene.addItem(vorGraphic)
397
+ vorNode = Node.new(0, nil, vor.lon.to_f, vor.lat.to_f)
398
+ vorGraphic.setPos((vorNode.toxtile - origin_x) * 256, (vorNode.toytile - origin_y) * 256)
399
+ vor.sceneItem = vorGraphic
400
+
401
+ # create text on Navaid
402
+ textString = vor.shortName + " " + vor.freq.to_s
403
+ text=Qt::GraphicsSimpleTextItem.new(textString)
404
+ text.setFont(@graphicsSceneFont)
405
+ bounding = text.boundingRect
406
+ background = Qt::GraphicsRectItem.new(bounding)
407
+ background.setBrush(@graphicsSceneBrush)
408
+ background.setPen(@noPen)
409
+ background.setToolTip(textString + "; " + vor.longName)
410
+ background.setPos(@vor_offsetx - bounding.width / 2, 2*@vor_offsety+3)
411
+ text.setParentItem(background)
412
+ background.setParentItem(vorGraphic)
413
+ end
414
+
415
+ def addRunwayToScene(rw, origin_x, origin_y)
416
+ rwNode = Node.new(0, nil, rw.lon.to_f, rw.lat.to_f)
417
+
418
+ # create text
419
+ textString = rw.airportName + " " + rw.freq.to_s
420
+ text=Qt::GraphicsSimpleTextItem.new(textString)
421
+ text.setFont(@graphicsSceneFont)
422
+ bounding = text.boundingRect
423
+ background = Qt::GraphicsRectItem.new(bounding)
424
+ background.setTransform(Qt::Transform.new.translate(-bounding.width / 2, ILSTEXTOFFSET))
425
+ background.setZValue(Z_VALUE_NAV)
426
+ background.setBrush(@graphicsSceneBrush)
427
+ background.setPen(@noPen)
428
+ background.setToolTip(textString)
429
+ text.setParentItem(background)
430
+ background.setPos((rwNode.toxtile - origin_x) * 256, (rwNode.toytile - origin_y) * 256)
431
+
432
+ rwGraphic = Qt::GraphicsEllipseItem.new(0,0,ILSSIZE,ILSSIZE)
433
+ rwGraphic.setStartAngle(ILSCONEANGLE*8)
434
+ rwGraphic.setSpanAngle(-ILSCONEANGLE*16)
435
+ rwGraphic.setTransform(Qt::Transform.new.translate(bounding.width/ 2, -ILSTEXTOFFSET).rotate(rw.direction + 90).translate(-ILSSIZE / 2, -ILSSIZE / 2))
436
+ rwGraphic.setPen(@noPen)
437
+ rwGraphic.setBrush(@ilsBrush)
438
+ rwGraphic.setFlag(Qt::GraphicsItem::ItemStacksBehindParent)
439
+
440
+ rwGraphic.setParentItem(background)
441
+ @scene.addItem(background)
442
+ rw.sceneItem = background
443
+ end
444
+
445
+ def movemap(node, repaint=false, downloadTiles=true)
446
+ origin_x=node.xtile
447
+ origin_y=node.ytile
448
+
449
+ if repaint then
450
+ @scene_tiles = []
451
+ @scene_navs = []
452
+ @scene_rws = []
453
+ @scene.clear
454
+ # 8 : 256 = 2**8
455
+ size = 2**(@zoom + 8)
456
+ sceneRect = Qt::RectF.new(0,0,size,size)
457
+ sceneRect.moveCenter(Qt::PointF.new(@node.xtile, @node.ytile))
458
+ @scene.setSceneRect(sceneRect)
459
+ end
460
+
461
+ vorsToDisplay = @navs.getVORs(node.getLatLonBox(@w.gVmap.size, @offset_x, @offset_y))
462
+ if vorsToDisplay.length < MAXVORSTODISPLAY then
463
+ vorsToDisplay.each do |vor|
464
+ if !@scene_navs.include?(vor)
465
+ if (@w.cBndb.isChecked and vor.type == "NDB") or
466
+ (@w.cBvor.isChecked and vor.type != "NDB") then
467
+ @scene_navs << vor
468
+ addNavToScene(vor, origin_x, origin_y)
469
+ end
470
+ end
471
+ end
472
+ elsif !@scene_navs.empty? then
473
+ repaint = true
474
+ @scene_tiles = []
475
+ @scene_navs = []
476
+ @scene_rws = []
477
+ @scene.clear
478
+ end
479
+
480
+ if @w.cBrw.isChecked then
481
+ runwaysToDisplay = @navs.getRunways(node.getLatLonBox(@w.gVmap.size, @offset_x, @offset_y))
482
+ if runwaysToDisplay.length < MAXILSTODISPLAY then
483
+ runwaysToDisplay.each do |runway|
484
+ if !@scene_rws.include?(runway)
485
+ @scene_rws << runway
486
+ addRunwayToScene(runway, origin_x, origin_y)
487
+ end
488
+ end
489
+ end
490
+ elsif !@scene_rws.empty? then
491
+ repaint = true
492
+ @scene_tiles = []
493
+ @scene_navs = []
494
+ @scene_rws = []
495
+ @scene.clear
496
+ end
497
+
498
+ fn = node.getfilenames(@w.gVmap.size, @offset_x, @offset_y)
499
+
500
+ fn.each{|f|
501
+ if !@scene_tiles.include?(f)
502
+ if FileTest.exist?(f+".png") then
503
+ addTileToScene(f, origin_x, origin_y)
504
+ elsif downloadTiles and (@timeNoInternet.nil? or (Time.now - @timeNoInternet) > 60) then
505
+ @httpThreads << Thread.new {
506
+ @remainingTiles += 1
507
+ @httpMutex.synchronize {
508
+ @warningText = Qt::GraphicsSimpleTextItem.new("#{@remainingTiles} remaining tiles")
509
+ @warningText.setBrush(Qt::Brush.new(Qt::Color.new("red")))
510
+ @scene.addItem(@warningText)
511
+ fontInfo = Qt::FontInfo.new(@warningText.font)
512
+ @warningText.setPos(@w.gVmap.mapToScene((@w.gVmap.size.width - @warningText.boundingRect.width)/2,
513
+ @w.gVmap.size.height - fontInfo.pixelSize - 10))
514
+
515
+ h = Net::HTTP.new('tile.openstreetmap.org')
516
+ f =~ /\/\d+\/\d+\/\d+$/
517
+ f = $&
518
+ resp, data = h.get(f + ".png", nil)
519
+ if resp.kind_of?(Net::HTTPOK) then
520
+ maindir = Dir.pwd
521
+ Dir.chdir($MAPSHOME)
522
+ f.split("/")[0..-2].each do |dir|
523
+ if !dir.empty? then
524
+ begin
525
+ Dir.mkdir(dir)
526
+ rescue Errno::EEXIST
527
+ # just swallow error
528
+ end
529
+ Dir.chdir(dir)
530
+ end
531
+ end
532
+ Dir.chdir(maindir)
533
+ File.open($MAPSHOME + f + ".png", "w") do |file|
534
+ file.write(data)
535
+ end
536
+ addTileToScene($MAPSHOME + f, origin_x, origin_y)
537
+ else
538
+ puts "Could not download tile. Internet connection alive?"
539
+ @timeNoInternet=Time.now
540
+ end
541
+ @scene.removeItem(@warningText)
542
+ }
543
+ @remainingTiles -= 1
544
+ }
545
+ else
546
+ puts "Internet timeout still running"
547
+ end
548
+ end
549
+ }
550
+
551
+ if repaint then
552
+ mainnode_x=node.toxtile
553
+ mainnode_y=node.toytile
554
+
555
+ # set waypoint flags
556
+ i=1
557
+ @waypoints.nodes.each {|node|
558
+ if !node.nil? then
559
+ putflag((node.toxtile - mainnode_x) * 256, (node.toytile - mainnode_y) * 256, i, node)
560
+ end
561
+ i+=1
562
+ }
563
+ # set origin pin
564
+ pmi=Qt::GraphicsPixmapItem.new(@pin)
565
+ pmi.setOffset(OFFSET_PIN_X, -OFFSET_PIN_Y)
566
+ pmi.setZValue(Z_VALUE_ORIGIN)
567
+ @scene.addItem(pmi)
568
+
569
+ # create hud display
570
+ # needs to be embedded in other graphics element to circumvent a bug if the position of
571
+ # the ProxyWidget is above, below 2**15 - 1, bug in QT
572
+ @hud=Qt::GraphicsRectItem.new(0,0,10,10)
573
+ @hud.setPen(@noPen)
574
+ hud=Qt::GraphicsProxyWidget.new(@hud)
575
+ @hud_widget = HudWidget.new()
576
+ hud.setWidget(@hud_widget)
577
+ @hud.setZValue(Z_VALUE_HUD)
578
+ @scene.addItem(@hud)
579
+ @hud.setPos(@w.gVmap.mapToScene(0,0))
580
+
581
+ # create rose
582
+ @rose=Qt::GraphicsSvgItem.new(":/icons/rose.svg")
583
+ @rose.setElementId("rose")
584
+ boundingrect = @rose.boundingRect
585
+ rose_offsetx = boundingrect.right / 2
586
+ rose_offsety = boundingrect.bottom / 2
587
+ @rose.setTransform(Qt::Transform.new.scale(SCALE_SVG,SCALE_SVG).translate(-rose_offsetx, -rose_offsety))
588
+ @rose.setZValue(Z_VALUE_ROSE)
589
+ @scene.addItem(@rose)
590
+ @rose.setPos((@posnode.toxtile - mainnode_x) * 256, (@posnode.toytile - mainnode_y) * 256)
591
+
592
+ # create bearing-pointer
593
+ @pointer=Qt::GraphicsSvgItem.new(":/icons/rose.svg")
594
+ @pointer.setElementId("zeiger")
595
+ boundingrect = @pointer.boundingRect
596
+ @pointer_offsetx = boundingrect.right / 2
597
+ @pointer.setTransform(Qt::Transform.new.scale(SCALE_SVG,SCALE_SVG).rotate(0).translate(-@pointer_offsetx, 0))
598
+ @pointer.setZValue(Z_VALUE_POINTER)
599
+ @scene.addItem(@pointer)
600
+ @pointer.setPos((@posnode.toxtile - mainnode_x) * 256, (@posnode.toytile - mainnode_y) * 256)
601
+
602
+ # create pointer to origin
603
+ @pointertoorigin=Qt::GraphicsSvgItem.new(":/icons/rose.svg")
604
+ @pointertoorigin.setElementId("zeigertoorigin")
605
+ boundingrect = @pointertoorigin.boundingRect
606
+ @pointertoorigin_offsetx = boundingrect.right / 2
607
+ @pointertoorigin.setTransform(Qt::Transform.new.scale(SCALE_SVG,SCALE_SVG).rotate(0).translate(-@pointertoorigin_offsetx, 0))
608
+ @pointertoorigin.setZValue(Z_VALUE_POINTERTOORIGIN)
609
+ @scene.addItem(@pointertoorigin)
610
+ @pointertoorigin.setPos((@posnode.toxtile - mainnode_x) * 256, (@posnode.toytile - mainnode_y) * 256)
611
+
612
+ # paint tracks
613
+ @mytracks.each {|track|
614
+ prev_node = nil
615
+ if !track.nil? then
616
+ @linepen.setColor(Qt::Color.new(track.color))
617
+ tck=nil
618
+ prev_node=false
619
+ track.nodes.each{|n|
620
+ if !prev_node then
621
+ tck=Qt::PainterPath.new(Qt::PointF.new((n.toxtile - mainnode_x) * 256, (n.toytile - mainnode_y) * 256))
622
+ else
623
+ tck.lineTo((n.toxtile - mainnode_x) * 256, (n.toytile - mainnode_y) * 256)
624
+ end
625
+ prev_node = true
626
+ }
627
+ track.path=TrackGraphicsPathItem.new(track)
628
+ track.path.setPath(tck)
629
+ track.path.setZValue(Z_VALUE_TRACK)
630
+ track.path.setPen(@linepen)
631
+ @scene.addItem(track.path)
632
+ end
633
+ }
634
+ if @w.pBrecordTrack.isChecked then
635
+ @tckpath=@mytracks[@mytrack_current].path.path
636
+ end
637
+ end
638
+
639
+ @w.gVmap.centerOn(@offset_x*256,@offset_y*256)
640
+ if !@hud.nil? then
641
+ @hud.setPos(@w.gVmap.mapToScene(0,0))
642
+ end
643
+ end
644
+
645
+ def wakeupTimer()
646
+ # p "wakeup in"
647
+ # have to do centering every time as QT will not scroll to scene coordinates which have no elements placed there yet
648
+ begin
649
+ @w.gVmap.centerOn(@offset_x*256,@offset_y*256)
650
+ rescue ArgumentError
651
+ # swallow
652
+ end
653
+
654
+ @wakeupCounter += 1
655
+ return if @wakeupCounter <= TICKSTOSKIP
656
+ @wakeupCounter = 0
657
+
658
+ if @fs_socket.nil? then
659
+ begin
660
+ @fs_socket = TCPSocket.open('localhost', FS_PORT)
661
+ movemap(@node, true)
662
+ rescue
663
+ #swallow all errors
664
+ puts "Non-critical socket error: #{$!}"
665
+ end
666
+ else
667
+ begin
668
+ @fs_queries.each do |q|
669
+ @fs_socket.print("get " + q + "\r\n")
670
+ s=""
671
+ while select([@fs_socket], nil, nil, 0.1 ) do
672
+ s += @fs_socket.read(1)
673
+ end
674
+ if s.include?(q) then
675
+ @fs_ans << s.split("\n")
676
+ @fs_ans.flatten!
677
+ end
678
+ end
679
+ rescue
680
+ puts "Warning: Can not communicate with Flightsimulator. Is Telnet interface configured?"
681
+ @scene.removeItem(@rose)
682
+ @scene.removeItem(@pointer)
683
+ @fs_socket = nil
684
+ @hud = nil
685
+ else # rescue
686
+ # p @fs_ans
687
+ if @fs_ans.length>0 then # check if any answer has been received yet.
688
+ if !@hud.nil? then
689
+ @posnode.lon = get_data("/position/longitude-deg")
690
+ @posnode.lat = get_data("/position/latitude-deg")
691
+ @rot = get_data("/orientation/heading-deg")
692
+ @alt = get_data("/position/ground-elev-m")
693
+ @speed = get_data("/velocities/groundspeed-kt") * 1.852
694
+ @hud_widget.w.lBlat.setText("%2.3f�" % @posnode.lat)
695
+ @hud_widget.w.lBlon.setText("%2.3f�" % @posnode.lon)
696
+ @speed=5.0;@alt=1000
697
+ conversion = @metricUnit ? 1 : 0.54
698
+ @hud_widget.w.lBspeed.setText("%3.1f" % (@speed*conversion) + @metricUnit ? " km/h" : "kt")
699
+ @hud_widget.w.lBheading.setText("%3.1f�" % (@rot))
700
+ conversion = @metricUnit ? 1 : 3.281
701
+ @hud_widget.w.lBalt.setText("%3.1f" % (@alt*conversion) + @metricUnit ? "m" : "ft")
702
+ mainnode_x=@node.toxtile
703
+ mainnode_y=@node.toytile
704
+ @rose.setPos((@posnode.toxtile - mainnode_x) * 256, (@posnode.toytile - mainnode_y) * 256)
705
+
706
+ @pointer.setTransform(Qt::Transform.new.scale(SCALE_SVG,SCALE_SVG).rotate(@rot+180.0) \
707
+ .translate(-@pointer_offsetx, -@pointer_offsetx))
708
+ @pointer.setPos((@posnode.toxtile - mainnode_x) * 256 ,(@posnode.toytile - mainnode_y) * 256)
709
+
710
+ to_x = mainnode_x
711
+ to_y = mainnode_y
712
+ to_lon = @node.lon
713
+ to_lat = @node.lat
714
+ if !@w.cBtoorigin.isChecked and !@waypoints.currentwp.nil? then
715
+ if !@waypoints.nodes[@waypoints.currentwp-1].nil? then
716
+ to_x = @waypoints.nodes[@waypoints.currentwp-1].toxtile
717
+ to_y = @waypoints.nodes[@waypoints.currentwp-1].toytile
718
+ to_lon = @waypoints.nodes[@waypoints.currentwp-1].lon
719
+ to_lat = @waypoints.nodes[@waypoints.currentwp-1].lat
720
+ end
721
+ end
722
+ @pointertoorigin.setTransform(Qt::Transform.new.scale(SCALE_SVG,SCALE_SVG).rotateRadians(Math::PI / 2 + \
723
+ Math.atan2((@posnode.toytile - to_y), (@posnode.toxtile - to_x))) \
724
+ .translate(-@pointertoorigin_offsetx, -@pointertoorigin_offsetx))
725
+ @pointertoorigin.setPos((@posnode.toxtile - mainnode_x) * 256 ,(@posnode.toytile - mainnode_y) * 256)
726
+
727
+ @hud_widget.w.lBdistance.text = @posnode.distanceto_str(to_lon, to_lat)
728
+
729
+ if @w.cBautocenter.isChecked then
730
+ @offset_x = @posnode.toxtile - mainnode_x
731
+ @offset_y = @posnode.toytile - mainnode_y
732
+ movemap(@node)
733
+ # @w.gVmap.centerOn(@offset_x*256,@offset_y*256)
734
+ # if !@hud.nil? then
735
+ # @hud.setPos(@w.gVmap.mapToScene(0,0))
736
+ # end
737
+ end
738
+ if @mytrack_current >= 0 and @w.pBrecordTrack.isChecked then
739
+ if @mytracks[@mytrack_current].nil? then
740
+ @mytracks[@mytrack_current] = Way.new(1, 'user', Time.now, nextcolor)
741
+ @linepen.setColor(Qt::Color.new(@mytracks[@mytrack_current].color))
742
+ @prev_track_node = false
743
+ end
744
+ @mytracks[@mytrack_current] << Node.new(nil, Time.now, @posnode.lon, @posnode.lat, @alt)
745
+ n = @mytracks[@mytrack_current].nodes.last
746
+ n.speed = @speed
747
+ if !@prev_track_node then
748
+ @tckpath = Qt::PainterPath.new(Qt::PointF.new((n.toxtile - mainnode_x) * 256, (n.toytile - mainnode_y) * 256))
749
+ @mytracks[@mytrack_current].path=TrackGraphicsPathItem.new(@mytracks[@mytrack_current])
750
+ @mytracks[@mytrack_current].path.setPath(@tckpath)
751
+ @mytracks[@mytrack_current].path.setZValue(Z_VALUE_TRACK)
752
+ @mytracks[@mytrack_current].path.setPen(@linepen)
753
+ @scene.addItem(@mytracks[@mytrack_current].path)
754
+ @prev_track_node = true
755
+ else
756
+ @tckpath.lineTo((n.toxtile - mainnode_x) * 256, (n.toytile - mainnode_y) * 256)
757
+ @mytracks[@mytrack_current].path.setPath(@tckpath)
758
+ end
759
+ end
760
+
761
+ end # if !@hud.nil?
762
+ end # if @fs_ans.length>0
763
+ end # rescue
764
+ @fs_ans=[]
765
+ end # socket nil
766
+ # p "wakeup out"
767
+ end
768
+
769
+ def autosaveTimer()
770
+ savetrack(@mytracks, false)
771
+ end
772
+
773
+ def pBrecordTrack_toggled(state)
774
+ if state
775
+ @mytrack_current += 1
776
+ @w.pBrecordTrack.text = "Recording Track #{@mytrack_current + 1}"
777
+ else
778
+ @w.pBrecordTrack.text = "Record Track #{@mytrack_current + 2}"
779
+ end
780
+ end
781
+
782
+ def cBpointorigin_clicked()
783
+ @w.fRcurrentwp.enabled = !@w.cBtoorigin.isChecked()
784
+ end
785
+
786
+ def pBminus_clicked()
787
+ zoomminus
788
+ end
789
+
790
+ def pBplus_clicked()
791
+ zoomplus
792
+ end
793
+
794
+ def pBexit_clicked()
795
+ puts "Syncing data and exiting."
796
+ @cfg.setValue("metricUnit", Qt::Variant.new(@metricUnit))
797
+ @cfg.setValue("zoom", Qt::Variant.new(@zoom))
798
+ @cfg.setValue("lat", Qt::Variant.new(@node.lat))
799
+ @cfg.setValue("lon", Qt::Variant.new(@node.lon))
800
+ @cfg.setValue("rwChecked", Qt::Variant.new(@w.cBrw.isChecked))
801
+ @cfg.setValue("nbdChecked", Qt::Variant.new(@w.cBndb.isChecked))
802
+ @cfg.setValue("vorChecked", Qt::Variant.new(@w.cBvor.isChecked))
803
+ @cfg.sync
804
+ @parent.close
805
+ end
806
+
807
+ def cBvor_clicked()
808
+ movemap(@node, true)
809
+ end
810
+
811
+ def cBndb_clicked()
812
+ movemap(@node, true)
813
+ end
814
+
815
+ def cBrw_clicked()
816
+ movemap(@node, true)
817
+ end
818
+
819
+ def resize(*k)
820
+ super
821
+ @hud.setPos(@w.gVmap.mapToScene(0,0)) if !@hud.nil?
822
+ end
823
+
824
+ def keyPressEvent(keyevent)
825
+ case keyevent.text
826
+ when "+"
827
+ zoomplus
828
+ when "-"
829
+ zoomminus
830
+ when " "
831
+ @w.pBrecordTrack.click
832
+ else # case
833
+ super
834
+ end # case
835
+ end
836
+ end
837
+
838
+
839
+ class FlagGraphicsPixmapItem < Qt::GraphicsPixmapItem
840
+ def initialize(*k)
841
+ super
842
+ end
843
+
844
+ def mousePressEvent(mouseEvent)
845
+ if mouseEvent.button == Qt::LeftButton then
846
+ dlg=mouseEvent.widget.parent.parent
847
+ dlg.waypoints.currentwp = childItems[0].toPlainText.to_i
848
+ dlg.w.lBcurrentwp.text = childItems[0].toPlainText
849
+ else
850
+ super
851
+ end
852
+ end
853
+ end
854
+
855
+
856
+ class TrackGraphicsPathItem < Qt::GraphicsPathItem
857
+ attr_reader :nodeinfo, :nodeinfo_widget
858
+
859
+ @@nodeinfo_array = Array.new
860
+
861
+ def initialize(parent)
862
+ super()
863
+ @parent=parent
864
+ @addToScene = true
865
+
866
+ # needs to be embedded in other graphics element to circumvent a bug if the position of
867
+ # the ProxyWidget is above, below 2**15 - 1, bug in QT
868
+ @nodeinfo = Qt::GraphicsRectItem.new(0,0,100,100)
869
+ @nodeinfo.setPen(Qt::Pen.new(Qt::NoPen))
870
+
871
+ @nodeinfow = Qt::GraphicsProxyWidget.new(@nodeinfo)
872
+ @nodeinfo_widget = NodeinfoWidget.new(@nodeinfo)
873
+ @nodeinfo_widget.setAttribute(Qt::WA_Hover)
874
+ @nodeinfow.setWidget(@nodeinfo_widget)
875
+ @nodeinfo.setZValue(Z_VALUE_HUD)
876
+ @nodeinfo.setAcceptHoverEvents(true)
877
+ @nodeinfo.setVisible(false)
878
+ setAcceptHoverEvents(true)
879
+ setHandlesChildEvents(true)
880
+
881
+ # store these elements in permanent arry
882
+ # otherwise GC will remove them and then causes core-dump in QT
883
+ @@nodeinfo_array << [@nodeinfow, @nodeinfo_widget]
884
+ end
885
+
886
+ def colorize(data, dlg)
887
+ scene=dlg.scene
888
+ prev_x = path.elementAt(0).x
889
+ prev_y = path.elementAt(0).y
890
+ group = Qt::GraphicsItemGroup.new
891
+ x = y = 0
892
+ pen=Qt::Pen.new
893
+ pen.setWidth(5)
894
+ line=nil
895
+ d=data.dup
896
+ d.delete_if{|e| e<=0.0 }
897
+ if d.length==0 then
898
+ Qt::MessageBox::warning(nil, "Warning", "No elevation/speed data found in track.")
899
+ return
900
+ end
901
+ max=d.max
902
+ min=d.min
903
+ delta=max-min
904
+ color=nil
905
+ 1.upto(path.elementCount-2){|i|
906
+ color=Qt::Color.new
907
+ if data[i]>0.0 then
908
+ color.setHsv((data[i]-min)/delta * COLORRANGE_DEG + COLOROFFSET_DEG,255,255)
909
+ else
910
+ color.setRgb(100,100,100)
911
+ end
912
+ pen.setColor(color)
913
+ x = path.elementAt(i).x
914
+ y = path.elementAt(i).y
915
+ line = Qt::GraphicsLineItem.new(prev_x, prev_y, x, y)
916
+ line.setPen(pen)
917
+ line.setZValue(Z_VALUE_TRACK_COLORED)
918
+ group.addToGroup(line)
919
+ prev_x = x
920
+ prev_y = y
921
+ }
922
+ group.setZValue(Z_VALUE_TRACK_COLORED)
923
+ scene.addItem(group)
924
+
925
+ end
926
+
927
+ def contextMenuEvent(contextEvent)
928
+ dlg=contextEvent.widget.parent.parent
929
+ entries=["Colorize Altitude", "Colorize Speed"]
930
+ menu=Qt::Menu.new
931
+ entries.each{|e|
932
+ if e=="-" then
933
+ menu.addSeparator
934
+ else
935
+ menu.addAction(e)
936
+ end
937
+ }
938
+ sel=menu.exec(contextEvent.screenPos)
939
+ sel=sel.text if !sel.nil?
940
+ data=[]
941
+ case sel
942
+ when entries[0]
943
+ @parent.nodes.each{|n|
944
+ data << n.elevation
945
+ }
946
+ colorize(data, dlg)
947
+
948
+ when entries[1]
949
+ @parent.nodes.each{|n|
950
+ data << n.speed
951
+ }
952
+ colorize(data, dlg)
953
+
954
+ end # case
955
+ end
956
+
957
+ def hoverMoveEvent(hoverEvent)
958
+ # ap "hovermove in"
959
+ dlg=hoverEvent.widget.parent.parent
960
+
961
+ if @addToScene then
962
+ dlg.scene.addItem(@nodeinfo)
963
+ @addToScene = false
964
+ end
965
+
966
+ if !@nodeinfo_widget.hover_on then
967
+ @nodeinfo.setVisible(true)
968
+ @nodeinfo_widget.hover_on = true
969
+ end
970
+ x=hoverEvent.pos.x
971
+ y=hoverEvent.pos.y
972
+ e=nil
973
+ hit=nil
974
+ 1.upto(self.path.elementCount-1){|i|
975
+ e=self.path.elementAt(i)
976
+ if ((e.x - x).abs < 3) and ((e.y - y).abs < 3)then
977
+ hit=i
978
+ break
979
+ end
980
+ }
981
+
982
+ if !hit.nil? and !@parent.nil? then
983
+ n=@parent.nodes[hit]
984
+ @nodeinfo_widget.w.lBlon.text="%.3f�" % n.lon
985
+ @nodeinfo_widget.w.lBlat.text="%.3f�" % n.lat
986
+ @nodeinfo_widget.w.lBalt.text="%.1fm" % n.elevation
987
+ @nodeinfo_widget.w.lBspeed.text="%.1fkm/h" % n.speed
988
+ pos = mapToScene(hoverEvent.pos)
989
+ if !@nodeinfo.isVisible or @nodeinfo_widget.hover_widget_pos.nil? or (!@nodeinfo_widget.hover_widget_pos.nil? \
990
+ and Qt::LineF.new(@nodeinfo_widget.hover_widget_pos, pos).length > 30) then
991
+ dlg.scene.items.each {|item|
992
+ if item.kind_of? Qt::GraphicsRectItem then
993
+ if item != @nodeinfo then
994
+ # item.setVisible(false)
995
+ end
996
+ end
997
+ }
998
+ @nodeinfo.setVisible(true)
999
+ @nodeinfo_widget.hover_widget_pos=pos
1000
+ @nodeinfo.setPos(pos)
1001
+ @nodeinfo_widget.hovertimer.stop
1002
+ end
1003
+ end
1004
+ # ap "hovermove out"
1005
+ end
1006
+
1007
+ def hoverLeaveEvent(hoverEvent)
1008
+ # ap "hoverleave in"
1009
+ if @nodeinfo_widget.hover_on then
1010
+ @nodeinfo_widget.hovertimer.start(HOVER_TIMER)
1011
+ end
1012
+ # ap "hoverleave out"
1013
+ end
1014
+ end
1015
+
1016
+
1017
+ class TileGraphicsPixmapItem < Qt::GraphicsPixmapItem
1018
+ def mousePressEvent(mouseEvent)
1019
+ pos = mouseEvent.scenePos
1020
+ dlg=mouseEvent.widget.parent.parent
1021
+ case mouseEvent.button
1022
+ when Qt::LeftButton
1023
+ dlg.offset_x = pos.x / 256.0
1024
+ dlg.offset_y = pos.y / 256.0
1025
+ dlg.movemap(dlg.node)
1026
+ when Qt::RightButton
1027
+
1028
+ end # case
1029
+ end
1030
+
1031
+ def contextMenuEvent(contextEvent)
1032
+ dlg=contextEvent.widget.parent.parent
1033
+ entries=["Set Waypoint", "Delete Waypoint", "Set Origin", "-", "Save Waypoints", "Save Track", "Load Waypoints",
1034
+ "Load Track", ["Metric Units", dlg.metricUnit]]
1035
+ menu=Qt::Menu.new
1036
+ entries.each{|e|
1037
+ if e.kind_of? Array then
1038
+ action = Qt::Action.new(e[0], nil)
1039
+ action.setCheckable(true)
1040
+ action.setChecked(e[1])
1041
+ menu.addAction(action)
1042
+ else
1043
+ if e=="-" then
1044
+ menu.addSeparator
1045
+ else
1046
+ menu.addAction(e)
1047
+ end
1048
+ end
1049
+ }
1050
+ sel=menu.exec(contextEvent.screenPos)
1051
+ sel=sel.text if !sel.nil?
1052
+ lon=dlg.node.tolon(dlg.node.xtile + contextEvent.scenePos.x / 256.0)
1053
+ lat=dlg.node.tolat(dlg.node.ytile + contextEvent.scenePos.y / 256.0)
1054
+ case sel
1055
+ when entries[0]
1056
+ i=dlg.waypoints << Node.new(nil, Time.now, lon, lat)
1057
+ dlg.putflag(contextEvent.scenePos.x, contextEvent.scenePos.y, i, dlg.waypoints.nodes.last)
1058
+ if i==1 and dlg.waypoints.nodes.length == 1 then
1059
+ dlg.w.lBcurrentwp.text="1"
1060
+ dlg.waypoints.currentwp=1
1061
+ end
1062
+
1063
+ when entries[1]
1064
+ d=dlg.waypoints.del(lon,lat)
1065
+ if dlg.w.lBcurrentwp.text.to_i == d then
1066
+ dlg.w.lBcurrentwp.text="-"
1067
+ end
1068
+ dlg.movemap(dlg.node, true)
1069
+
1070
+ when entries[2]
1071
+ dlg.node=Node.new(1, Time.now, lon, lat)
1072
+ dlg.movemap(dlg.node, true)
1073
+
1074
+ when entries[4]
1075
+ dlg.saveWaypoints([dlg.waypoints])
1076
+
1077
+ when entries[5]
1078
+ dlg.savetrack(dlg.mytracks)
1079
+
1080
+ when entries[6]
1081
+ savecurrent = dlg.waypoints.currentwp
1082
+ if dlg.loadwaypoint("Load Waypoints") then
1083
+ dlg.waypoints.currentwp = nil
1084
+ else
1085
+ dlg.waypoints.currentwp = savecurrent
1086
+ end
1087
+
1088
+ when entries[7]
1089
+ dlg.mytrack_current += (dlg.w.pBrecordTrack.isChecked ? 0 : 1)
1090
+ savewp=dlg.mytracks[dlg.mytrack_current]
1091
+ if dlg.mytracks[dlg.mytrack_current].nil? then
1092
+ dlg.mytracks[dlg.mytrack_current] = Way.new(1, 'user', Time.now, dlg.nextcolor)
1093
+ @prev_track_node = nil
1094
+ end
1095
+ if dlg.loadtrack("Load Track") then
1096
+ dlg.w.pBrecordTrack.text = "Record Track #{dlg.mytrack_current + 2}"
1097
+ dlg.w.pBrecordTrack.setChecked(false)
1098
+ else
1099
+ dlg.mytracks[dlg.mytrack_current]=savewp
1100
+ end
1101
+
1102
+ when entries[8][0]
1103
+ dlg.metricUnit = !dlg.metricUnit
1104
+
1105
+ end #case
1106
+ end
1107
+ end
1108
+
1109
+
1110
+ class Qt::GraphicsScene
1111
+ def mouseMoveEvent(mouseEvent)
1112
+ super
1113
+ # a=mouseEvent.scenePos()
1114
+ # p a.x
1115
+ end
1116
+ end
1117
+