2013-08-20 87 views
6

Sulla mia applicazione ho bisogno di disegnare su TCanvas un "marker", come il marker di Google Maps (vedi l'immagine).Disegna un marker come google maps con TCanvas su Delphi

google marker

mi piacerebbe utilizzare come parametri il raggio, l'altezza e l'origine:

marker parameters

Non ho idea di algoritmo da utilizzare. Posso usare un arco per disegnare la parte superiore, ma come posso disegnare il fondo? Nota: ho bisogno di disegnarlo sia con GDI che con GDI +, quindi qualsiasi soluzione è benvenuta.

+2

Non voglio essere scortese, ma non credo che questo ha a che fare con Delphi o GDI in particolare. È più come cercare un algoritmo che richiede tre parametri e restituisce qualcosa come sopra. –

+0

@ GünthertheBeautiful è possibile ma ho bisogno di farlo con Delphi usando GDI e GDI + – Martin

+1

Il punto è che una volta che hai la descrizione matematica, puoi disegnarla in qualsiasi lingua tu voglia. Non è categoricamente una domanda delphi. FWIW Scommetto che Google usa le immagini raster. –

risposta

10

Ecco un esempio rapido utilizzando un 200x200 PaintBox - dovrebbe almeno darti un'idea dell'algoritmo. Spero che tu possa disegnare il punto nero nel mezzo. Leggi su Bezier Curves; PolyBezier definisce cubic Bezier curves. (link)

bezier

Quattro punti definiscono una curva di Bezier cubica - inizio, fine, e due punti di controllo. I punti di controllo definiscono l'intensità della curvatura mentre la linea si sposta dall'inizio alla fine.

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; 

per soddisfare il punto che si può fare questo con un Bezier:

// 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

Non è necessario il riempimento 'FloodFill' ex-post. Inoltre, puoi descrivere l'intera forma del marker mediante le curve di bezier (e disegnarlo con una singola chiamata 'PolyBezier'). – TLama

+2

@TLama - sì, puoi farlo con un bezier. L'ho fatto rapidamente e non volevo definire altri quattro punti di controllo: doveva essere didattico, non completo di produzione. Arc era più veloce da codificare, non necessariamente meglio. Ovviamente una soluzione GDI utilizza i percorsi (che definiscono Beziers allo stesso modo) e con i percorsi il riempimento del post non è necessario, naturalmente. Ancora una volta, è stato un bezier how-to, non cercando di fare il lavoro di OP per lui. –

+1

Sì, è meglio :-) E hai ragione. Con GDI + puoi creare un percorso e riempire il percorso. È più facile lì. [+1] – TLama