티스토리 뷰

반응형

Bing Map Control에 Google Map을 보여주는 예제로, 지도에 Pin을 설정하는 방법까지 작성을 하였다. 그러나, 기본 베이스는 지도 관련 셈플인것 처럼 보이나, 사실 Reactive Extension(Rx)를 실습하기 위한 프로젝트이다.

구글 지도를 Map 컨트롤에 보이도록 하는 작업에 대해서 간단하게 알아보자

1. MainPage.xaml.cs

    //구글맵 설정 클래스
    public class GoogleTile : TileSource
    {
        private int _server;
        private char _mapmode;
        private GoogleTileTypes _tiletypes;

        public GoogleTileTypes TileTypes
        {
            get { return _tiletypes; }
            set
            {
                _tiletypes = value;
                MapMode = MapModeConverter(value);
            }
        }

        public char MapMode
        {
            get { return _mapmode; }
            set { _mapmode = value; }
        }

        public int Server
        {
            get { return _server; }
            set { _server = value; }
        }

        public GoogleTile()
        {
            UriFormat = @"http://mt{0}.google.com/vt/lyrs={1}&z={2}&x={3}&y={4}";
            Server = 0;
        }

        public override Uri GetUri(int x, int y, int zoomLevel)
        {
            if (zoomLevel > 0)
            {
                var Url = string.Format(UriFormat, Server, MapMode, zoomLevel, x, y);
                return new Uri(Url);
            }
            return null;
        }

        private char MapModeConverter(GoogleTileTypes tiletype)
        {
            switch (tiletype)
            {
                case GoogleTileTypes.Hybrid:
                    {
                        return 'y';
                    }
                case GoogleTileTypes.Physical:
                    {
                        return 't';
                    }
                case GoogleTileTypes.Satellite:
                    {
                        return 's';
                    }
                case GoogleTileTypes.Street:
                    {
                        return 'm';
                    }
                case GoogleTileTypes.WaterOverlay:
                    {
                        return 'r';
                    }
            }
            return ' ';
        }
    }

위의 클래스를 만들어 넣은 후 xaml에서 바로 인스턴스 시켜서 Map 컨트롤에 넣으면 끝이다.

2. MainPage.xaml

    <!--Bing Maps Control에 Google 지도를..-->
    <Microsoft_Phone_Controls_Maps:Map Name="googlemap"
                                       CopyrightVisibility="Collapsed"
                                       LogoVisibility="Collapsed"
                                       ScaleVisibility="Visible"
                                       CredentialsProvider="ApBXPZf5IR94SLXE8nh5FYsb5WHKrH1XPY7428-EqQudseivcWhCROIJvGmtnkAV" Grid.Row="2" Grid.ColumnSpan="3">
        <Microsoft_Phone_Controls_Maps:Map.Mode>
            <MSPCMCore:MercatorMode/>
        </Microsoft_Phone_Controls_Maps:Map.Mode>
        <!--구글 지도 클래스를 인스턴스 시켜서 타일 소스에 넣는다.-->
        <Microsoft_Phone_Controls_Maps:MapTileLayer Name="street" Margin="0,0,0,32">
            <Microsoft_Phone_Controls_Maps:MapTileLayer.TileSources>
                <GoogleTileSource:GoogleTile TileTypes="Street"/>
            </Microsoft_Phone_Controls_Maps:MapTileLayer.TileSources>
        </Microsoft_Phone_Controls_Maps:MapTileLayer>
    </Microsoft_Phone_Controls_Maps:Map>

구글 지도에 관한 원본 소스
Google Maps for Windows Phone 7 using Bing Map Control
http://www.codeproject.com/Articles/153467/Google-Maps-for-Windows-Phone-7-using-Bing-Map-Con
를 참조하기 바란다.


3. Reactive Extension(Rx)
지금까지의 프로그램들은 만들어 놓은 함수를 프로세스에 맞추어서 호출해서 사용을 하는 pull 방식의 프로그램이고, Rx는 특정 조건을 만족하는 경우 자동으로 실행을 해서 결과를 만들어서 밀어 보내주는 push 방식의 프로그램을 개발할때 사용된다. 그럼, Rx를 사용하면 어떤 점이 좋은가? 멀티 스레드로 프로그램을 만들어서 더 빠른 실행 속도를 가지게 된다.

여기서 사용된 Rx의 원본 소스
Where am I?
http://compiledexperience.com/windows-phone-7/tutorials/where-am-i


4. 프로젝트에서 사용한 Rx 설명

1) GPS 센서를 이용한 위치 표시를 할 때
    //위치 정보 조회용
    private readonly GeoCoordinateWatcher geoCoordinateWatcher = new GeoCoordinateWatcher();
    ...
    //좌표를 감시하는 변수 - 스테틱
    var observable = CreateObservableGeoPositionWatcher();
    //그 변수의 감시 결과를 구독 - 스테틱
    observable
        .ObserveOn(Scheduler.ThreadPool)
        .ObserveOn(Scheduler.Dispatcher)
        .Subscribe(geo =>
        {
            Latitude.Text = geo.Latitude.ToString();
            Longitude.Text = geo.Longitude.ToString();

            googlemap.Center = geo;
            geoCoordinateWatcher.Stop(); //위치정보 수신 그만~ 계속 받기 위해서는 여기를 막고 아래 변경 사항 적용 소스에는 없으니 추가해서 넣으세요
        });
     ...
    //위치정보 좌표 반환 변수 생성
    private IObservable<GeoCoordinate> CreateObservableGeoPositionWatcher()
    {
        //geoCoordinateWatcher 녀석의 PositionChanged 를 감시 한다.
        var observable = Observable.FromEvent<GeoPositionChangedEventArgs<GeoCoordinate>>(
            e => geoCoordinateWatcher.PositionChanged += e,
            e => geoCoordinateWatcher.PositionChanged -= e)
            .Select(e => e.EventArgs.Position.Location);

        return observable;
    }

    //위치 정보 조회 시작
    //geoCoordinateWatcher.MovementThreshold = 20; //위치정보 수신을 20미터 이동시에 위치정보 변경 이벤트 발생..이것 않하면 1초에 한번씩..;;; 소스에는 없으니 추가해서 넣으세요
   geoCoordinateWatcher.Start();

2) Pin 추가/삭제 작업 시
    //랜덤
    private readonly Random random = new Random();
    //핀 추가 레이어
    MapLayer layer = new MapLayer();
    //핀id
    int pinCount;
    //핀 좌표 컬렉션
    private ObservableCollection<GeoCoordinate> geoCollection = new ObservableCollection<GeoCoordinate>();
    //구독취소 테스트용
    IDisposable one;
    ...
    //핀 좌표 컬렉션 감시 - 스테틱
    Observable
        .FromEvent<NotifyCollectionChangedEventArgs>(geoCollection, "CollectionChanged")
        .ObserveOn(Scheduler.ThreadPool)
        .ObserveOn(Scheduler.Dispatcher)
        .Subscribe(evt =>
        {
            //핀 좌표 변경 시 처리
            switch (evt.EventArgs.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    pinCount++;
                    var location = evt.EventArgs.NewItems[0] as GeoCoordinate;
                    //핀생성
                    Pushpin pin = new Pushpin
                    {
                        Location = location,
                        Content = pinCount.ToString(),
                        Background = location.Speed == 1 ? new SolidColorBrush(Colors.Blue) : new SolidColorBrush(Colors.Red)
                    };
                   
                    layer.Children.Add(pin);
                    break;
                case NotifyCollectionChangedAction.Remove:
                    //핀제거
                    GeoCoordinate ungeo = evt.EventArgs.OldItems[0] as GeoCoordinate;
                    Pushpin unpin = layer
                                    .Children.Cast<Pushpin>()
                                    .SingleOrDefault(
                                        p => p.Location.Latitude == ungeo.Latitude
                                            && p.Location.Longitude == ungeo.Longitude);
                    if (unpin != null)
                    {
                        layer.Children.Remove(unpin);
                    }
                    break;
                case NotifyCollectionChangedAction.Reset:
                    layer.Children.Clear();
                    break;
            }
        });
    //핀 레이어 구글 맵에 추가
    googlemap.Children.Add(layer);
    ...
    //Pin, 1, 2 버튼
    private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
    {
        Button ctn = sender as Button;
 
        switch (ctn.Content.ToString())
        {
            case "Pin":
                //현재 위치 Pin만들기
                var pin = new GeoCoordinate { Latitude = Convert.ToDouble(Latitude.Text),
                                              Longitude = Convert.ToDouble(Longitude.Text) };
                geoCollection.Add(pin);
                break;
            case "1":
                //1초에 한번씩 발생 - 현재 스레드
                var tik = Observable
                            .Interval(new TimeSpan(0, 0, 1));
 
                //구독 증명;;
                one = tik.Subscribe(time =>
                        {
                            var latitude = ((random.NextDouble() * 0.26114931) - 0.0) + 37.4;
                            var longitude = ((random.NextDouble() * 0.30761719) - 0.0) + 126.8;
                            var pin2 = new GeoCoordinate
                            {
                                Latitude = Convert.ToDouble(latitude),
                                Longitude = Convert.ToDouble(longitude),
                                Speed = 1
                            };
                            geoCollection.Add(pin2);
                        });
 
                //3초에 한번씩 발생 - 스레드 독립 - 여긴 평생 구독;;
                Observable
                    .Interval(new TimeSpan(0, 0, 3))
                    .ObserveOn(Scheduler.ThreadPool)
                    .ObserveOn(Scheduler.Dispatcher)
                    .Subscribe(time =>
                    {
                        var latitude = ((random.NextDouble() * 0.26114931) - 0.0) + 37.4;
                        var longitude = ((random.NextDouble() * 0.30761719) - 0.0) + 126.8;
                        var pin2 = new GeoCoordinate
                        {
                            Latitude = Convert.ToDouble(latitude),
                            Longitude = Convert.ToDouble(longitude),
                            Speed = 2
                        };
                        geoCollection.Add(pin2);
                    });
 
                //위를 막고 여기를 풀어서 100개를 한번에 추가하는 것도 가능
                //for (int i = 0; i < 100; i++)
                //{
                //    var latitude = ((random.NextDouble() * 0.26114931) - 0.0) + 37.4;
                //    var longitude = ((random.NextDouble() * 0.30761719) - 0.0) + 126.8;
                //    var pin2 = new GeoCoordinate
                //    {
                //        Latitude = Convert.ToDouble(latitude),
                //        Longitude = Convert.ToDouble(longitude)
                //    };
                //    geoCollection.Add(pin2);
                //}
                break;
            case "2":
                //구독취소
                if(one != null)
                    one.Dispose();
 
                //위를 막고 여기를 풀어서 100개를 한번에 지우는 것도 가능
                //for (int i = 0; i < 100; i++)
                //{
                //    geoCollection.Remove(geoCollection.FirstOrDefault());
                //}
                break;
        }
    }


5. Rx를 공부하면 Windows Phone 7 프로그램 개발 할 때 좋은 성능을 낼 수 있다. 구글에서 Reactive Extension로 검색하면 만은 자료를 찾을 수 있으니 검색을 해보기를 권한다.

googlemaps.zip
다운로드


 

반응형
댓글