2013-08-20 13 views
6

Auf meiner Anwendung muss ich auf TCanvas einen "Marker", wie Google Maps Marker (siehe das Bild).Zeichnen Sie einen Marker wie Google Maps mit TCanvas auf Delphi

google marker

ich Gebrauch möchte den Radius-Parameter, die Höhe und die Herkunft:

marker parameters

Ich habe keine Ahnung von Algorithmus zu verwenden. Ich kann einen Bogen verwenden, um die Spitze zu zeichnen, aber wie kann ich den Boden zeichnen? Hinweis: Ich muss es beide mit GDI und GDI + zeichnen, so dass jede Lösung willkommen ist.

+2

Ich will nicht unhöflich sein, aber ich glaube nicht, das irgendetwas mit Delphi oder GDI zu tun bestimmtes. Es ist eher so, als würde man nach einem Algorithmus suchen, der drei Parameter benötigt und so etwas ausgibt. –

+0

@ GünthertheBeautiful es ist möglich, aber ich muss es tun mit Delphi mit GDI und GDI + – Martin

+1

Der Punkt ist, dass sobald Sie die mathematische Beschreibung haben, können Sie es in welcher Sprache Sie Lust haben. Es ist kategorisch keine Delphi-Frage. FWIW Ich wette, dass Google Rasterbilder verwendet. –

Antwort

10

Hier ist ein schnelles Beispiel mit einem 200x200 PaintBox - es sollte Ihnen zumindest eine Idee für den Algorithmus geben. Ich vertraue darauf, dass du den schwarzen Punkt in der Mitte zeichnen kannst. Lesen Sie weiter unter Bezier Curves; PolyBezier definiert cubic Bezier curves. (link)

bezier

Vier Punkte eine kubische Bezier-Kurve definieren, - Start, Ende und zwei Kontrollpunkte. Kontrollpunkte definieren die Stärke der Krümmung, wenn sich die Linie von Anfang bis Ende bewegt.

var origin, innerL, midL, midR, lft, tp, rgt, innerR : TPoint; 
    radius, hgt : integer; 
begin  
    radius := 25; 
    hgt := 90;  
    origin.X := 100; 
    origin.Y := 180; 
    //control points 
    innerL.X := origin.X; 
    innerL.Y := origin.Y - (hgt - radius) div 3; 
    midL.X := origin.X - radius; 
    midL.Y := origin.Y - 2*((hgt - radius) div 3); 
    //top circle 
    lft.X := origin.X - radius; 
    lft.Y := origin.Y - (hgt - radius); 
    tp.X := origin.X; 
    tp.Y := origin.Y - hgt; 
    rgt.X := origin.X + radius; 
    rgt.Y := lft.Y; 
    //control points 
    midR.X := origin.X + radius; 
    midR.Y := midL.Y; 
    innerR.X := origin.X; 
    innerR.Y := innerL.Y; 

    PaintBox1.Canvas.Pen.Width := 2; 
    PaintBox1.Canvas.PolyBezier([origin, innerL, midL, lft]); 
    PaintBox1.Canvas.Arc(lft.X, tp.Y, rgt.X, rgt.Y + radius, rgt.X, rgt.Y, lft.X, lft.Y); 
    PaintBox1.Canvas.PolyBezier([rgt, midR, innerR, origin]); 
    //fill 
    PaintBox1.Canvas.Brush.Color := clYellow; 
    PaintBox1.Canvas.FloodFill(origin.X, origin.Y - radius, 
          Canvas.Pen.Color, TFillStyle.fsBorder);  
end; 

den Punkt zu vergewissern, dass Sie dies mit einer Bezier tun können:

// add four more control TPoints 
    cornerL.X := lft.X; 
    cornerL.Y := tp.Y + radius div 2; 
    cL2.X := lft.X + radius div 2; 
    cL2.Y := tp.Y; 
    cR2.X := rgt.X - radius div 2; 
    cR2.Y := tp.Y; 
    cornerR.X := rgt.X; 
    cornerR.Y := cornerL.Y; 


    PaintBox1.Canvas.PolyBezier([origin, innerL, midL, lft, 
           cornerL, cL2, tp, cR2, cornerR, rgt, 
           midR, innerR, origin]); 
+4

Ex-post 'FloodFill' Füllung ist nicht nötig. Außerdem können Sie die gesamte Markerform mit Bezier-Kurven beschreiben (und sie mit einem einzelnen PolyBezier-Aufruf zeichnen). – TLama

+2

@TLama - ja, Sie können es mit einem Bezier tun. Ich habe es schnell gemacht und wollte keine vier Kontrollpunkte mehr definieren - es sollte didaktisch sein und nicht die Produktion komplett sein. Arc war schneller zu codieren, nicht unbedingt besser. Offensichtlich würde eine GDI-Lösung Pfade verwenden (die Béziers auf die gleiche Weise definieren) und bei Pfaden wird die Nachfüllung natürlich nicht benötigt. Wiederum war es ein Bézier-How-To, der nicht versuchte, OPs Job für ihn zu erledigen. –

+1

Ja, das ist besser :-) Und du hast Recht. Mit GDI + können Sie einen Pfad erstellen und den Pfad füllen. Es ist einfacher dort. [+1] – TLama