2 #include "GVORenderer.h"
3 #include "GVOWorldMap.h"
9 const double k_scaleStep = 0.125; // 12.5%
10 const double k_minScale = 0.125; // 12.5%
11 const double k_maxScale = 4.00; // 400%
13 // Google
\90æ
\90¶
\9eH
\82
\81u
\92n
\8b\85\82Ì
\8aO
\8eü
\82Í40,075km
\81v
\81u1
\83m
\83b
\83g
\82Í1.85200km
\81v
14 // 1
\90¢
\8aE
\8dÀ
\95W
\82Í40,075km/16384points
15 //
\8eÀ
\8e\9e\8aÔ1
\95b
\82Å
\83Q
\81[
\83\80\93à0.4
\8e\9e\8aÔ
17 //
\92n
\8b\85\8aO
\8eü
\82ð
\90Ô
\93¹
\94¼
\8ca
\82©
\82ç
\8eZ
\8fo
\82·
\82é
\81B
18 //
\90Ô
\93¹
\94¼
\8ca
\82Í6378.137
\82È
\82Ì
\82Å
\8aO
\8eü
\82Í2*M_PI_*6378.137
19 inline double s_velocityByKnot( const double velocity )
21 static const double k_knotFactor = (2 * M_PI * 6378.137) / 16384.0 / 0.4 / 1.852;
22 return velocity * k_knotFactor;
27 void GVORenderer::setup( HDC hdcPrimary )
29 m_hdcPrimary = hdcPrimary;
33 void GVORenderer::teardown()
39 void GVORenderer::setWorldMap( const GVOWorldMap& worldMap )
41 m_worldMap = &worldMap;
42 const GVOImage & map = m_worldMap->image();
43 m_mapImage.copy( map );
47 void GVORenderer::setConfig( const GVOConfig& config )
49 m_positionUpdated = config.m_traceShipPositionEnabled;
50 m_focusPointInWorldCoord = config.m_initialSurveyCoord;
51 m_shipPointInWorld = config.m_initialSurveyCoord;
52 m_previousDrawPointInWorld = m_shipPointInWorld;
53 m_shipVectorLineEnabled = config.m_shipVectorLineEnabled;
54 m_speedMeterEnabled = config.m_speedMeterEnabled;
55 m_traceShipEnabled = config.m_traceShipPositionEnabled;
59 void GVORenderer::setViewSize( const SIZE& viewSize )
61 m_viewSize = viewSize;
65 SIZE GVORenderer::scaledMapSize() const
68 LONG( m_mapImage.width() * m_viewScale ),
69 LONG( m_mapImage.height() * m_viewScale )
75 POINT GVORenderer::mapOriginInView() const
77 const POINT viewCenter = viewCenterPoint();
78 const SIZE mapSize = scaledMapSize();
79 const POINT worldPosInView = drawOffsetFromWorldCoord( m_focusPointInWorldCoord );
82 viewCenter.x - worldPosInView.x,
83 viewCenter.y - worldPosInView.y
85 if ( m_viewSize.cx < mapSize.cx ) {
86 while ( 0 < mapTopLeft.x ) {
87 mapTopLeft.x -= mapSize.cx;
95 void GVORenderer::offsetFocusInViewCoord( const POINT& offset )
97 const double dx = ((double)offset.x / m_viewScale) / m_mapImage.width();
98 const double dy = ((double)offset.y / m_viewScale) / m_mapImage.height();
100 LONG x = m_focusPointInWorldCoord.x + LONG( dx * k_worldWidth );
101 LONG y = m_focusPointInWorldCoord.y + LONG( dy * k_worldHeight );
102 y = max( 0, min( y, k_worldHeight ) );
106 while ( k_worldWidth < x ) {
110 m_focusPointInWorldCoord.x = x;
111 m_focusPointInWorldCoord.y = y;
115 bool GVORenderer::zoomIn()
117 double scale = m_viewScale;
118 double step = k_scaleStep;
120 scale = m_viewScale + step;
121 if ( k_maxScale < scale ) {
124 if ( m_viewScale != scale ) {
132 bool GVORenderer::zoomOut()
134 double scale = m_viewScale;
135 double step = k_scaleStep;
137 scale = m_viewScale - step;
138 if ( scale < k_minScale ) {
141 if ( m_viewScale != scale ) {
149 void GVORenderer::resetViewScale()
155 POINT GVORenderer::drawOffsetFromWorldCoord( const POINT&worldCoord ) const
157 const POINT worldPosInImage = m_worldMap->imageCoordFromWorldCoord( worldCoord );
158 const POINT drawOffset = {
159 LONG( worldPosInImage.x * m_viewScale ),
160 LONG( worldPosInImage.y * m_viewScale )
166 void GVORenderer::updateShipState( const POINT& worldCoord, const GVOVector& shipVector, const double shipVelocity )
168 m_shipVector = shipVector;
169 m_shipVelocity = shipVelocity;
171 if ( m_traceShipEnabled ) {
172 m_focusPointInWorldCoord = worldCoord;
174 if ( m_shipPointInWorld.x != worldCoord.x
175 || m_shipPointInWorld.y != worldCoord.y ) {
177 m_positionUpdated = true;
178 m_shipPointInWorld = worldCoord;
180 updateShipRouteMap();
184 void GVORenderer::updateShipRouteMap()
186 //
\88Ú
\93®
\82µ
\82Ä
\82¢
\82È
\82¯
\82ê
\82Î
\89½
\82à
\82µ
\82È
\82¢
187 if ( !m_positionUpdated ) {
190 //
\88Ú
\93®
\82µ
\82Ä
\82¢
\82Ä
\82à
\8dq
\98H
\82ð
\8cq
\82°
\82È
\82¢
\82È
\82ç
\95`
\89æ
\82µ
\82È
\82¢
191 if ( !m_linkRoute ) {
192 m_previousDrawPointInWorld = m_shipPointInWorld;
197 const POINT& latestPoint = m_worldMap->imageCoordFromWorldCoord( m_shipPointInWorld );
198 const POINT& previousPoint = m_worldMap->imageCoordFromWorldCoord( m_previousDrawPointInWorld );
200 //
\95`
\89æ
\8dÀ
\95W
\82ª
\88ê
\8f\8f\82È
\82ç
\89½
\82à
\82µ
\82È
\82¢
201 if ( latestPoint.x == previousPoint.x
202 && latestPoint.y == previousPoint.y ) {
207 //
\8dÅ
\90V
\8dÀ
\95W
\82©
\82ç
\88ê
\82Â
\91O
\82Ì
\8dÀ
\95W
\82Ö
\90ü
\82ð
\88ø
\82
208 //
\90¢
\8aE
\82ð
\8c×
\82®
\8fê
\8d\87\82É
\8dl
\97¶
\82ª
\95K
\97v
\81B
209 //
\88Ú
\93®
\97Ê
\82ª
\88ê
\92è
\82ð
\92´
\82¦
\82½
\82ç
\95`
\89æ
\8f\88\97\9d\82µ
\82È
\82¢
\82æ
\82¤
\82É
\82·
\82é
\82Ì
\82ª
\83X
\83}
\81[
\83g
\82©
\82È
212 //
\90¢
\8aE
\82ð
\8c×
\82¢
\82¾
\82Æ
\82Ý
\82È
\82·è
\87\92l
213 const int k_distanceThreshold = m_mapImage.width() / 2;
215 const LONG xMin = min( latestPoint.x, previousPoint.x );
216 const LONG xMax = max( latestPoint.x, previousPoint.x );
217 const int xDistance = xMax - xMin;
220 HDC hdcMem = ::CreateCompatibleDC( m_hdcPrimary );
223 HPEN hpen = ::CreatePen( PS_SOLID, 1, RGB( 255, 255, 255 ) );
225 ::SelectObject( hdcMem, m_mapImage.bitmapHandle() );
226 ::SelectObject( hdcMem, hpen );
228 if ( k_distanceThreshold < xDistance ) {
229 if ( previousPoint.x < latestPoint.x ) { //
\90¢
\8aE
\82ð
\90¼
\82É
\8cü
\82©
\82Á
\82Ä
\8c×
\82¢
\82¾
230 //
\8d¶
\82Ì
\89æ
\96Ê
\8aO
\82©
\82ç
\8cü
\82©
\82¤
\90ü
\82ð
\95`
\89æ
231 LONG x3 = latestPoint.x - m_mapImage.width();
233 ::MoveToEx( hdcMem, x3, latestPoint.y, NULL );
234 ::LineTo( hdcMem, previousPoint.x, previousPoint.y );
236 //
\89E
\82Ì
\89æ
\96Ê
\8aO
\82É
\8cü
\82©
\82¤
\90ü
\82ð
\95`
\89æ
237 LONG x4 = previousPoint.x + m_mapImage.width();
238 ::MoveToEx( hdcMem, latestPoint.x, latestPoint.y, NULL );
239 ::LineTo( hdcMem, x4, previousPoint.y );
241 else { //
\90¢
\8aE
\82ð
\93\8c\82É
\8cü
\82©
\82Á
\82Ä
\8c×
\82¢
\82¾
242 //
\8d¶
\82Ì
\89æ
\96Ê
\8aO
\82©
\82ç
\8cü
\82©
\82¤
\90ü
\82ð
\95`
\89æ
243 LONG x3 = previousPoint.x - m_mapImage.width();
245 ::MoveToEx( hdcMem, latestPoint.x, latestPoint.y, NULL );
246 ::LineTo( hdcMem, x3, previousPoint.y );
248 //
\89E
\82Ì
\89æ
\96Ê
\8aO
\82É
\8cü
\82©
\82¤
\90ü
\82ð
\95`
\89æ
249 LONG x4 = latestPoint.x + m_mapImage.width();
250 ::MoveToEx( hdcMem, x4, latestPoint.y, NULL );
251 ::LineTo( hdcMem, previousPoint.x, previousPoint.y );
255 //
\8c×
\82ª
\82È
\82¢
\95`
\89æ
256 ::MoveToEx( hdcMem, latestPoint.x, latestPoint.y, NULL );
257 ::LineTo( hdcMem, previousPoint.x, previousPoint.y );
261 ::RestoreDC( hdcMem, -1 );
262 ::DeleteDC( hdcMem );
263 ::DeleteObject( hpen );
265 m_previousDrawPointInWorld = m_shipPointInWorld;
269 void GVORenderer::clearShipRoute()
271 m_mapImage.copy( m_worldMap->image() );
275 void GVORenderer::render()
277 if ( !m_backBuffer.isCompatible(m_viewSize) ) {
278 m_backBuffer.createDIBImage( m_viewSize );
280 HDC hdcBackbuffer = ::CreateCompatibleDC( m_hdcPrimary );
281 ::SaveDC( hdcBackbuffer );
283 ::SelectObject( hdcBackbuffer, m_backBuffer.bitmapHandle() );
284 RECT rc = { 0, 0, m_backBuffer.width(), m_backBuffer.height()};
285 ::FillRect( hdcBackbuffer, &rc, (HBRUSH)::GetStockObject( BLACK_BRUSH ) );
287 drawMap( hdcBackbuffer, m_shipVector );
289 if ( m_speedMeterEnabled ) {
290 drawSpeedMeter( hdcBackbuffer, m_shipVelocity );
293 ::BitBlt( m_hdcPrimary, 0, 0, m_backBuffer.width(), m_backBuffer.height(),
294 hdcBackbuffer, 0, 0, SRCCOPY );
295 ::RestoreDC( hdcBackbuffer, -1 );
296 ::DeleteDC( hdcBackbuffer );
300 void GVORenderer::drawMap( HDC hdc, const GVOVector& shipVector )
302 const SIZE mapSize = scaledMapSize();
303 const GVOImage *mapImage = &m_mapImage;
306 if ( m_viewScale < 1.0 ) {
308 ::GetBrushOrgEx( hdc, &org );
309 ::SetStretchBltMode( hdc, HALFTONE );
310 ::SetBrushOrgEx( hdc, org.x, org.y, NULL );
313 ::SetStretchBltMode( hdc, COLORONCOLOR );
316 HDC hdcMem = ::CreateCompatibleDC( hdc );
319 ::SelectObject( hdcMem, mapImage->bitmapHandle() );
321 const POINT mapTopLeft = mapOriginInView();
323 int xDrawOrigin, yDrawOrigin;
324 xDrawOrigin = mapTopLeft.x;
325 yDrawOrigin = mapTopLeft.y;
327 if ( 0 < xDrawOrigin ) {
328 xDrawOrigin = (xDrawOrigin % mapSize.cx) - mapSize.cx;
330 const int xInitial = xDrawOrigin; //
\8d¶
\92[
\82Ì
\95`
\89æ
\8aJ
\8enx
\8dÀ
\95W
331 int drawn = xInitial; //
\95`
\89æ
\8dÏ
\82Ý
\8dÀ
\95W
333 //
\90¢
\8aE
\92n
\90}
\82ð
\89¡
\82É
\95À
\82×
\82Ä
\95`
\89æ
334 //
\81i
\95`
\89æ
\8dÅ
\93K
\89»
\82Í
\8fÈ
\97ª
\81j
335 while ( drawn < m_viewSize.cx ) {
337 xDrawOrigin, yDrawOrigin,
338 mapSize.cx, mapSize.cy,
341 mapImage->width(), mapImage->height(),
344 xDrawOrigin += mapSize.cx;
349 const POINT shipPointOffset = drawOffsetFromWorldCoord( m_shipPointInWorld );
351 //
\90j
\98H
\97\
\91ª
\90ü
\82ð
\95`
\89æ
352 if ( shipVector.length() != 0.0 && m_shipVectorLineEnabled ) {
353 const int penWidth = max( 1, int( 1 * m_viewScale ) );
354 HPEN courseLinePen = ::CreatePen( PS_SOLID, penWidth, RGB( 255, 0, 255 ) );
355 HGDIOBJ oldPen = ::SelectObject( hdc, courseLinePen );
357 const LONG k_lineLength = k_worldHeight;
358 const POINT reachPointOffset = drawOffsetFromWorldCoord(
359 shipVector.pointFromOriginWithLength( m_shipPointInWorld, k_lineLength )
362 //
\8c©
\82¦
\82Ä
\82é
\92n
\90}
\89æ
\91\9c\82Ì
\95ª
\82¾
\82¯
\95`
\89æ
\82·
\82é
364 xDrawOrigin = xInitial;
365 while ( drawn < m_viewSize.cx ) {
366 const POINT shipPointInView = {
367 xDrawOrigin + shipPointOffset.x,
368 yDrawOrigin + shipPointOffset.y
370 const POINT reachPointInView = {
371 xDrawOrigin + reachPointOffset.x,
372 yDrawOrigin + reachPointOffset.y
374 ::MoveToEx( hdc, shipPointInView.x, shipPointInView.y, NULL );
375 ::LineTo( hdc, reachPointInView.x, reachPointInView.y );
376 xDrawOrigin += mapSize.cx;
380 ::SelectObject( hdc, oldPen );
381 ::DeleteObject( courseLinePen );
384 //
\8e©
\91D
\82Ì
\88Ê
\92u
\82ð
\95`
\89æ
385 const SIZE shipMarkSize = { 6, 6 };
386 HBRUSH shipBrush = ::CreateSolidBrush( RGB( 51, 238, 153 ) );
387 HGDIOBJ prevBrush = ::SelectObject( hdc, shipBrush );
389 //
\8c©
\82¦
\82Ä
\82é
\92n
\90}
\89æ
\91\9c\82Ì
\95ª
\82¾
\82¯
\95`
\89æ
\82·
\82é
391 xDrawOrigin = xInitial;
392 while ( drawn < m_viewSize.cx ) {
394 xDrawOrigin + shipPointOffset.x - shipMarkSize.cx / 2,
395 yDrawOrigin + shipPointOffset.y - shipMarkSize.cy / 2,
396 xDrawOrigin + shipPointOffset.x + shipMarkSize.cx,
397 yDrawOrigin + shipPointOffset.y + shipMarkSize.cy );
399 xDrawOrigin += mapSize.cx;
402 ::SelectObject( hdc, prevBrush );
403 ::DeleteObject( shipBrush );
406 ::RestoreDC( hdcMem, -1 );
407 ::DeleteDC( hdcMem );
408 ::RestoreDC( hdc, -1 );
412 void GVORenderer::drawSpeedMeter( HDC hdc, double shipVelocity )
414 const double velocity = s_velocityByKnot( shipVelocity );
415 wchar_t buf[4096] = { 0 };
416 swprintf( buf, _countof( buf ), L"%.2f kt", velocity );
419 ::DrawText( hdc, buf, -1, &rc, DT_SINGLELINE | DT_RIGHT | DT_TOP | DT_CALCRECT );
420 const int width = rc.right - rc.left;
421 rc.left = m_viewSize.cx - width;
422 rc.right = rc.left + width;
423 ::DrawText( hdc, buf, -1, &rc, DT_SINGLELINE | DT_RIGHT | DT_TOP );