• R/O
  • SSH
  • HTTPS

qrobosdk: コミット


コミットメタ情報

リビジョン1978 (tree)
日時2012-04-06 01:23:43
作者satofumi

ログメッセージ

change line feed

変更サマリ

差分

--- trunk/widgets/UrgDrawWidget/UrgDrawWidget.cpp (revision 1977)
+++ trunk/widgets/UrgDrawWidget/UrgDrawWidget.cpp (revision 1978)
@@ -1,629 +1,629 @@
1-/*!
2- \file
3- \brief URG データの描画ウィジット
4-
5- \author Satofumi KAMIMURA
6-
7- $Id$
8-
9- \todo Intensity 描画の色を指定できるようにする
10- \todo グリッドに数値と単位系を描画。画面左端と、画面下
11- \todo 描画する色を変更できるようにする
12-*/
13-
14-#include "UrgDrawWidget.h"
15-#include "RangeSensor.h"
16-#include "convert2d.h"
17-#include "ticks.h"
18-#include <QMouseEvent>
19-#include <deque>
20-#include <limits>
21-
22-using namespace qrk;
23-using namespace std;
24-
25-#if defined(MSC)
26-#undef min
27-#undef max
28-#endif
29-
30-
31-namespace
32-{
33- const double DefaultPixelPerMm = 20.0;
34-
35-
36- struct DrawData
37- {
38- vector<Point<long> > point_data;
39- long timestamp;
40- Color line_color;
41-
42-
43- DrawData(vector<Point<long> >& point_data_,
44- long timestamp_, const Color& line_color_)
45- : timestamp(timestamp_), line_color(line_color_)
46- {
47- swap(point_data, point_data_);
48- }
49- };
50-}
51-
52-
53-struct UrgDrawWidget::pImpl
54-{
55- enum {
56- MinimumWidth = 100,
57- MinimumHeight = 100,
58-
59- PointLength = 30 * 1000, // [mm]
60- };
61-
62- UrgDrawWidget* widget_;
63-
64- Point<double> view_center_;
65- double pixel_per_mm_;
66- DrawMode draw_mode_;
67- long draw_period_;
68- long last_redraw_;
69- long last_timestamp_;
70-
71- typedef deque<DrawData> DataArray;
72- DataArray draw_data_;
73- size_t width_;
74- size_t height_;
75-
76- QColor clear_color_;
77- Position<long> rotate_offset_;
78- QPoint clicked_position_;
79- bool now_pressed_;
80-
81- Color line_color_;
82-
83-
84- pImpl(UrgDrawWidget* widget)
85- : widget_(widget),
86- pixel_per_mm_(DefaultPixelPerMm), draw_mode_(Lines),
87- draw_period_(100), last_redraw_(0), last_timestamp_(0),
88- width_(MinimumWidth), height_(MinimumHeight), clear_color_(Qt::white),
89- rotate_offset_(Position<long>(0, 0, deg(90))), now_pressed_(false),
90- line_color_(0.2f, 0.2f, 1.0f, 0.6f)
91- {
92- }
93-
94-
95- void initializeForm(void)
96- {
97- widget_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
98- widget_->setMinimumSize(MinimumWidth, MinimumHeight);
99-
100- widget_->setMouseTracking(true);
101- }
102-
103-
104- void removeOldData(long timestamp)
105- {
106- if (draw_data_.empty()) {
107- return;
108- }
109-
110- // タイムスタンプが異常な場合、全てのデータをクリアする
111- if (draw_data_.back().timestamp > timestamp) {
112- draw_data_.clear();
113- return;
114- }
115-
116- int index = 0;
117- for (DataArray::iterator it = draw_data_.begin();
118- it != draw_data_.end(); ++it, ++index) {
119- long difference = timestamp - it->timestamp;
120- if (difference < draw_period_) {
121- break;
122- }
123- }
124-
125- if (index > 0) {
126- DataArray::iterator it = draw_data_.begin();
127- draw_data_.erase(it, it + index);
128- }
129- }
130-
131-
132- void initializeGL(void)
133- {
134- widget_->qglClearColor(clear_color_);
135- glEnable(GL_CULL_FACE);
136- glEnable(GL_TEXTURE_2D);
137- glEnable(GL_BLEND);
138- glDisable(GL_DEPTH_TEST);
139-
140- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
141- }
142-
143-
144- void resizeGL(int width, int height)
145- {
146- glViewport(0, 0, width, height);
147-
148- glMatrixMode(GL_PROJECTION);
149- glLoadIdentity();
150-
151- double aspect = 1.0 * width / height;
152- glOrtho(-1.0 * aspect, +1.0 * aspect, -1.0, +1.0,
153- numeric_limits<int>::min(), numeric_limits<int>::max());
154-
155- glMatrixMode(GL_MODELVIEW);
156- width_ = width;
157- height_ = height;
158- }
159-
160-
161- void paintGL(void)
162- {
163- widget_->qglClearColor(clear_color_);
164- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
165- glLoadIdentity();
166-
167- // 軸の描画
168- drawAxis();
169-
170- // データの描画
171- drawData();
172- }
173-
174-
175- void drawAxis(void)
176- {
177- double zoom_ratio = zoomRatio();
178- Point<double> offset = drawOffset(zoom_ratio);
179-
180- // 補助線の描画
181- drawSubAxis(offset);
182-
183- glColor3d(0.3, 0.3, 0.3);
184- glBegin(GL_LINES);
185-
186- // Y 軸
187- glVertex2d(-offset.x, -1.0);
188- glVertex2d(-offset.x, +1.0);
189-
190- // X 軸
191- double aspect = 1.0 * width_ / height_;
192- glVertex2d(-aspect, -offset.y);
193- glVertex2d(+aspect, -offset.y);
194-
195- // 背後 45 [deg] の補助線
196- glVertex2d(-offset.x, -offset.y);
197- glVertex2d((-PointLength * zoom_ratio) - offset.x,
198- (-PointLength * zoom_ratio) - offset.y);
199- glVertex2d(-offset.x, -offset.y);
200- glVertex2d((+PointLength * zoom_ratio) - offset.x,
201- (-PointLength * zoom_ratio) - offset.y);
202- glEnd();
203-
204- // 円の補助線を描画
205- for (int i = 0; i <= PointLength; i += 1000) {
206- drawSubCircle(i, offset);
207- }
208-
209- // 単位の表示
210- // !!!
211- }
212-
213-
214- void drawSubCircle(int radius, const Point<double>& offset)
215- {
216- double pixel_radius = (radius / pixel_per_mm_) / (height_ / 2.0);
217-
218- glBegin(GL_LINE_STRIP);
219- for (int theta = -45; theta <= (180 + 45); theta += 2) {
220-
221- double radian = M_PI * theta / 180.0;
222- double x = pixel_radius * cos(radian);
223- double y = pixel_radius * sin(radian);
224- glVertex2d(x - offset.x, y - offset.y);
225- }
226- glEnd();
227- }
228-
229-
230- void drawSubAxis(const Point<double>& offset)
231- {
232- Point<int> center(width_ / 2, height_ / 2);
233- Point<long> first(static_cast<int>((-center.x * pixel_per_mm_)
234- - view_center_.x),
235- static_cast<int>((-center.y * pixel_per_mm_)
236- - view_center_.y));
237- Point<long> last(static_cast<int>((+center.x * pixel_per_mm_)
238- - view_center_.x),
239- static_cast<int>((+center.y * pixel_per_mm_)
240- - view_center_.y));
241-
242- const double threshold[] = { 4.0, 16.0, 32.0 };
243- const int interval[] = { 10, 100, 1000 };
244- const double color[] = { 0.8, 0.6, 0.3 };
245- size_t n = sizeof(threshold) / sizeof(threshold[0]);
246- for (size_t i = 0; i < n; ++i) {
247- const double draw_threshold = threshold[i];
248- if (pixel_per_mm_ > draw_threshold) {
249- continue;
250- }
251- double alpha = 1.0 - (pixel_per_mm_ / draw_threshold);
252- glColor4d(color[i], color[i], color[i], alpha);
253- drawSubPointLine(interval[i], offset, first, last);
254- }
255- }
256-
257-
258- void drawSubPointLine(int interval, const Point<double>& offset,
259- const Point<long>& first, const Point<long>& last)
260- {
261- glBegin(GL_LINES);
262- for (int x = (first.x / interval) - 1;
263- x < ((last.x / interval) + 1); ++x) {
264- double draw_x = (interval * x / pixel_per_mm_) / (height_ / 2.0);
265- glVertex2d(draw_x - offset.x, -1.0);
266- glVertex2d(draw_x - offset.x, +1.0);
267- }
268-
269- double aspect = 1.0 * width_ / height_;
270- for (int y = (first.y / interval) - 1;
271- y < ((last.y / interval) + 1); ++y) {
272- double draw_y = (interval * y / pixel_per_mm_) / (height_ / 2.0);
273- glVertex2d(-aspect, draw_y - offset.y);
274- glVertex2d(+aspect, draw_y - offset.y);
275- }
276- glEnd();
277- }
278-
279-
280- void drawData(void)
281- {
282- // !!! 時間が経過するほど、薄い色で表示するようにする
283-
284- double zoom_ratio = zoomRatio();
285- Point<double> offset = drawOffset(zoom_ratio);
286-
287- if (draw_mode_ == Lines) {
288- // 中心から測定点への直線を描画
289- glBegin(GL_LINES);
290- for (DataArray::iterator line_it = draw_data_.begin();
291- line_it != draw_data_.end(); ++line_it) {
292-
293- Color& line_color = line_it->line_color;
294- double diff = last_timestamp_ - line_it->timestamp;
295- double alpha = 1.0 - (diff / draw_period_);
296- glColor4d(line_color.r, line_color.g, line_color.b, alpha);
297-
298- vector<Point<long> >& line_data = line_it->point_data;;
299- vector<Point<long> >::iterator end_it = line_data.end();
300- for (vector<Point<long> >::iterator it = line_data.begin();
301- it != end_it; ++it) {
302-
303- double x = it->x * zoom_ratio;
304- double y = it->y * zoom_ratio;
305- glVertex2d(-offset.x, -offset.y);
306- glVertex2d(x - offset.x, y - offset.y);
307- }
308- }
309- glEnd();
310-
311- } else if (draw_mode_ == Polygon) {
312- // !!! これを実現するには、convert2d 時に捨ててしまった情報が必要
313- // !!! 実装方法を見直すべき
314- }
315-
316- // 測定点の描画
317- double base_size = 1.4;
318- double mm_pixel = max(base_size / pixel_per_mm_, base_size);
319- glPointSize(mm_pixel);
320-
321- glBegin(GL_POINTS);
322- for (DataArray::iterator line_it = draw_data_.begin();
323- line_it != draw_data_.end(); ++line_it) {
324-
325- // !!! 関数にする
326- double diff = last_timestamp_ - line_it->timestamp;
327- double alpha = 1.0 - (diff / draw_period_);
328- glColor4d(1.0, 0.0, 0.0, alpha);
329-
330- vector<Point<long> >::iterator end_it = line_it->point_data.end();
331- for (vector<Point<long> >::iterator it =
332- line_it->point_data.begin();
333- it != end_it; ++it) {
334-
335- double x = it->x * zoom_ratio;
336- double y = it->y * zoom_ratio;
337- glVertex2d(x - offset.x, y - offset.y);
338- }
339- }
340- glEnd();
341- }
342-
343-
344- // [mm] -> [pixel]
345- double zoomRatio(void)
346- {
347- return (1.0 / pixel_per_mm_ / (height_ / 2.0));
348- }
349-
350-
351- Point<double> drawOffset(double zoom_ratio)
352- {
353- return Point<double>(-view_center_.x * zoom_ratio,
354- -view_center_.y * zoom_ratio);
355- }
356-
357-
358- void setClickedPosition(QMouseEvent* event)
359- {
360- clicked_position_ = event->pos();
361- }
362-
363-
364- void updateZoomRatio(int steps)
365- {
366- double zoom = widget_->zoomRatio();
367- zoom *= pow(1.1, steps);
368-
369- if (zoom > 500.0) {
370- zoom = 500.0;
371- } else if (zoom < 0.05) {
372- zoom = 0.05;
373- }
374- widget_->setZoomRatio(zoom);
375- }
376-
377-
378- bool storeUrgData(int timestamp, vector<Point<long> >& point_data,
379- vector<Point<long> >* intensity_point_data = NULL)
380- {
381- removeOldData(timestamp);
382- draw_data_.push_back(DrawData(point_data, timestamp, line_color_));
383- if (intensity_point_data) {
384- draw_data_.push_back(DrawData(*intensity_point_data, timestamp,
385- Color(1.0f, 0.0f, 1.0f, 0.7f)));
386- }
387- last_timestamp_ = timestamp;
388-
389- return true;
390- }
391-};
392-
393-
394-UrgDrawWidget::UrgDrawWidget(QWidget* parent)
395- : QGLWidget(parent), pimpl(new pImpl(this))
396-{
397- pimpl->initializeForm();
398-}
399-
400-
401-UrgDrawWidget::~UrgDrawWidget(void)
402-{
403-}
404-
405-
406-void UrgDrawWidget::clear(void)
407-{
408- pimpl->draw_data_.clear();
409- //redraw();
410-}
411-
412-
413-void UrgDrawWidget::initializeView(void)
414-{
415- pimpl->pixel_per_mm_ = DefaultPixelPerMm;
416- pimpl->view_center_ = Point<double>(0.0, 0.0);
417- redraw();
418-}
419-
420-
421-void UrgDrawWidget::redraw(void)
422-{
423- pimpl->last_redraw_ = ticks();
424- updateGL();
425-}
426-
427-
428-bool UrgDrawWidget::setUrgData(qrk::RangeSensor* sensor)
429-{
430- vector<long> data;
431- vector<long> intensity_data;
432- vector<Point<long> > intensity_point_data;
433- long timestamp = 0;
434-
435- RangeCaptureMode capture_mode = sensor->captureMode();
436-
437- int n = 0;
438- if (capture_mode != IntensityCapture) {
439- n = sensor->capture(data, &timestamp);
440- } else {
441- n = sensor->captureWithIntensity(data, intensity_data, &timestamp);
442- }
443- if (n <= 0) {
444- return false;
445- }
446-
447- vector<Point<long> > point_data;
448- qrk::convert2d(point_data, sensor, data, pimpl->rotate_offset_);
449- if (capture_mode == IntensityCapture) {
450- qrk::convert2d(intensity_point_data, sensor, intensity_data,
451- pimpl->rotate_offset_, numeric_limits<int>::max());
452- }
453-
454- return pimpl->storeUrgData(timestamp, point_data, &intensity_point_data);
455-}
456-
457-
458-bool UrgDrawWidget::setUrgData(std::vector<long>& data,
459- const RangeSensor* sensor, long timestamp)
460-{
461- vector<Point<long> > point_data;
462- qrk::convert2d(point_data, sensor, data, pimpl->rotate_offset_);
463-
464- return pimpl->storeUrgData(timestamp, point_data, NULL);
465-}
466-
467-
468-bool UrgDrawWidget::setUrgData(std::vector<qrk::Point<long> >& data,
469- long timestamp)
470-{
471- return pimpl->storeUrgData(timestamp, data, NULL);
472-}
473-
474-
475-bool UrgDrawWidget::setUrgIntensityData(std::vector<long>& data,
476- const qrk::RangeSensor* sensor,
477- long timestamp)
478-{
479- vector<Point<long> > point_data;
480- qrk::convert2d(point_data, sensor, data, pimpl->rotate_offset_,
481- numeric_limits<int>::max());
482-
483- pimpl->draw_data_.push_back(DrawData(point_data, timestamp,
484- Color(1.0f, 0.0f, 1.0f, 0.7f)));
485- return true;
486-}
487-
488-
489-bool UrgDrawWidget::setUrgIntensityData(vector<qrk::Point<long> >& data,
490- long timestamp)
491-{
492- pimpl->draw_data_.push_back(DrawData(data, timestamp,
493- Color(1.0f, 0.0f, 1.0f, 0.7f)));
494- return true;
495-}
496-
497-
498-void UrgDrawWidget::setDrawColor(const qrk::Color& line_color)
499-{
500- pimpl->line_color_ = line_color;
501-}
502-
503-
504-void UrgDrawWidget::setDrawMode(DrawMode mode)
505-{
506- pimpl->draw_mode_ = mode;
507-}
508-
509-
510-void UrgDrawWidget::setDrawPeriod(size_t msec)
511-{
512- pimpl->draw_period_ = msec;
513-}
514-
515-
516-void UrgDrawWidget::setZoomRatio(double pixel_per_mm)
517-{
518- pimpl->pixel_per_mm_ = pixel_per_mm;
519- redraw();
520-}
521-
522-
523-double UrgDrawWidget::zoomRatio(void)
524-{
525- return pimpl->pixel_per_mm_;
526-}
527-
528-
529-void UrgDrawWidget::updateZoomRatio(int steps)
530-{
531- pimpl->updateZoomRatio(steps);
532-}
533-
534-
535-void UrgDrawWidget::setViewCenter(const Point<long>& point)
536-{
537- pimpl->view_center_.x = point.x;
538- pimpl->view_center_.y = point.y;
539-}
540-
541-
542-Point<long> UrgDrawWidget::viewCenter(void)
543-{
544- return Point<long>(static_cast<long>(pimpl->view_center_.x),
545- static_cast<long>(pimpl->view_center_.y));
546-}
547-
548-
549-void UrgDrawWidget::initializeGL(void)
550-{
551- pimpl->initializeGL();
552-}
553-
554-
555-void UrgDrawWidget::resizeGL(int width, int height)
556-{
557- pimpl->resizeGL(width, height);
558-}
559-
560-
561-void UrgDrawWidget::paintGL(void)
562-{
563- pimpl->paintGL();
564-}
565-
566-
567-void UrgDrawWidget::mousePressEvent(QMouseEvent* event)
568-{
569- pimpl->now_pressed_ = true;
570- pimpl->setClickedPosition(event);
571-}
572-
573-
574-void UrgDrawWidget::mouseMoveEvent(QMouseEvent* event)
575-{
576- int x = event->x();
577- int y = event->y();
578-
579- if (pimpl->now_pressed_) {
580- int dx = x - pimpl->clicked_position_.x();
581- int dy = y - pimpl->clicked_position_.y();
582-
583- pimpl->view_center_.x += dx * pimpl->pixel_per_mm_;
584- pimpl->view_center_.y -= dy * pimpl->pixel_per_mm_;
585-
586- pimpl->setClickedPosition(event);
587-
588- // 最後の更新が MinimumRedrawInterval [msec] 以前だったなら、
589- // 再描画を行う
590- enum { MinimumRedrawInterval = 25 };
591- if ((pimpl->last_redraw_ + MinimumRedrawInterval) < ticks()) {
592- redraw();
593- }
594- }
595-
596- // カーソル位置の座標をシグナルで送信する
597- if ((x < 0) || (x >= static_cast<int>(pimpl->width_)) ||
598- (y < 0) || (y >= static_cast<int>(pimpl->height_))) {
599- emit position(false, -1, -1);
600- return;
601- }
602-
603- int center_x = pimpl->width_ / 2;
604- int center_y = pimpl->height_ / 2;
605- int x_mm = static_cast<int>(((x - center_x) * pimpl->pixel_per_mm_)
606- - pimpl->view_center_.x);
607- int y_mm = static_cast<int>((-(y - center_y) * pimpl->pixel_per_mm_)
608- - pimpl->view_center_.y);
609- emit position(true, x_mm, y_mm);
610-}
611-
612-
613-void UrgDrawWidget::mouseReleaseEvent(QMouseEvent* event)
614-{
615- static_cast<void>(event);
616-
617- pimpl->now_pressed_ = false;
618- redraw();
619-}
620-
621-
622-void UrgDrawWidget::wheelEvent(QWheelEvent* event)
623-{
624- int degrees = event->delta() / 8;
625- int steps = degrees / 15;
626-
627- event->accept();
628- updateZoomRatio(steps);
629-}
1+/*!
2+ \file
3+ \brief URG データの描画ウィジット
4+
5+ \author Satofumi KAMIMURA
6+
7+ $Id$
8+
9+ \todo Intensity 描画の色を指定できるようにする
10+ \todo グリッドに数値と単位系を描画。画面左端と、画面下
11+ \todo 描画する色を変更できるようにする
12+*/
13+
14+#include "UrgDrawWidget.h"
15+#include "RangeSensor.h"
16+#include "convert2d.h"
17+#include "ticks.h"
18+#include <QMouseEvent>
19+#include <deque>
20+#include <limits>
21+
22+using namespace qrk;
23+using namespace std;
24+
25+#if defined(MSC)
26+#undef min
27+#undef max
28+#endif
29+
30+
31+namespace
32+{
33+ const double DefaultPixelPerMm = 20.0;
34+
35+
36+ struct DrawData
37+ {
38+ vector<Point<long> > point_data;
39+ long timestamp;
40+ Color line_color;
41+
42+
43+ DrawData(vector<Point<long> >& point_data_,
44+ long timestamp_, const Color& line_color_)
45+ : timestamp(timestamp_), line_color(line_color_)
46+ {
47+ swap(point_data, point_data_);
48+ }
49+ };
50+}
51+
52+
53+struct UrgDrawWidget::pImpl
54+{
55+ enum {
56+ MinimumWidth = 100,
57+ MinimumHeight = 100,
58+
59+ PointLength = 30 * 1000, // [mm]
60+ };
61+
62+ UrgDrawWidget* widget_;
63+
64+ Point<double> view_center_;
65+ double pixel_per_mm_;
66+ DrawMode draw_mode_;
67+ long draw_period_;
68+ long last_redraw_;
69+ long last_timestamp_;
70+
71+ typedef deque<DrawData> DataArray;
72+ DataArray draw_data_;
73+ size_t width_;
74+ size_t height_;
75+
76+ QColor clear_color_;
77+ Position<long> rotate_offset_;
78+ QPoint clicked_position_;
79+ bool now_pressed_;
80+
81+ Color line_color_;
82+
83+
84+ pImpl(UrgDrawWidget* widget)
85+ : widget_(widget),
86+ pixel_per_mm_(DefaultPixelPerMm), draw_mode_(Lines),
87+ draw_period_(100), last_redraw_(0), last_timestamp_(0),
88+ width_(MinimumWidth), height_(MinimumHeight), clear_color_(Qt::white),
89+ rotate_offset_(Position<long>(0, 0, deg(90))), now_pressed_(false),
90+ line_color_(0.2f, 0.2f, 1.0f, 0.6f)
91+ {
92+ }
93+
94+
95+ void initializeForm(void)
96+ {
97+ widget_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
98+ widget_->setMinimumSize(MinimumWidth, MinimumHeight);
99+
100+ widget_->setMouseTracking(true);
101+ }
102+
103+
104+ void removeOldData(long timestamp)
105+ {
106+ if (draw_data_.empty()) {
107+ return;
108+ }
109+
110+ // タイムスタンプが異常な場合、全てのデータをクリアする
111+ if (draw_data_.back().timestamp > timestamp) {
112+ draw_data_.clear();
113+ return;
114+ }
115+
116+ int index = 0;
117+ for (DataArray::iterator it = draw_data_.begin();
118+ it != draw_data_.end(); ++it, ++index) {
119+ long difference = timestamp - it->timestamp;
120+ if (difference < draw_period_) {
121+ break;
122+ }
123+ }
124+
125+ if (index > 0) {
126+ DataArray::iterator it = draw_data_.begin();
127+ draw_data_.erase(it, it + index);
128+ }
129+ }
130+
131+
132+ void initializeGL(void)
133+ {
134+ widget_->qglClearColor(clear_color_);
135+ glEnable(GL_CULL_FACE);
136+ glEnable(GL_TEXTURE_2D);
137+ glEnable(GL_BLEND);
138+ glDisable(GL_DEPTH_TEST);
139+
140+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
141+ }
142+
143+
144+ void resizeGL(int width, int height)
145+ {
146+ glViewport(0, 0, width, height);
147+
148+ glMatrixMode(GL_PROJECTION);
149+ glLoadIdentity();
150+
151+ double aspect = 1.0 * width / height;
152+ glOrtho(-1.0 * aspect, +1.0 * aspect, -1.0, +1.0,
153+ numeric_limits<int>::min(), numeric_limits<int>::max());
154+
155+ glMatrixMode(GL_MODELVIEW);
156+ width_ = width;
157+ height_ = height;
158+ }
159+
160+
161+ void paintGL(void)
162+ {
163+ widget_->qglClearColor(clear_color_);
164+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
165+ glLoadIdentity();
166+
167+ // 軸の描画
168+ drawAxis();
169+
170+ // データの描画
171+ drawData();
172+ }
173+
174+
175+ void drawAxis(void)
176+ {
177+ double zoom_ratio = zoomRatio();
178+ Point<double> offset = drawOffset(zoom_ratio);
179+
180+ // 補助線の描画
181+ drawSubAxis(offset);
182+
183+ glColor3d(0.3, 0.3, 0.3);
184+ glBegin(GL_LINES);
185+
186+ // Y 軸
187+ glVertex2d(-offset.x, -1.0);
188+ glVertex2d(-offset.x, +1.0);
189+
190+ // X 軸
191+ double aspect = 1.0 * width_ / height_;
192+ glVertex2d(-aspect, -offset.y);
193+ glVertex2d(+aspect, -offset.y);
194+
195+ // 背後 45 [deg] の補助線
196+ glVertex2d(-offset.x, -offset.y);
197+ glVertex2d((-PointLength * zoom_ratio) - offset.x,
198+ (-PointLength * zoom_ratio) - offset.y);
199+ glVertex2d(-offset.x, -offset.y);
200+ glVertex2d((+PointLength * zoom_ratio) - offset.x,
201+ (-PointLength * zoom_ratio) - offset.y);
202+ glEnd();
203+
204+ // 円の補助線を描画
205+ for (int i = 0; i <= PointLength; i += 1000) {
206+ drawSubCircle(i, offset);
207+ }
208+
209+ // 単位の表示
210+ // !!!
211+ }
212+
213+
214+ void drawSubCircle(int radius, const Point<double>& offset)
215+ {
216+ double pixel_radius = (radius / pixel_per_mm_) / (height_ / 2.0);
217+
218+ glBegin(GL_LINE_STRIP);
219+ for (int theta = -45; theta <= (180 + 45); theta += 2) {
220+
221+ double radian = M_PI * theta / 180.0;
222+ double x = pixel_radius * cos(radian);
223+ double y = pixel_radius * sin(radian);
224+ glVertex2d(x - offset.x, y - offset.y);
225+ }
226+ glEnd();
227+ }
228+
229+
230+ void drawSubAxis(const Point<double>& offset)
231+ {
232+ Point<int> center(width_ / 2, height_ / 2);
233+ Point<long> first(static_cast<int>((-center.x * pixel_per_mm_)
234+ - view_center_.x),
235+ static_cast<int>((-center.y * pixel_per_mm_)
236+ - view_center_.y));
237+ Point<long> last(static_cast<int>((+center.x * pixel_per_mm_)
238+ - view_center_.x),
239+ static_cast<int>((+center.y * pixel_per_mm_)
240+ - view_center_.y));
241+
242+ const double threshold[] = { 4.0, 16.0, 32.0 };
243+ const int interval[] = { 10, 100, 1000 };
244+ const double color[] = { 0.8, 0.6, 0.3 };
245+ size_t n = sizeof(threshold) / sizeof(threshold[0]);
246+ for (size_t i = 0; i < n; ++i) {
247+ const double draw_threshold = threshold[i];
248+ if (pixel_per_mm_ > draw_threshold) {
249+ continue;
250+ }
251+ double alpha = 1.0 - (pixel_per_mm_ / draw_threshold);
252+ glColor4d(color[i], color[i], color[i], alpha);
253+ drawSubPointLine(interval[i], offset, first, last);
254+ }
255+ }
256+
257+
258+ void drawSubPointLine(int interval, const Point<double>& offset,
259+ const Point<long>& first, const Point<long>& last)
260+ {
261+ glBegin(GL_LINES);
262+ for (int x = (first.x / interval) - 1;
263+ x < ((last.x / interval) + 1); ++x) {
264+ double draw_x = (interval * x / pixel_per_mm_) / (height_ / 2.0);
265+ glVertex2d(draw_x - offset.x, -1.0);
266+ glVertex2d(draw_x - offset.x, +1.0);
267+ }
268+
269+ double aspect = 1.0 * width_ / height_;
270+ for (int y = (first.y / interval) - 1;
271+ y < ((last.y / interval) + 1); ++y) {
272+ double draw_y = (interval * y / pixel_per_mm_) / (height_ / 2.0);
273+ glVertex2d(-aspect, draw_y - offset.y);
274+ glVertex2d(+aspect, draw_y - offset.y);
275+ }
276+ glEnd();
277+ }
278+
279+
280+ void drawData(void)
281+ {
282+ // !!! 時間が経過するほど、薄い色で表示するようにする
283+
284+ double zoom_ratio = zoomRatio();
285+ Point<double> offset = drawOffset(zoom_ratio);
286+
287+ if (draw_mode_ == Lines) {
288+ // 中心から測定点への直線を描画
289+ glBegin(GL_LINES);
290+ for (DataArray::iterator line_it = draw_data_.begin();
291+ line_it != draw_data_.end(); ++line_it) {
292+
293+ Color& line_color = line_it->line_color;
294+ double diff = last_timestamp_ - line_it->timestamp;
295+ double alpha = 1.0 - (diff / draw_period_);
296+ glColor4d(line_color.r, line_color.g, line_color.b, alpha);
297+
298+ vector<Point<long> >& line_data = line_it->point_data;;
299+ vector<Point<long> >::iterator end_it = line_data.end();
300+ for (vector<Point<long> >::iterator it = line_data.begin();
301+ it != end_it; ++it) {
302+
303+ double x = it->x * zoom_ratio;
304+ double y = it->y * zoom_ratio;
305+ glVertex2d(-offset.x, -offset.y);
306+ glVertex2d(x - offset.x, y - offset.y);
307+ }
308+ }
309+ glEnd();
310+
311+ } else if (draw_mode_ == Polygon) {
312+ // !!! これを実現するには、convert2d 時に捨ててしまった情報が必要
313+ // !!! 実装方法を見直すべき
314+ }
315+
316+ // 測定点の描画
317+ double base_size = 1.4;
318+ double mm_pixel = max(base_size / pixel_per_mm_, base_size);
319+ glPointSize(mm_pixel);
320+
321+ glBegin(GL_POINTS);
322+ for (DataArray::iterator line_it = draw_data_.begin();
323+ line_it != draw_data_.end(); ++line_it) {
324+
325+ // !!! 関数にする
326+ double diff = last_timestamp_ - line_it->timestamp;
327+ double alpha = 1.0 - (diff / draw_period_);
328+ glColor4d(1.0, 0.0, 0.0, alpha);
329+
330+ vector<Point<long> >::iterator end_it = line_it->point_data.end();
331+ for (vector<Point<long> >::iterator it =
332+ line_it->point_data.begin();
333+ it != end_it; ++it) {
334+
335+ double x = it->x * zoom_ratio;
336+ double y = it->y * zoom_ratio;
337+ glVertex2d(x - offset.x, y - offset.y);
338+ }
339+ }
340+ glEnd();
341+ }
342+
343+
344+ // [mm] -> [pixel]
345+ double zoomRatio(void)
346+ {
347+ return (1.0 / pixel_per_mm_ / (height_ / 2.0));
348+ }
349+
350+
351+ Point<double> drawOffset(double zoom_ratio)
352+ {
353+ return Point<double>(-view_center_.x * zoom_ratio,
354+ -view_center_.y * zoom_ratio);
355+ }
356+
357+
358+ void setClickedPosition(QMouseEvent* event)
359+ {
360+ clicked_position_ = event->pos();
361+ }
362+
363+
364+ void updateZoomRatio(int steps)
365+ {
366+ double zoom = widget_->zoomRatio();
367+ zoom *= pow(1.1, steps);
368+
369+ if (zoom > 500.0) {
370+ zoom = 500.0;
371+ } else if (zoom < 0.05) {
372+ zoom = 0.05;
373+ }
374+ widget_->setZoomRatio(zoom);
375+ }
376+
377+
378+ bool storeUrgData(int timestamp, vector<Point<long> >& point_data,
379+ vector<Point<long> >* intensity_point_data = NULL)
380+ {
381+ removeOldData(timestamp);
382+ draw_data_.push_back(DrawData(point_data, timestamp, line_color_));
383+ if (intensity_point_data) {
384+ draw_data_.push_back(DrawData(*intensity_point_data, timestamp,
385+ Color(1.0f, 0.0f, 1.0f, 0.7f)));
386+ }
387+ last_timestamp_ = timestamp;
388+
389+ return true;
390+ }
391+};
392+
393+
394+UrgDrawWidget::UrgDrawWidget(QWidget* parent)
395+ : QGLWidget(parent), pimpl(new pImpl(this))
396+{
397+ pimpl->initializeForm();
398+}
399+
400+
401+UrgDrawWidget::~UrgDrawWidget(void)
402+{
403+}
404+
405+
406+void UrgDrawWidget::clear(void)
407+{
408+ pimpl->draw_data_.clear();
409+ //redraw();
410+}
411+
412+
413+void UrgDrawWidget::initializeView(void)
414+{
415+ pimpl->pixel_per_mm_ = DefaultPixelPerMm;
416+ pimpl->view_center_ = Point<double>(0.0, 0.0);
417+ redraw();
418+}
419+
420+
421+void UrgDrawWidget::redraw(void)
422+{
423+ pimpl->last_redraw_ = ticks();
424+ updateGL();
425+}
426+
427+
428+bool UrgDrawWidget::setUrgData(qrk::RangeSensor* sensor)
429+{
430+ vector<long> data;
431+ vector<long> intensity_data;
432+ vector<Point<long> > intensity_point_data;
433+ long timestamp = 0;
434+
435+ RangeCaptureMode capture_mode = sensor->captureMode();
436+
437+ int n = 0;
438+ if (capture_mode != IntensityCapture) {
439+ n = sensor->capture(data, &timestamp);
440+ } else {
441+ n = sensor->captureWithIntensity(data, intensity_data, &timestamp);
442+ }
443+ if (n <= 0) {
444+ return false;
445+ }
446+
447+ vector<Point<long> > point_data;
448+ qrk::convert2d(point_data, sensor, data, pimpl->rotate_offset_);
449+ if (capture_mode == IntensityCapture) {
450+ qrk::convert2d(intensity_point_data, sensor, intensity_data,
451+ pimpl->rotate_offset_, numeric_limits<int>::max());
452+ }
453+
454+ return pimpl->storeUrgData(timestamp, point_data, &intensity_point_data);
455+}
456+
457+
458+bool UrgDrawWidget::setUrgData(std::vector<long>& data,
459+ const RangeSensor* sensor, long timestamp)
460+{
461+ vector<Point<long> > point_data;
462+ qrk::convert2d(point_data, sensor, data, pimpl->rotate_offset_);
463+
464+ return pimpl->storeUrgData(timestamp, point_data, NULL);
465+}
466+
467+
468+bool UrgDrawWidget::setUrgData(std::vector<qrk::Point<long> >& data,
469+ long timestamp)
470+{
471+ return pimpl->storeUrgData(timestamp, data, NULL);
472+}
473+
474+
475+bool UrgDrawWidget::setUrgIntensityData(std::vector<long>& data,
476+ const qrk::RangeSensor* sensor,
477+ long timestamp)
478+{
479+ vector<Point<long> > point_data;
480+ qrk::convert2d(point_data, sensor, data, pimpl->rotate_offset_,
481+ numeric_limits<int>::max());
482+
483+ pimpl->draw_data_.push_back(DrawData(point_data, timestamp,
484+ Color(1.0f, 0.0f, 1.0f, 0.7f)));
485+ return true;
486+}
487+
488+
489+bool UrgDrawWidget::setUrgIntensityData(vector<qrk::Point<long> >& data,
490+ long timestamp)
491+{
492+ pimpl->draw_data_.push_back(DrawData(data, timestamp,
493+ Color(1.0f, 0.0f, 1.0f, 0.7f)));
494+ return true;
495+}
496+
497+
498+void UrgDrawWidget::setDrawColor(const qrk::Color& line_color)
499+{
500+ pimpl->line_color_ = line_color;
501+}
502+
503+
504+void UrgDrawWidget::setDrawMode(DrawMode mode)
505+{
506+ pimpl->draw_mode_ = mode;
507+}
508+
509+
510+void UrgDrawWidget::setDrawPeriod(size_t msec)
511+{
512+ pimpl->draw_period_ = msec;
513+}
514+
515+
516+void UrgDrawWidget::setZoomRatio(double pixel_per_mm)
517+{
518+ pimpl->pixel_per_mm_ = pixel_per_mm;
519+ redraw();
520+}
521+
522+
523+double UrgDrawWidget::zoomRatio(void)
524+{
525+ return pimpl->pixel_per_mm_;
526+}
527+
528+
529+void UrgDrawWidget::updateZoomRatio(int steps)
530+{
531+ pimpl->updateZoomRatio(steps);
532+}
533+
534+
535+void UrgDrawWidget::setViewCenter(const Point<long>& point)
536+{
537+ pimpl->view_center_.x = point.x;
538+ pimpl->view_center_.y = point.y;
539+}
540+
541+
542+Point<long> UrgDrawWidget::viewCenter(void)
543+{
544+ return Point<long>(static_cast<long>(pimpl->view_center_.x),
545+ static_cast<long>(pimpl->view_center_.y));
546+}
547+
548+
549+void UrgDrawWidget::initializeGL(void)
550+{
551+ pimpl->initializeGL();
552+}
553+
554+
555+void UrgDrawWidget::resizeGL(int width, int height)
556+{
557+ pimpl->resizeGL(width, height);
558+}
559+
560+
561+void UrgDrawWidget::paintGL(void)
562+{
563+ pimpl->paintGL();
564+}
565+
566+
567+void UrgDrawWidget::mousePressEvent(QMouseEvent* event)
568+{
569+ pimpl->now_pressed_ = true;
570+ pimpl->setClickedPosition(event);
571+}
572+
573+
574+void UrgDrawWidget::mouseMoveEvent(QMouseEvent* event)
575+{
576+ int x = event->x();
577+ int y = event->y();
578+
579+ if (pimpl->now_pressed_) {
580+ int dx = x - pimpl->clicked_position_.x();
581+ int dy = y - pimpl->clicked_position_.y();
582+
583+ pimpl->view_center_.x += dx * pimpl->pixel_per_mm_;
584+ pimpl->view_center_.y -= dy * pimpl->pixel_per_mm_;
585+
586+ pimpl->setClickedPosition(event);
587+
588+ // 最後の更新が MinimumRedrawInterval [msec] 以前だったなら、
589+ // 再描画を行う
590+ enum { MinimumRedrawInterval = 25 };
591+ if ((pimpl->last_redraw_ + MinimumRedrawInterval) < ticks()) {
592+ redraw();
593+ }
594+ }
595+
596+ // カーソル位置の座標をシグナルで送信する
597+ if ((x < 0) || (x >= static_cast<int>(pimpl->width_)) ||
598+ (y < 0) || (y >= static_cast<int>(pimpl->height_))) {
599+ emit position(false, -1, -1);
600+ return;
601+ }
602+
603+ int center_x = pimpl->width_ / 2;
604+ int center_y = pimpl->height_ / 2;
605+ int x_mm = static_cast<int>(((x - center_x) * pimpl->pixel_per_mm_)
606+ - pimpl->view_center_.x);
607+ int y_mm = static_cast<int>((-(y - center_y) * pimpl->pixel_per_mm_)
608+ - pimpl->view_center_.y);
609+ emit position(true, x_mm, y_mm);
610+}
611+
612+
613+void UrgDrawWidget::mouseReleaseEvent(QMouseEvent* event)
614+{
615+ static_cast<void>(event);
616+
617+ pimpl->now_pressed_ = false;
618+ redraw();
619+}
620+
621+
622+void UrgDrawWidget::wheelEvent(QWheelEvent* event)
623+{
624+ int degrees = event->delta() / 8;
625+ int steps = degrees / 15;
626+
627+ event->accept();
628+ updateZoomRatio(steps);
629+}
--- trunk/widgets/UrgDrawWidget/UrgDrawWidget.h (revision 1977)
+++ trunk/widgets/UrgDrawWidget/UrgDrawWidget.h (revision 1978)
@@ -1,91 +1,91 @@
1-#ifndef QRK_URG_DRAW_WIDGET_H
2-#define QRK_URG_DRAW_WIDGET_H
3-
4-/*!
5- \file
6- \brief URG データの描画ウィジット
7-
8- \author Satofumi KAMIMURA
9-
10- $Id$
11-*/
12-
13-#include "Point.h"
14-#include "Color.h"
15-#include <QGLWidget>
16-#include <memory>
17-
18-
19-namespace qrk
20-{
21- class RangeSensor;
22-}
23-
24-
25-/*!
26- \brief URG データの描画用ウィジット
27-*/
28-class UrgDrawWidget : public QGLWidget
29-{
30- Q_OBJECT;
31-
32-public:
33- typedef enum {
34- Points,
35- Lines,
36- Polygon,
37- } DrawMode;
38-
39-
40- UrgDrawWidget(QWidget* parent = 0);
41- ~UrgDrawWidget(void);
42-
43- void clear(void);
44- void initializeView(void);
45-
46- void redraw(void);
47-
48- bool setUrgData(qrk::RangeSensor* sensor);
49- bool setUrgData(std::vector<long>& data,
50- const qrk::RangeSensor* sensor, long timestamp);
51- bool setUrgData(std::vector<qrk::Point<long> >& data, long timestamp);
52-
53- bool setUrgIntensityData(std::vector<long>& data,
54- const qrk::RangeSensor* sensor, long timestamp);
55- bool setUrgIntensityData(std::vector<qrk::Point<long> >& data,
56- long timestamp);
57-
58- void setDrawColor(const qrk::Color& line_color);
59-
60- void setDrawMode(DrawMode mode);
61-
62- void setDrawPeriod(size_t msec);
63-
64- void setZoomRatio(double pixel_per_mm);
65- double zoomRatio(void);
66- void updateZoomRatio(int steps);
67-
68- void setViewCenter(const qrk::Point<long>& point);
69- qrk::Point<long> viewCenter(void);
70-
71-signals:
72- void position(bool active, long x_mm, long y_mm);
73-
74-protected:
75- void initializeGL(void);
76- void resizeGL(int width, int height);
77- void paintGL(void);
78- void mousePressEvent(QMouseEvent* event);
79- void mouseMoveEvent(QMouseEvent* event);
80- void mouseReleaseEvent(QMouseEvent* event);
81- void wheelEvent(QWheelEvent* event);
82-
83-private:
84- UrgDrawWidget(const UrgDrawWidget& rhs);
85- UrgDrawWidget& operator = (const UrgDrawWidget& rhs);
86-
87- struct pImpl;
88- std::auto_ptr<pImpl> pimpl;
89-};
90-
91-#endif /* !QRK_URG_DRAW_WIDGET_H */
1+#ifndef QRK_URG_DRAW_WIDGET_H
2+#define QRK_URG_DRAW_WIDGET_H
3+
4+/*!
5+ \file
6+ \brief URG データの描画ウィジット
7+
8+ \author Satofumi KAMIMURA
9+
10+ $Id$
11+*/
12+
13+#include "Point.h"
14+#include "Color.h"
15+#include <QGLWidget>
16+#include <memory>
17+
18+
19+namespace qrk
20+{
21+ class RangeSensor;
22+}
23+
24+
25+/*!
26+ \brief URG データの描画用ウィジット
27+*/
28+class UrgDrawWidget : public QGLWidget
29+{
30+ Q_OBJECT;
31+
32+public:
33+ typedef enum {
34+ Points,
35+ Lines,
36+ Polygon,
37+ } DrawMode;
38+
39+
40+ UrgDrawWidget(QWidget* parent = 0);
41+ ~UrgDrawWidget(void);
42+
43+ void clear(void);
44+ void initializeView(void);
45+
46+ void redraw(void);
47+
48+ bool setUrgData(qrk::RangeSensor* sensor);
49+ bool setUrgData(std::vector<long>& data,
50+ const qrk::RangeSensor* sensor, long timestamp);
51+ bool setUrgData(std::vector<qrk::Point<long> >& data, long timestamp);
52+
53+ bool setUrgIntensityData(std::vector<long>& data,
54+ const qrk::RangeSensor* sensor, long timestamp);
55+ bool setUrgIntensityData(std::vector<qrk::Point<long> >& data,
56+ long timestamp);
57+
58+ void setDrawColor(const qrk::Color& line_color);
59+
60+ void setDrawMode(DrawMode mode);
61+
62+ void setDrawPeriod(size_t msec);
63+
64+ void setZoomRatio(double pixel_per_mm);
65+ double zoomRatio(void);
66+ void updateZoomRatio(int steps);
67+
68+ void setViewCenter(const qrk::Point<long>& point);
69+ qrk::Point<long> viewCenter(void);
70+
71+signals:
72+ void position(bool active, long x_mm, long y_mm);
73+
74+protected:
75+ void initializeGL(void);
76+ void resizeGL(int width, int height);
77+ void paintGL(void);
78+ void mousePressEvent(QMouseEvent* event);
79+ void mouseMoveEvent(QMouseEvent* event);
80+ void mouseReleaseEvent(QMouseEvent* event);
81+ void wheelEvent(QWheelEvent* event);
82+
83+private:
84+ UrgDrawWidget(const UrgDrawWidget& rhs);
85+ UrgDrawWidget& operator = (const UrgDrawWidget& rhs);
86+
87+ struct pImpl;
88+ std::auto_ptr<pImpl> pimpl;
89+};
90+
91+#endif /* !QRK_URG_DRAW_WIDGET_H */
--- trunk/programs/ScipRecorder/main.cpp (revision 1977)
+++ trunk/programs/ScipRecorder/main.cpp (nonexistent)
@@ -1,20 +0,0 @@
1-/*!
2- \file
3- \brief SCIP 応答の記録アプリ
4-
5- \author Satofumi KAMIMURA
6-
7- $Id$
8-*/
9-
10-#include <QApplication>
11-
12-
13-int main(int argc, char *argv[])
14-{
15- QApplication app(argc, argv);
16-
17- // !!!
18-
19- return app.exec();
20-}
Deleted: svn:keywords
## -1 +0,0 ##
-Id
\ No newline at end of property
--- trunk/programs/ScipPlayer/ScipPlayerWindow.cpp (revision 1977)
+++ trunk/programs/ScipPlayer/ScipPlayerWindow.cpp (revision 1978)
@@ -1,506 +1,506 @@
1-/*!
2- \file
3- \brief SCIP データの表示ウィンドウ
4-
5- \author Satofumi KAMIMURA
6-
7- $Id$
8-
9- \todo MD の 00P 応答のときに、適切に読み出せるようにする
10-*/
11-
12-#include "ScipPlayerWindow.h"
13-#include "ScipDataReader.h"
14-#include "UrgDrawWidget.h"
15-#include "UrgDevice.h"
16-#include "ScipHandler.h"
17-#include "CustomConnection.h"
18-#include "ConvertStdStringPath.h"
19-#include <QTimer>
20-#include <QUrl>
21-#include <QDragEnterEvent>
22-#include <QDropEvent>
23-#include <QFileDialog>
24-#include <QShortcut>
25-#include <QSettings>
26-#include <QMessageBox>
27-
28-using namespace qrk;
29-using namespace std;
30-
31-
32-namespace
33-{
34- const char* Organization = "Hokuyo LTD.";
35- const char* Application = "Scip Player";
36-
37- typedef vector<string> ScipData;
38-}
39-
40-
41-struct ScipPlayerWindow::pImpl
42-{
43- ScipPlayerWindow* widget_;
44- UrgDrawWidget urg_draw_widget_;
45- ScipDataReader* data_reader_;
46-
47- ScipData scip_data_;
48- long current_timestamp_;
49- long last_timestamp_;
50-
51- CustomConnection con_;
52- UrgDevice urg_;
53-
54- QTimer continuous_timer_;
55- int play_ratio_;
56- bool led_on_;
57-
58- QStringList csv_files_;
59- QString csv_files_dir_;
60- bool csv_mode_;
61- int csv_index_;
62-
63-
64- pImpl(ScipPlayerWindow* parent)
65- : widget_(parent), data_reader_(NULL),
66- current_timestamp_(0), last_timestamp_(0),
67- play_ratio_(0), led_on_(false), csv_mode_(false), csv_index_(0)
68- {
69- urg_.setConnection(&con_);
70- continuous_timer_.setSingleShot(true);
71- urg_draw_widget_.setDrawPeriod(1);
72- }
73-
74-
75- ~pImpl(void)
76- {
77- delete data_reader_;
78- }
79-
80-
81- void initializeForm(void)
82- {
83- // 表示ウィジット
84- widget_->dummy_label_->hide();
85- widget_->main_layout_->addWidget(&urg_draw_widget_);
86-
87- widget_->path_edit_->setAcceptDrops(false);
88- widget_->setAcceptDrops(true);
89-
90- // イベント
91- connect(widget_->path_button_, SIGNAL(clicked()),
92- widget_, SLOT(pathPressed()));
93- connect(widget_->reload_button_, SIGNAL(clicked()),
94- widget_, SLOT(reloadPressed()));
95- connect(widget_->next_button_, SIGNAL(clicked()),
96- widget_, SLOT(nextPressed()));
97- connect(widget_->continuous_button_, SIGNAL(clicked()),
98- widget_, SLOT(continuousPressed()));
99- connect(&continuous_timer_, SIGNAL(timeout()),
100- widget_, SLOT(timerTimeout()));
101-
102- // メニュー
103- connect(widget_->action_about_, SIGNAL(triggered()),
104- widget_, SLOT(aboutApplication()));
105- connect(widget_->action_quit_, SIGNAL(triggered()),
106- widget_, SLOT(close()));
107-
108- // ショートカット
109- (void) new QShortcut(Qt::Key_Return, widget_, SLOT(initializeView()));
110- (void) new QShortcut(Qt::Key_F5, widget_, SLOT(reloadPressed()));
111- (void) new QShortcut(Qt::Key_Less, widget_, SLOT(zoomSmaller()));
112- (void) new QShortcut(Qt::Key_Comma, widget_, SLOT(zoomSmaller()));
113- (void) new QShortcut(Qt::Key_Greater, widget_, SLOT(zoomLarger()));
114- (void) new QShortcut(Qt::Key_Period, widget_, SLOT(zoomLarger()));
115- }
116-
117-
118- void saveSettings(void)
119- {
120- QSettings settings(Organization, Application);
121-
122- settings.setValue("geometry", widget_->saveGeometry());
123- settings.setValue("file_path", widget_->path_edit_->text());
124- }
125-
126-
127- void loadSettings(void)
128- {
129- QSettings settings(Organization, Application);
130-
131- widget_->restoreGeometry(settings.value("geometry").toByteArray());
132- QString log_file = settings.value("file_path", "").toString();
133- widget_->path_edit_->setText(log_file);
134- }
135-
136-
137- void reload(void)
138- {
139- // !!! この初期化処理は、適切にまとめるべき
140- widget_->setWindowTitle("Scip Player");
141- continuous_timer_.stop();
142- scip_data_.clear();
143- con_.clear();
144- urg_draw_widget_.clear();
145- urg_draw_widget_.redraw();
146- current_timestamp_ = 0;
147- play_ratio_ = 0;
148- led_on_ = false;
149-
150- QString log_file = widget_->path_edit_->text();
151-
152- QFileInfo file_info(log_file);
153- QString suffix = file_info.suffix().toLower();
154- csv_mode_ = (! suffix.compare("csv")) ? true : false;
155- if (csv_mode_) {
156- // 拡張子が CSV だったら、専用のモードでファイルを処理する
157- handleCsvFile(log_file);
158-
159- } else {
160- handleRawFile(log_file);
161- }
162- }
163-
164-
165- void handleRawFile(const QString& log_file)
166- {
167- string std_log_file = qrk::toStdStringPath(log_file);
168- delete data_reader_;
169- data_reader_ = new ScipDataReader(std_log_file);
170-
171- prepareUrgReply();
172- // !!! 接続に失敗したら、ファイルフォーマットが無効、という表示をすべき
173- if (! urg_.connect("dummy")) {
174- fprintf(stderr, "UrgDevice::connect: %s\n", urg_.what());
175- }
176-
177- // 最初の描画、次データの取得、と2回のデータ更新を行う
178- for (int i = 0; i < 2; ++i) {
179- while ((! data_reader_->isEmpty()) && (! updateDrawData())) {
180- ;
181- }
182- }
183-
184-#if 0
185- // 最初のデータの表示を行う
186- updateDrawData();
187-#endif
188- }
189-
190-
191- void handleCsvFile(const QString& file_name)
192- {
193- // ディレクトリ中の CSV ファイルを、名前順に読み出す
194- QFileInfo file_info(file_name);
195- QDir dir = file_info.dir();
196- csv_files_dir_ = file_info.absolutePath();
197- QStringList filters;
198- filters << "*.csv" << "*.CSV";
199- dir.setNameFilters(filters);
200- csv_files_ =
201- dir.entryList(QDir::Files | QDir::NoSymLinks |
202- QDir::NoDotAndDotDot | QDir::Readable, QDir::Name);
203-
204- // 初期化
205- csv_index_ = 0;
206- current_timestamp_ = 0;
207-
208- // 最初のデータを表示させる
209- updateCsvFile();
210- }
211-
212-
213- bool updateCsvFile(void)
214- {
215- if (csv_index_ >= csv_files_.size()) {
216- return false;
217- }
218-
219- // CSV データを配置する
220- QString file_name = csv_files_[csv_index_];
221- QFile file(csv_files_dir_ + "/" + file_name);
222-
223- widget_->setWindowTitle("Scip Player: " + file_name);
224-
225- file.open(QIODevice::ReadOnly | QIODevice::Text);
226- // !!! エラー処理をすべき
227-
228- vector<Point<long> > points;
229- while (! file.atEnd()) {
230- QByteArray line = file.readLine();
231- setLine(points, line);
232- }
233-
234- urg_draw_widget_.clear();
235- urg_draw_widget_.setUrgData(points, 0);
236- urg_draw_widget_.redraw();
237-
238- ++csv_index_;
239- return true;
240- }
241-
242-
243- void setLine(vector<Point<long> >& points, const QByteArray& line)
244- {
245- QList<QByteArray> tokens = line.split(',');
246- if (tokens.size() < 5) {
247- // トークンが不足していたら戻る
248- return;
249- }
250-
251- // !!! Top-URG の場合は 23 なのを考慮すべき
252- if (atoi(tokens[1]) < 20) {
253- // 距離データがエラー値の場合は戻る
254- return;
255- }
256- long x = atoi(tokens[3]);
257- long y = atoi(tokens[4]);
258- points.push_back(Point<long>(-y, x));
259- }
260-
261-
262- void prepareUrgReply(void)
263- {
264- con_.clear();
265- con_.setReadData("QT\r00P\r\r");
266-
267- // ダミーデータ
268- con_.setReadData("PP\r"
269- "00P\r"
270- "MODL:URG-04LX(Hokuyo Automatic Co.,Ltd.);N\r"
271- "DMIN:20;4\r"
272- "DMAX:5600;_\r"
273- "ARES:1024;\r"
274- "AMIN:44;7\r"
275- "AMAX:725;o\r"
276- "AFRT:384;6\r"
277- "SCAN:600;e\r"
278- "\r");
279- }
280-
281-
282- bool updateDrawData(void)
283- {
284- if (csv_mode_) {
285- return updateCsvFile();
286- } else {
287- return updateRawDraw();
288- }
289- }
290-
291-
292-
293- bool updateRawDraw(void)
294- {
295- if (! scip_data_.empty()) {
296- // 保持しているデータを描画
297- current_timestamp_ = timestamp(scip_data_);
298- setScipData(scip_data_);
299- urg_draw_widget_.setUrgData(&urg_);
300- urg_draw_widget_.redraw();
301- scip_data_.clear();
302-
303- QString message = QString("timestamp: %1 [msec] (%2)")
304- .arg(current_timestamp_)
305- .arg(current_timestamp_ - last_timestamp_);
306- widget_->statusBar()->showMessage(message, 60 * 1000);
307- last_timestamp_ = current_timestamp_;
308- }
309-
310- ScipData line_block;
311- while (data_reader_->readReplyLines(line_block)) {
312-
313- string& first_line = line_block[0];
314- if (! first_line.compare(0, 2, "BM")) {
315- con_.setReadData("BM\r00P\r\r");
316-
317- } else if (! first_line.compare(0, 2, "PP")) {
318- // パラメータ読み出し
319- setScipData(line_block);
320- urg_.loadParameter();
321-
322- } else if (! first_line.compare(0, 1, "G")) {
323- // Gx データの読み出し
324- swap(scip_data_, line_block);
325- setPlayEnabled(true);
326- return true;
327-
328- } else if (! first_line.compare(0, 1, "M")) {
329-
330- if (line_block.size() <= 2) {
331- // MD を RawManualCapture で無理矢理に再生させるための処理
332- // !!! 重複をどうにかする
333- if (! led_on_) {
334- con_.setReadData("BM\r00P\r\r");
335- led_on_ = true;
336- }
337- if (! first_line.compare(1, 1, "E")) {
338- fprintf(stderr, "set intensity mode.\n");
339- urg_.setCaptureMode(IntensityCapture);
340- }
341-
342- } else {
343- // Mx データの読み出し
344- // !!! 重複をどうにかする
345- swap(scip_data_, line_block);
346- setPlayEnabled(true);
347- return true;
348- }
349- }
350- }
351-
352- setPlayEnabled(false);
353- return false;
354- }
355-
356-
357- void setPlayEnabled(bool enable)
358- {
359- widget_->next_button_->setEnabled(enable);
360- widget_->continuous_button_->setEnabled(enable);
361- }
362-
363-
364- void setScipData(const ScipData& line_block)
365- {
366- for (ScipData::const_iterator it = line_block.begin();
367- it != line_block.end(); ++it) {
368- con_.setReadData(*it + "\r");
369- }
370- }
371-
372-
373- void continuousPlay(void)
374- {
375- if (updateDrawData()) {
376- long delay = timestamp(scip_data_) - current_timestamp_;
377- if (play_ratio_ > 0) {
378- delay /= play_ratio_;
379- }
380- continuous_timer_.start(max(delay, 1L));
381- }
382- }
383-
384-
385- long timestamp(const ScipData& data)
386- {
387- if (data.size() <= 2) {
388- //return 100;
389- return 25;
390- }
391- return ScipHandler::decode(data[2].c_str(), 4);
392- }
393-};
394-
395-
396-ScipPlayerWindow::ScipPlayerWindow(void) : pimpl(new pImpl(this))
397-{
398- setupUi(this);
399- pimpl->initializeForm();
400- pimpl->loadSettings();
401-
402- pimpl->reload();
403-}
404-
405-
406-ScipPlayerWindow::~ScipPlayerWindow(void)
407-{
408- pimpl->saveSettings();
409-}
410-
411-
412-void ScipPlayerWindow::aboutApplication(void)
413-{
414- QMessageBox::about(this, tr("About Scip Player"),
415- tr("<h2>Scip Player ($Rev$)</h2>"
416- "<p>Demo Application for URG sensor</p>"
417- "<p>Report bugs to "
418- "&lt;s-kamimura@hokuyo-aut.co.jp&gt;</p>"));
419-}
420-
421-
422-void ScipPlayerWindow::pathPressed(void)
423-{
424- QString file_name =
425- QFileDialog::getOpenFileName(this, tr("SCIP Log file"),
426- path_edit_->text(),
427- tr("Log files (*.txt *.log *.csv)"));
428- if (file_name.isEmpty()) {
429- return;
430- }
431-
432- path_edit_->setText(file_name);
433- pimpl->reload();
434-}
435-
436-
437-void ScipPlayerWindow::reloadPressed(void)
438-{
439- pimpl->reload();
440-}
441-
442-
443-void ScipPlayerWindow::nextPressed(void)
444-{
445- pimpl->continuous_timer_.stop();
446- if (pimpl->play_ratio_ > 0) {
447- --pimpl->play_ratio_;
448- }
449- pimpl->updateDrawData();
450-}
451-
452-
453-void ScipPlayerWindow::timerTimeout(void)
454-{
455- pimpl->continuousPlay();
456-}
457-
458-
459-void ScipPlayerWindow::continuousPressed(void)
460-{
461- ++pimpl->play_ratio_;
462- pimpl->continuousPlay();
463-}
464-
465-
466-void ScipPlayerWindow::dragEnterEvent(QDragEnterEvent* event)
467-{
468- if (event->mimeData()->hasFormat("text/uri-list")) {
469- event->acceptProposedAction();
470- }
471-}
472-
473-
474-void ScipPlayerWindow::dropEvent(QDropEvent* event)
475-{
476- QList<QUrl> urls = event->mimeData()->urls();
477- if (urls.isEmpty()) {
478- return;
479- }
480-
481- QString file_name = urls.first().toLocalFile();
482- if (file_name.isEmpty()) {
483- return;
484- }
485-
486- path_edit_->setText(file_name);
487- pimpl->reload();
488-}
489-
490-
491-void ScipPlayerWindow::zoomSmaller(void)
492-{
493- pimpl->urg_draw_widget_.updateZoomRatio(+1);
494-}
495-
496-
497-void ScipPlayerWindow::zoomLarger(void)
498-{
499- pimpl->urg_draw_widget_.updateZoomRatio(-1);
500-}
501-
502-
503-void ScipPlayerWindow::initializeView(void)
504-{
505- pimpl->urg_draw_widget_.initializeView();
506-}
1+/*!
2+ \file
3+ \brief SCIP データの表示ウィンドウ
4+
5+ \author Satofumi KAMIMURA
6+
7+ $Id$
8+
9+ \todo MD の 00P 応答のときに、適切に読み出せるようにする
10+*/
11+
12+#include "ScipPlayerWindow.h"
13+#include "ScipDataReader.h"
14+#include "UrgDrawWidget.h"
15+#include "UrgDevice.h"
16+#include "ScipHandler.h"
17+#include "CustomConnection.h"
18+#include "ConvertStdStringPath.h"
19+#include <QTimer>
20+#include <QUrl>
21+#include <QDragEnterEvent>
22+#include <QDropEvent>
23+#include <QFileDialog>
24+#include <QShortcut>
25+#include <QSettings>
26+#include <QMessageBox>
27+
28+using namespace qrk;
29+using namespace std;
30+
31+
32+namespace
33+{
34+ const char* Organization = "Hokuyo LTD.";
35+ const char* Application = "Scip Player";
36+
37+ typedef vector<string> ScipData;
38+}
39+
40+
41+struct ScipPlayerWindow::pImpl
42+{
43+ ScipPlayerWindow* widget_;
44+ UrgDrawWidget urg_draw_widget_;
45+ ScipDataReader* data_reader_;
46+
47+ ScipData scip_data_;
48+ long current_timestamp_;
49+ long last_timestamp_;
50+
51+ CustomConnection con_;
52+ UrgDevice urg_;
53+
54+ QTimer continuous_timer_;
55+ int play_ratio_;
56+ bool led_on_;
57+
58+ QStringList csv_files_;
59+ QString csv_files_dir_;
60+ bool csv_mode_;
61+ int csv_index_;
62+
63+
64+ pImpl(ScipPlayerWindow* parent)
65+ : widget_(parent), data_reader_(NULL),
66+ current_timestamp_(0), last_timestamp_(0),
67+ play_ratio_(0), led_on_(false), csv_mode_(false), csv_index_(0)
68+ {
69+ urg_.setConnection(&con_);
70+ continuous_timer_.setSingleShot(true);
71+ urg_draw_widget_.setDrawPeriod(1);
72+ }
73+
74+
75+ ~pImpl(void)
76+ {
77+ delete data_reader_;
78+ }
79+
80+
81+ void initializeForm(void)
82+ {
83+ // 表示ウィジット
84+ widget_->dummy_label_->hide();
85+ widget_->main_layout_->addWidget(&urg_draw_widget_);
86+
87+ widget_->path_edit_->setAcceptDrops(false);
88+ widget_->setAcceptDrops(true);
89+
90+ // イベント
91+ connect(widget_->path_button_, SIGNAL(clicked()),
92+ widget_, SLOT(pathPressed()));
93+ connect(widget_->reload_button_, SIGNAL(clicked()),
94+ widget_, SLOT(reloadPressed()));
95+ connect(widget_->next_button_, SIGNAL(clicked()),
96+ widget_, SLOT(nextPressed()));
97+ connect(widget_->continuous_button_, SIGNAL(clicked()),
98+ widget_, SLOT(continuousPressed()));
99+ connect(&continuous_timer_, SIGNAL(timeout()),
100+ widget_, SLOT(timerTimeout()));
101+
102+ // メニュー
103+ connect(widget_->action_about_, SIGNAL(triggered()),
104+ widget_, SLOT(aboutApplication()));
105+ connect(widget_->action_quit_, SIGNAL(triggered()),
106+ widget_, SLOT(close()));
107+
108+ // ショートカット
109+ (void) new QShortcut(Qt::Key_Return, widget_, SLOT(initializeView()));
110+ (void) new QShortcut(Qt::Key_F5, widget_, SLOT(reloadPressed()));
111+ (void) new QShortcut(Qt::Key_Less, widget_, SLOT(zoomSmaller()));
112+ (void) new QShortcut(Qt::Key_Comma, widget_, SLOT(zoomSmaller()));
113+ (void) new QShortcut(Qt::Key_Greater, widget_, SLOT(zoomLarger()));
114+ (void) new QShortcut(Qt::Key_Period, widget_, SLOT(zoomLarger()));
115+ }
116+
117+
118+ void saveSettings(void)
119+ {
120+ QSettings settings(Organization, Application);
121+
122+ settings.setValue("geometry", widget_->saveGeometry());
123+ settings.setValue("file_path", widget_->path_edit_->text());
124+ }
125+
126+
127+ void loadSettings(void)
128+ {
129+ QSettings settings(Organization, Application);
130+
131+ widget_->restoreGeometry(settings.value("geometry").toByteArray());
132+ QString log_file = settings.value("file_path", "").toString();
133+ widget_->path_edit_->setText(log_file);
134+ }
135+
136+
137+ void reload(void)
138+ {
139+ // !!! この初期化処理は、適切にまとめるべき
140+ widget_->setWindowTitle("Scip Player");
141+ continuous_timer_.stop();
142+ scip_data_.clear();
143+ con_.clear();
144+ urg_draw_widget_.clear();
145+ urg_draw_widget_.redraw();
146+ current_timestamp_ = 0;
147+ play_ratio_ = 0;
148+ led_on_ = false;
149+
150+ QString log_file = widget_->path_edit_->text();
151+
152+ QFileInfo file_info(log_file);
153+ QString suffix = file_info.suffix().toLower();
154+ csv_mode_ = (! suffix.compare("csv")) ? true : false;
155+ if (csv_mode_) {
156+ // 拡張子が CSV だったら、専用のモードでファイルを処理する
157+ handleCsvFile(log_file);
158+
159+ } else {
160+ handleRawFile(log_file);
161+ }
162+ }
163+
164+
165+ void handleRawFile(const QString& log_file)
166+ {
167+ string std_log_file = qrk::toStdStringPath(log_file);
168+ delete data_reader_;
169+ data_reader_ = new ScipDataReader(std_log_file);
170+
171+ prepareUrgReply();
172+ // !!! 接続に失敗したら、ファイルフォーマットが無効、という表示をすべき
173+ if (! urg_.connect("dummy")) {
174+ fprintf(stderr, "UrgDevice::connect: %s\n", urg_.what());
175+ }
176+
177+ // 最初の描画、次データの取得、と2回のデータ更新を行う
178+ for (int i = 0; i < 2; ++i) {
179+ while ((! data_reader_->isEmpty()) && (! updateDrawData())) {
180+ ;
181+ }
182+ }
183+
184+#if 0
185+ // 最初のデータの表示を行う
186+ updateDrawData();
187+#endif
188+ }
189+
190+
191+ void handleCsvFile(const QString& file_name)
192+ {
193+ // ディレクトリ中の CSV ファイルを、名前順に読み出す
194+ QFileInfo file_info(file_name);
195+ QDir dir = file_info.dir();
196+ csv_files_dir_ = file_info.absolutePath();
197+ QStringList filters;
198+ filters << "*.csv" << "*.CSV";
199+ dir.setNameFilters(filters);
200+ csv_files_ =
201+ dir.entryList(QDir::Files | QDir::NoSymLinks |
202+ QDir::NoDotAndDotDot | QDir::Readable, QDir::Name);
203+
204+ // 初期化
205+ csv_index_ = 0;
206+ current_timestamp_ = 0;
207+
208+ // 最初のデータを表示させる
209+ updateCsvFile();
210+ }
211+
212+
213+ bool updateCsvFile(void)
214+ {
215+ if (csv_index_ >= csv_files_.size()) {
216+ return false;
217+ }
218+
219+ // CSV データを配置する
220+ QString file_name = csv_files_[csv_index_];
221+ QFile file(csv_files_dir_ + "/" + file_name);
222+
223+ widget_->setWindowTitle("Scip Player: " + file_name);
224+
225+ file.open(QIODevice::ReadOnly | QIODevice::Text);
226+ // !!! エラー処理をすべき
227+
228+ vector<Point<long> > points;
229+ while (! file.atEnd()) {
230+ QByteArray line = file.readLine();
231+ setLine(points, line);
232+ }
233+
234+ urg_draw_widget_.clear();
235+ urg_draw_widget_.setUrgData(points, 0);
236+ urg_draw_widget_.redraw();
237+
238+ ++csv_index_;
239+ return true;
240+ }
241+
242+
243+ void setLine(vector<Point<long> >& points, const QByteArray& line)
244+ {
245+ QList<QByteArray> tokens = line.split(',');
246+ if (tokens.size() < 5) {
247+ // トークンが不足していたら戻る
248+ return;
249+ }
250+
251+ // !!! Top-URG の場合は 23 なのを考慮すべき
252+ if (atoi(tokens[1]) < 20) {
253+ // 距離データがエラー値の場合は戻る
254+ return;
255+ }
256+ long x = atoi(tokens[3]);
257+ long y = atoi(tokens[4]);
258+ points.push_back(Point<long>(-y, x));
259+ }
260+
261+
262+ void prepareUrgReply(void)
263+ {
264+ con_.clear();
265+ con_.setReadData("QT\r00P\r\r");
266+
267+ // ダミーデータ
268+ con_.setReadData("PP\r"
269+ "00P\r"
270+ "MODL:URG-04LX(Hokuyo Automatic Co.,Ltd.);N\r"
271+ "DMIN:20;4\r"
272+ "DMAX:5600;_\r"
273+ "ARES:1024;\r"
274+ "AMIN:44;7\r"
275+ "AMAX:725;o\r"
276+ "AFRT:384;6\r"
277+ "SCAN:600;e\r"
278+ "\r");
279+ }
280+
281+
282+ bool updateDrawData(void)
283+ {
284+ if (csv_mode_) {
285+ return updateCsvFile();
286+ } else {
287+ return updateRawDraw();
288+ }
289+ }
290+
291+
292+
293+ bool updateRawDraw(void)
294+ {
295+ if (! scip_data_.empty()) {
296+ // 保持しているデータを描画
297+ current_timestamp_ = timestamp(scip_data_);
298+ setScipData(scip_data_);
299+ urg_draw_widget_.setUrgData(&urg_);
300+ urg_draw_widget_.redraw();
301+ scip_data_.clear();
302+
303+ QString message = QString("timestamp: %1 [msec] (%2)")
304+ .arg(current_timestamp_)
305+ .arg(current_timestamp_ - last_timestamp_);
306+ widget_->statusBar()->showMessage(message, 60 * 1000);
307+ last_timestamp_ = current_timestamp_;
308+ }
309+
310+ ScipData line_block;
311+ while (data_reader_->readReplyLines(line_block)) {
312+
313+ string& first_line = line_block[0];
314+ if (! first_line.compare(0, 2, "BM")) {
315+ con_.setReadData("BM\r00P\r\r");
316+
317+ } else if (! first_line.compare(0, 2, "PP")) {
318+ // パラメータ読み出し
319+ setScipData(line_block);
320+ urg_.loadParameter();
321+
322+ } else if (! first_line.compare(0, 1, "G")) {
323+ // Gx データの読み出し
324+ swap(scip_data_, line_block);
325+ setPlayEnabled(true);
326+ return true;
327+
328+ } else if (! first_line.compare(0, 1, "M")) {
329+
330+ if (line_block.size() <= 2) {
331+ // MD を RawManualCapture で無理矢理に再生させるための処理
332+ // !!! 重複をどうにかする
333+ if (! led_on_) {
334+ con_.setReadData("BM\r00P\r\r");
335+ led_on_ = true;
336+ }
337+ if (! first_line.compare(1, 1, "E")) {
338+ fprintf(stderr, "set intensity mode.\n");
339+ urg_.setCaptureMode(IntensityCapture);
340+ }
341+
342+ } else {
343+ // Mx データの読み出し
344+ // !!! 重複をどうにかする
345+ swap(scip_data_, line_block);
346+ setPlayEnabled(true);
347+ return true;
348+ }
349+ }
350+ }
351+
352+ setPlayEnabled(false);
353+ return false;
354+ }
355+
356+
357+ void setPlayEnabled(bool enable)
358+ {
359+ widget_->next_button_->setEnabled(enable);
360+ widget_->continuous_button_->setEnabled(enable);
361+ }
362+
363+
364+ void setScipData(const ScipData& line_block)
365+ {
366+ for (ScipData::const_iterator it = line_block.begin();
367+ it != line_block.end(); ++it) {
368+ con_.setReadData(*it + "\r");
369+ }
370+ }
371+
372+
373+ void continuousPlay(void)
374+ {
375+ if (updateDrawData()) {
376+ long delay = timestamp(scip_data_) - current_timestamp_;
377+ if (play_ratio_ > 0) {
378+ delay /= play_ratio_;
379+ }
380+ continuous_timer_.start(max(delay, 1L));
381+ }
382+ }
383+
384+
385+ long timestamp(const ScipData& data)
386+ {
387+ if (data.size() <= 2) {
388+ //return 100;
389+ return 25;
390+ }
391+ return ScipHandler::decode(data[2].c_str(), 4);
392+ }
393+};
394+
395+
396+ScipPlayerWindow::ScipPlayerWindow(void) : pimpl(new pImpl(this))
397+{
398+ setupUi(this);
399+ pimpl->initializeForm();
400+ pimpl->loadSettings();
401+
402+ pimpl->reload();
403+}
404+
405+
406+ScipPlayerWindow::~ScipPlayerWindow(void)
407+{
408+ pimpl->saveSettings();
409+}
410+
411+
412+void ScipPlayerWindow::aboutApplication(void)
413+{
414+ QMessageBox::about(this, tr("About Scip Player"),
415+ tr("<h2>Scip Player ($Rev$)</h2>"
416+ "<p>Demo Application for URG sensor</p>"
417+ "<p>Report bugs to "
418+ "&lt;s-kamimura@hokuyo-aut.co.jp&gt;</p>"));
419+}
420+
421+
422+void ScipPlayerWindow::pathPressed(void)
423+{
424+ QString file_name =
425+ QFileDialog::getOpenFileName(this, tr("SCIP Log file"),
426+ path_edit_->text(),
427+ tr("Log files (*.txt *.log *.csv)"));
428+ if (file_name.isEmpty()) {
429+ return;
430+ }
431+
432+ path_edit_->setText(file_name);
433+ pimpl->reload();
434+}
435+
436+
437+void ScipPlayerWindow::reloadPressed(void)
438+{
439+ pimpl->reload();
440+}
441+
442+
443+void ScipPlayerWindow::nextPressed(void)
444+{
445+ pimpl->continuous_timer_.stop();
446+ if (pimpl->play_ratio_ > 0) {
447+ --pimpl->play_ratio_;
448+ }
449+ pimpl->updateDrawData();
450+}
451+
452+
453+void ScipPlayerWindow::timerTimeout(void)
454+{
455+ pimpl->continuousPlay();
456+}
457+
458+
459+void ScipPlayerWindow::continuousPressed(void)
460+{
461+ ++pimpl->play_ratio_;
462+ pimpl->continuousPlay();
463+}
464+
465+
466+void ScipPlayerWindow::dragEnterEvent(QDragEnterEvent* event)
467+{
468+ if (event->mimeData()->hasFormat("text/uri-list")) {
469+ event->acceptProposedAction();
470+ }
471+}
472+
473+
474+void ScipPlayerWindow::dropEvent(QDropEvent* event)
475+{
476+ QList<QUrl> urls = event->mimeData()->urls();
477+ if (urls.isEmpty()) {
478+ return;
479+ }
480+
481+ QString file_name = urls.first().toLocalFile();
482+ if (file_name.isEmpty()) {
483+ return;
484+ }
485+
486+ path_edit_->setText(file_name);
487+ pimpl->reload();
488+}
489+
490+
491+void ScipPlayerWindow::zoomSmaller(void)
492+{
493+ pimpl->urg_draw_widget_.updateZoomRatio(+1);
494+}
495+
496+
497+void ScipPlayerWindow::zoomLarger(void)
498+{
499+ pimpl->urg_draw_widget_.updateZoomRatio(-1);
500+}
501+
502+
503+void ScipPlayerWindow::initializeView(void)
504+{
505+ pimpl->urg_draw_widget_.initializeView();
506+}
--- trunk/programs/Makefile (revision 1977)
+++ trunk/programs/Makefile (revision 1978)
@@ -14,7 +14,6 @@
1414 cd UrgPorts/ && $(QMAKE_COMMAND) && $(MAKE)
1515 cd MultiUrgViewer/ && $(QMAKE_COMMAND) && $(MAKE)
1616 cd ScipPlayer/ && $(QMAKE_COMMAND) && $(MAKE)
17- cd ScipRecorder/ && $(QMAKE_COMMAND) && $(MAKE)
1817 -cd UrgLasers/ && $(MAKE)
1918 cd cUrgViewer/ && $(QMAKE_COMMAND) && $(MAKE)
2019 cd ItemShuffle/ && $(QMAKE_COMMAND) && $(MAKE)
@@ -39,7 +38,6 @@
3938 -cd UrgPorts/ && (if test -f Makefile; then $(MAKE) distclean; fi)
4039 -cd MultiUrgViewer/ && (if test -f Makefile; then $(MAKE) distclean; fi)
4140 -cd ScipPlayer/ && (if test -f Makefile; then $(MAKE) distclean; fi); $(RM) error_log.txt
42- -cd ScipRecorder/ && (if test -f Makefile; then $(MAKE) distclean; fi); $(RM) error_log.txt
4341 -cd UrgLasers/ && $(MAKE) clean
4442 -cd cUrgViewer/ && (if test -f Makefile; then $(MAKE) distclean; fi)
4543 -cd ItemShuffle/ && $(MAKE) clean
旧リポジトリブラウザで表示