Latest Entries »

Bézier Curves in Bing Silvelight Maps

Bézier Curves in Bing Silverlight Maps

Connecting geographical locations on Bing Maps with Bézier curves.

Download sample: MapBezier Silverlight Application

Introduction

Bing Maps Silverlight Control library has a MapPolyline class for showing connected points on the map. I wanted my points to be smoothly connected but there wasn’t out-of-the-box support so I developed a custom control deriving from MapShapeBase class.

Bézier Curve on map.

Background

Every developer who messed with Expression Blend or Gimp long enough knows by experimentation how a Bézier curve behaves. Basically a cubic Bézier curve has an initial point (P1), two control points (B1, B2) and a final point (P2).

Bézier Curve

Cubic Bézier Curve

The formula that defines a cubic Bézier curve is:

Cubic Bézier Curve

where t is in the interval [0,1].

Terms multiplying P1, B1, B2, P2 are called the basis functions for the cubic Bézier. Our points determine how much of these basis functions does the curve contains.

Basis Functions for Cubic Bézier Curve

Cubic Bézier Basis Functions

The thing is we need to calculate coordinates of the control points such that our points of interest are on the curve.

Polyline, Bézier, Catmull-Rom

Polyline, Bézier, Catmull-Rom

So how can we calculate these control points? After researching(read googling) I have landed on cardinal splines and Catmull-Rom splines. It appears that every control point of a Catmull-Rom spline is on the curve and it is also a Bézier curve which means we can use it as PathGeometry with a Silverlight Path object.

Calculating Control Points

If we rewrite formulas from the cardinal splines page as the following, we can easily calculate control points.

Point Derivative

Control Points:

Control Points

Fitted Bézier with Control Points Visible.

Fitted Bézier with Control Points Visible

Using the code

The method that calculates the Bézier Points is as the following. GetB1 and GetB2 are straight forward implementations of the aforementioned formulas.

private PointCollection GetBezierPoints(PointCollection pts, double tension)
{
PointCollection ret = new PointCollection();

for (int i = 0; i < pts.Count; i++)
{
// for first point append as is.
if (i == 0)
{
ret.Add(pts[0]);
continue;
}

// for each point except first and last get B1, B2. next point.
// Last point do not have a next point.
ret.Add(GetB1(pts, i - 1, tension));
ret.Add(GetB2(pts, i - 1, tension));
ret.Add(pts[i]);
}

return ret;
}

To use the PointCollection returned from GetBezierPoints method in Silverlight, we need to build a Path with BezierSegments in it.

private PathFigure GetBezierSegments(PointCollection pts, double tension)
{
PathFigure ret = new PathFigure();
ret.Segments.Clear();
ret.IsClosed = false;

var bzPoints = GetBezierPoints(_projectedPoints, tension);

// First point is the starting point.
ret.StartPoint = bzPoints[0];

for (int i = 1; i < bzPoints.Count; i += 3)
{
ret.Segments.Add(new BezierSegment()
{
Point1 = bzPoints[i],       // B1 control point.
Point2 = bzPoints[i + 1],   // B2 control point.
Point3 = bzPoints[i + 2]    // P2 start / end point.
});
}

return ret;
}

And use this PathFigure in the MapBezier as:

// Create a new PathGeometry.
var pGeo = new PathGeometry();

// Add the Bezier PathFigure to the PathGeometry.
pGeo.Figures.Add(GetBezierSegments(_projectedPoints, Tension));

// Set data of the Path to the created PathGeometry.
((Path)EncapsulatedShape).Data = pGeo;

You can use the MapBezier class just like MapPolyline and MapPolygon classes in your silverlight XAML file. See the attached sample for an example silverlight application.

<m:Map x:Name="myMap" CredentialsProvider="***">
<m:MapLayer x:Name="layerDurak" >
<local:MapBezier Tension="2" x:Name="plDurakGidis" Stroke="Orange" StrokeThickness="3" Opacity=".6" Locations="{Binding MyLocations, Mode=OneWay}" />
</m:MapLayer>
</m:Map>

Note: Bing Maps Silverlight SDK is needed for compiling the sample application.

Points of Interest

It was fun messing with the Bing Maps Silverlight Control toolkit and I hope MapBezier is what you are looking for.

If you liked this, vote the article at http://www.codeproject.com/KB/silverlight/MapBezier.aspx

Koordinat Dönüşüm Fonksiyonları

Ne?

İlgilendiğimiz koordinat sistemleri, dünya yüzeyindeki herhangi bir noktayı karışıklığa mahal vermeden tarif etmeye yarar. Koordinat sistemi denildiğinde akla gelen ilk sistem x-y koordinatları olarak da hatırlanan bir 2 boyutlu dik koordinat sistemi olan kartezyen koordinat sistemidir.

Peki bahsettiğimiz gibi eğer bir koordinat sistemi karışıklığa mahal vermeden bir noktayı tarif edebiliyorsa farklı koordinat sistemlerine ne gerek var sorusu akla gelebilir, gelmelidir. Farklı koordinat sistemlerine olan ihtiyaç tamamen kullanım yeri ve kullanım kolaylığı ile ilgilidir.

Nedir?

İlgilendiğimiz koordinat sistemlerinden bahsetmeden önce harita yapımının bir aşaması olan izdüşüm (projection) almaktan bahsetmekte fayda var.

İzdüşüm Nedir?

En basit haliyle izdüşüm, bir noktanın bir yüzey üzerine düşen izidir. Biraz detaylandırırsak belli bir merkezden gelip bir noktadan veya bir noktalar kümesinin her bir noktasından geçen doğruların izdüşüm tarafından tanımlanmış olan yüzeyi kestiği noktaların geometrik yeridir diyebiliriz.

Bu biraz karışık olduysa merkezde bir ışık kaynağı olduğunu ve izdüşüm yüzeyinin bizim istediğimiz şekilde bir perde olduğunu düşünün. İzdüşümünü almak istediğimiz noktaları ışık kaynağı ile perde arasına koyarsak, perde üzerinde izdüşümünü elde ederiz.

Bizim ilgilendiğimiz izdüşümü, dünyanın (noktalar) üzerinde geçirilmiş bir silindire (perde), dünyanın merkezinden (ışık kaynağı) olan izdüşümüdür.

Mercator İzdüşümü

Türkiye’de de tapu, ruhsat, askeri ve benzeri alanlarda en çok kullanılan koordinat sistemi UTM şeklinde kısaltılan Universal Transverse Mercator (Evrensel “Uzun eksene dik” Mercator) sistemidir.

Transverse Mercator

Transverse Mercator

KorTransLib

Koordinat Dönüşüm Kütüphanesinin yazılış amacı ileride düşünülen projelerde kullanılmak üzere olduğundan sadece 6 derece dilimli UTM, enlem-boylam ve derece-dakika-saniye olmak üzere üç adet koordinat sınıfı olmakla beraber istenilen koordinat sistemleri kolaylıkla eklenebilecek şekilde tasarlanmıştır.

Coordinate Sınıfı ve Türetilmiş Sınıfları

Coordinate Sınıfı ve Türetilmiş Sınıfları

Koordinat Sınıfları

  • DecimalDegreeCoordinate
  • DegreeMinuteSecondCoordinate
  • UTMCoordinate

DecimalDegreeCoordinate

Ondalık dereceli gösterim. Matematiksel hesap yaparken kolaylıkla kullanılır.

DegreeMinuteSecondCoordinate

Derece, dakika, saniye sisteminde gösterim.

UTMCoordinate

6 derecelik dilimli Universal Transverse Sekant Mercator izdüşüm sistemindeki koordinatlar. UTM koordinat sisteminde sağa ve yukarı değerden başka dilim bölgesi (UTM Zone) değeri de vardır. Bu değer sağa ve yukarı değerlerinin anlamını tanımlar. Türkiye’nin UTM dilimleri aşağıda gösterilmiştir.

Türkiye UTM Dilimleri

Türkiye UTM Dilimleri

Koordinatlar Sınıfları Arasında Matematiksel İşlemler

Örnek olarak herhangi iki koordinatın orta noktasının bulunmasını aşağıdaki şekilde yapabilmemiz için kullanılan TypeConverter sınıfı, kodun yazılmasında da kullanılmasında da büyük kolaylık sağlamıştır.

DecimalDegreeCoordinate dd = new DecimalDegreeCoordinate(38.4, 28.1);
UTMCoordinate utm = new UTMCoordinate(&amp;quot;35T&amp;quot;, 663890, 4568130);

DegreeMinuteSecondCoordinate dmsSonuc = new DegreeMinuteSecondCoordinate();

TypeConverter corcon = TypeDescriptor.GetConverter(typeof(DegreeMinuteSecondCoordinate));
dmsSonuc = (DegreeMinuteSecondCoordinate)corcon.ConvertFrom((dd + utm) / 2);

Yukarıda gösterildiği gibi koordinat dönüşüm işlemi sadece bir değişkene atama yapılmadan önce yapılıyor.

İki koordinatın ortalaması, karşılıklı iki köşe koordinatı bilinen bir paftanın merkezini bulurken kullanılabilir.

TypeConverter Kullanımı

  1. System.ComponentModel içerisindeki TypeConverter sınıfı miras alınarak CanConvertFrom, ConvertFrom, CanConvertTo, ConvertTo fonksiyonları yazılır.
  2. Yaratılan TypeConverter mirasçısı sınıfının hangi tipi dönüştürdüğü Nitelik (Attribute) sınıfları kullanılarak tanımlanır.
  3. TypeDescriptor sınıfı yardımı ile kullanılır.

Örnek:

public static Coordinate operator +(Coordinate c1, Coordinate c2)
{
    DecimalDegreeCoordinate dd1 = (DecimalDegreeCoordinate)TypeDescriptor.GetConverter(c1).ConvertTo(c1, typeof(DecimalDegreeCoordinate));
    DecimalDegreeCoordinate dd2 = (DecimalDegreeCoordinate)TypeDescriptor.GetConverter(c2).ConvertTo(c2, typeof(DecimalDegreeCoordinate));
    return new DecimalDegreeCoordinate(dd1.lat + dd2.lat, dd1.lon + dd2.lon);
}

Project Euler Problem 53

Project Euler 53. Problem ve Çözümü

53. Problem’de 1 <= n <= 100 ve C(n,r) > 1000000 koşullarını sağlayan kaç adet C(n,r) şeklinde kombinasyon olduğunu bulmamız isteniyor.

Bu problemin çözümü için akla gelen pek çok yol içerisinden hızlı ve basit olan bir yol ile problemi çözmeye çalışalım. Problemimizde kombinasyonu hesaplayarak 1000000′dan büyük olup olmadığını sınamak yerine kombinasyonun ve kontrol değerinin logaritmasını alarak logaritmaları karşılatırıyoruz.  Öncelikle bazı kombinasyon formüllerini hatırlayalım:

Faktoriyel ve kombinasyonun formülü.

ve bazı logaritma formüllerini:

Çarpımın logaritması.

Bölümün logaritması.

Yukarıdaki formülleri kullanarak faktoriyelin logaritmasını aşağıdaki gibi yazabiliriz:

Faktoriyelin logaritması.

Bu fonksiyon project euler ile doğrudan ilgili olmasa da gammaln fonksiyonunun analogudur.

Böylece kombinasyonun logaritmasını da aşağıdaki şekilde yazabiliriz:

Kombinasyonun logaritması.

Buraya kadar yazdıklarımızdan çıkarmak istediğimiz sonuç olan problem 53‘ün logaritmalar ile ifadesini aşağıda görebiliriz:

Logarithm of a million

Logarithm representation of Problem 53

Böylece logaritmanın da yardımı ile kendimizi big-integer çarpım, bölüm ve karşılaştırmalarından kurtararak işimizi double toplamlara ve karşılaştırmalara indirgemiş olduk. Aynı zamanda faktoriyelin logaritma fonksiyonunu tasarlarken memoization tekniğini de kullanabiliriz. Problemi çözen örnek C# kodu aşağıda verilmiştir:

using System;
using System.Collections.Generic;
using System.Text;

namespace ProjectEuler53
{
    class Program
    {
        static void Main(string[] args)
        {
            // count will be the answer of the problem.
            int count = 0;

            for (int n = 1; n &lt;= 100; n++) // upper limit imposed by the problem on 'n' is 100
                for (int r = 1; r &lt;= n; r++) // n &gt; r
                {
                    if (LogCombination(n, r) &gt; 6) // log(1000000) = log(10^6) = 6 log10 = 6
                        count++;
                }

            Console.WriteLine(count);
            Console.ReadKey(true);
        }

        // Memoization dictionary for logarithm of factorials.
        static Dictionary&lt;int, double&gt; dictLogFactorial = new Dictionary&lt;int, double&gt;();

        // Returns logarithm of the combination C(n,r)
        static double LogCombination(int n, int r)
        {
            return LogFactorial(n) - LogFactorial(r) - LogFactorial(n - r);
        }

        /// Returns logarithm of n!, if called before value comes from a dictionary.
        static double LogFactorial(int n)
        {
            if (n == 0 || n == 1)
                return 1;

            if (dictLogFactorial.ContainsKey(n))
                return dictLogFactorial[n];

            double ret = 0;
            for (int i = 1; i &lt;= n; i++)
            {
                ret += Math.Log10(i);
            }
            dictLogFactorial.Add(n, ret);
            return ret;
        }

    }
}

Powered by WordPress. Theme: Motion by 85ideas.