상위 목록: 하위 목록: 작성 날짜: 읽는 데 25 분 소요

사용자 정의 다각형(Custom Polygon)

기존 GMap.Net의 다각형 클래스는 구멍이 있는 다각형을 지원하지 않습니다.

그러므로, 다각형(GMapPolygon) 클래스를 재정의하여 구멍이 있는 다각형을 구현할 수 있습니다.

다각형을 재정의한다면 기존 다각형에서 지원되지 않는 기능을 덧붙여 새로운 다각형을 생성할 수 있습니다.



클래스 코드

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using GMap.NET;
using GMap.NET.MapProviders;
using GMap.NET.WindowsForms;

namespace Project
{
    class Map
    {
        public GMapControl App;
        public GMapOverlay PolygonOverlay = new GMapOverlay("polygons");

        public Map(GMapControl app)
        {
            // App Connection
            this.App = app;
            this.App.MapProvider = GMapProviders.GoogleMap;
            this.App.Overlays.Add(PolygonOverlay);

            // Default Zoom Level
            this.App.Zoom = 16;
            this.App.MaxZoom = 25;
            this.App.MinZoom = 5;

            // Default Position
            this.App.Position = new PointLatLng(37.497872, 127.0275142);

            // Outer & Inner Position
            List<PointLatLng> outer = new List<PointLatLng>
            {
                new PointLatLng(37.5012147086396, 127.02392578125),
                new PointLatLng(37.4951541896508, 127.02321767807),
                new PointLatLng(37.4952563373043, 127.03165054321),
                new PointLatLng(37.5014189872271, 127.03104972839)
            };

            List<PointLatLng> inner = new List<PointLatLng>
            {
                new PointLatLng(37.4993931998586, 127.025470733643),
                new PointLatLng(37.4966182926675, 127.025406360626),
                new PointLatLng(37.4968055595875, 127.030062675476),
                new PointLatLng(37.4998528371071, 127.029933929443)
            };

            GMapPolygonWithHole gMapPolygonWithHole = new GMapPolygonWithHole(outer, inner, "hole");
            gMapPolygonWithHole.Fill = new SolidBrush(Color.FromArgb(50, Color.Black));
            gMapPolygonWithHole.Stroke = new Pen(Color.Red, 2);
            PolygonOverlay.Polygons.Add(gMapPolygonWithHole);
        }

        public class GMapPolygonWithHole : GMapPolygon
        {
            List<PointLatLng> Outer;
            List<PointLatLng> Inner;


            public GMapPolygonWithHole(List<PointLatLng> outer, List<PointLatLng> inner, string name) : base(outer, name)
            {
                Outer = outer;
                Inner = inner;
            }

            public override void OnRender(Graphics g)
            {
                using (GraphicsPath OuterPath = new GraphicsPath())
                using (GraphicsPath InnerPath = new GraphicsPath())
                {
                    PointF[] outer = new PointF[Outer.Count];
                    PointF[] inner = new PointF[Inner.Count];

                    GPoint point = Overlay.Control.FromLatLngToLocal(Outer[0]);
                    GPoint offset = new GPoint(point.X - LocalPoints[0].X, point.Y - LocalPoints[0].Y);

                    for (int i = 0; i < Outer.Count; i++)
                    {
                        GPoint pt = Overlay.Control.FromLatLngToLocal(Outer[i]);
                        outer[i] = new PointF(pt.X - offset.X, pt.Y - offset.Y);
                    }

                    for (int i = 0; i < Inner.Count; i++)
                    {
                        GPoint pt = Overlay.Control.FromLatLngToLocal(Inner[i]);
                        inner[i] = new PointF(pt.X - offset.X, pt.Y - offset.Y);
                    }

                    OuterPath.AddPolygon(outer);
                    InnerPath.AddPolygon(inner);

                    using (Region region = new Region(OuterPath))
                    {
                        region.Exclude(InnerPath);
                        g.FillRegion(Fill, region);

                        g.DrawPolygon(Stroke, inner);
                        g.DrawPolygon(Stroke, outer);
                    }
                }
            }
        }
    }
}


세부 코드

GMapPolygonWithHole

public class GMapPolygonWithHole : GMapPolygon
{
    ...
}

사용자 정의 다각형을 생성하기 위해 GMapPolygon 클래스를 상속받아 GMapPolygonWithHole로 재정의합니다.

GMapPolygonWithHole 클래스는 구멍이 있는 다각형을 그립니다.


public class GMapPolygonWithHole : GMapPolygon
{
    List<PointLatLng> Outer;
    List<PointLatLng> Inner;

    ...
}

GMapPolygonWithHole 클래스에 사용될 외곽(Outer), 내곽(Inner)을 선언합니다.

외곽(Outer)은 다각형의 외부를 의미합니다.

내곽(Inner)은 다각형의 구멍을 의미합니다.


public GMapPolygonWithHole(List<PointLatLng> outer, List<PointLatLng> inner, string name) : base(outer, name)
{
    Outer = outer;
    Inner = inner;
}

GMapPolygonWithHole는 입력값으로 외곽(outer), 내곽(inner), 다각형 이름(name)을 사용합니다.

base 키워드를 통해 부모 클래스의 가르킵니다.


OnRender

public override void OnRender(Graphics g)
{
    ...
}

OnRender 메서드를 오버라이드(Override)하여 재정의합니다.

OnRender 메서드는 렌더링될 때 실행되는 메서드입니다.

즉, 렌더링 메서드를 재정의하여 기존에 그려지는 방식과 다른 방식으로 그립니다.


public override void OnRender(Graphics g)
{
    using (GraphicsPath OuterPath = new GraphicsPath())
    using (GraphicsPath InnerPath = new GraphicsPath())
    {
        PointF[] outer = new PointF[Outer.Count];
        PointF[] inner = new PointF[Inner.Count];
    }
}

구멍이 있는 다각형을 그릴 예정이므로 외곽내곽의 경로를 입력할 그래픽스 경로(GraphicsPath)를 생성합니다.

리소스를 자동으로 해제하기 위해 using 키워드를 활용하여 묶어줍니다.

그래픽스 경로(GraphicsPath)PointF[] 형식의 변수를 입력값으로 받으므로, outerinner를 초기화합니다.


PointF[] outer = new PointF[Outer.Count];
PointF[] inner = new PointF[Inner.Count];

GPoint point = Overlay.Control.FromLatLngToLocal(Outer[0]);
GPoint offset = new GPoint(point.X - LocalPoints[0].X, point.Y - LocalPoints[0].Y);

다각형 그리기의 위치를 보정하기 위해 오프셋(offset)을 계산합니다.

LocalPoints 필드는 GMapPolygon 클래스의 GPoint 좌표가 저장되어 있습니다.

해당 좌표는 Outer 좌표와 매핑되지만, 동일한 위치에 그려지지 않습니다.

그러므로, Outer의 첫 번째 좌표와 LocalPoints의 첫 번째 좌표의 차이를 계산하여 모든 좌표의 오프셋으로 적용합니다.

Overlay 속성의 Control 속성에서 위도/경도를 지역 좌표로 변경할 수 있습니다.


for (int i = 0; i < Outer.Count; i++)
{
    GPoint pt = Overlay.Control.FromLatLngToLocal(Outer[i]);
    outer[i] = new PointF(pt.X - offset.X, pt.Y - offset.Y);
}

for (int i = 0; i < Inner.Count; i++)
{
    GPoint pt = Overlay.Control.FromLatLngToLocal(Inner[i]);
    inner[i] = new PointF(pt.X - offset.X, pt.Y - offset.Y);
}

OuterPath.AddPolygon(outer);
InnerPath.AddPolygon(inner);

FromLatLngToLocal 메서드를 활용하여 좌표로 변환하고, 오프셋 만큼 감산을 진행합ㄴ디ㅏ.

외곽과 내곽에 대해 동일하게 처리하고, 각각의 그래픽스 경로(GraphicsPath)에 추가합니다.


using (Region region = new Region(OuterPath))
{
    region.Exclude(InnerPath);
    g.FillRegion(Fill, region);

    g.DrawPolygon(Stroke, inner);
    g.DrawPolygon(Stroke, outer);
}

내부에 구멍이 있는 다각형을 그릴 예정이므로, Region 클래스를 활용합니다.

Exclude 메서드를 통해 다각형에서 특정 다각형을 제외할 수 있습니다.

제외된 클래스를 그래픽스에 그립니다.

내부 색상은 GMapPolygon 클래스의 Fill 속성을 그대로 사용합니다.

DrawPolygon 메서드를 통해 다각형의 외곽 및 내곽 라인을 그립니다.

선의 색상은 GMapPolygon 클래스의 Stroke 속성을 그대로 사용합니다.


Map

// Outer & Inner Position
List<PointLatLng> outer = new List<PointLatLng>
{
    new PointLatLng(37.5012147086396, 127.02392578125),
    new PointLatLng(37.4951541896508, 127.02321767807),
    new PointLatLng(37.4952563373043, 127.03165054321),
    new PointLatLng(37.5014189872271, 127.03104972839)
};

List<PointLatLng> inner = new List<PointLatLng>
{
    new PointLatLng(37.4993931998586, 127.025470733643),
    new PointLatLng(37.4966182926675, 127.025406360626),
    new PointLatLng(37.4968055595875, 127.030062675476),
    new PointLatLng(37.4998528371071, 127.029933929443)
};

GMapPolygonWithHole gMapPolygonWithHole = new GMapPolygonWithHole(outer, inner, "hole");
gMapPolygonWithHole.Fill = new SolidBrush(Color.FromArgb(50, Color.Black));
gMapPolygonWithHole.Stroke = new Pen(Color.Red, 2);
PolygonOverlay.Polygons.Add(gMapPolygonWithHole);

기존 다각형의 추가 방식과 동일한 방식으로 등록합니다.

단, 내곽을 새로 정의하여 추가합니다.



출력 결과

댓글 남기기