画画好看的箭头线

 
Akka-http是如出一辙件系统融为一体工具。这至关重要因系统间的数据交换功能。因为程序外数据表达形式与网上传的数码格式是勿等同的,所以要对先后高级结构化的多寡进行换(marshalling
or
serializing)成为可每当网上传的数量格式。由于可能波及到异类系统并,网上传数据格式是一个当面的正儿八经,这样大家才都得展开剖析。Json就是是一个脚下业界普遍接受的网上交换数据格式。当然,所谓的数目格式转换应该是双向的,还得包括把接受的网上传输数据易成为程序高级结构化数据。

FormShow()->FormMouseDown->FormMouseMove->FormMouseUp

Akka-http网上交换数据易代表把一个尖端结构类型T的实例转换成为简单的目标项目如MessageEntity,它代表http消息被的数据有(entity-body),最后来Json进行交换。Akka-http用Marshaller[A,B]色来进行类型A的实例到路B实例的变换。Marshaller[A,B]概念如下:

初始化            鼠标按下,起点         移动鼠标                
鼠标弹起 ,终点 

sealed abstract class Marshaller[-A, +B] {

  def apply(value: A)(implicit ec: ExecutionContext): Future[List[Marshalling[B]]]

  def map[C](f: B ⇒ C): Marshaller[A, C] =
    Marshaller(implicit ec ⇒ value ⇒ this(value).fast map (_ map (_ map f)))
...
}

//#marshaller-creation
object Marshaller
  extends GenericMarshallers
  with PredefinedToEntityMarshallers
  with PredefinedToResponseMarshallers
  with PredefinedToRequestMarshallers {

  /**
   * Creates a [[Marshaller]] from the given function.
   */
  def apply[A, B](f: ExecutionContext ⇒ A ⇒ Future[List[Marshalling[B]]]): Marshaller[A, B] =
    new Marshaller[A, B] {
      def apply(value: A)(implicit ec: ExecutionContext) =
        try f(ec)(value)
        catch { case NonFatal(e) ⇒ FastFuture.failed(e) }
    }
...
}

图片 1

构建函数apply[A,B]包嵌了单操作函数:A=>Future[List[Marshalling[B]]],至于为何未利用重复简单直接的不二法门A=>B是盖:

 网上下的事例:

1、转换的经过是异步non-blocking的,所以回来Future[??]

图片 2

2、可能产生强移目标数格式如XML,Json:所以用List[??]表达

unit   Unit1;

interface

uses
    Windows,   Messages,   SysUtils,   Variants,   Classes,   Graphics,   Controls,   Forms,
    Dialogs;

const
    Penwidth   =   1;//画笔的粗细
    Len   =   20;//箭头线的长度
    {说明:这两个常量应该一起变化,具体值由效果来定。
    当Penwidth很小时,显示的效果不是太好}

type
    TForm1   =   class(TForm)
        procedure   FormMouseUp(Sender:   TObject;   Button:   TMouseButton;
            Shift:   TShiftState;   X,   Y:   Integer);
        procedure   FormMouseDown(Sender:   TObject;   Button:   TMouseButton;
            Shift:   TShiftState;   X,   Y:   Integer);
        procedure   FormMouseMove(Sender:   TObject;   Shift:   TShiftState;   X,
            Y:   Integer);
        procedure   FormShow(Sender:   TObject);
        procedure   FormCreate(Sender:   TObject);
    private
        {   Private   declarations   }
    public
        {   Public   declarations   }
    end;

var
    Form1:   TForm1;
    xs,   ys:   integer;//画线开始处的坐标
    xt,   yt:   integer;//记录鼠标前一时刻的坐标
    xl,   yl:   integer;//记录第一条箭头线的端点坐标
    xr,   yr:   integer;//记录第二条箭头线的端点坐标
    B:   boolean;//判断是否已经开始画线

implementation

{$R   *.dfm}

procedure   TForm1.FormMouseUp(Sender:   TObject;   Button:   TMouseButton;
    Shift:   TShiftState;   X,   Y:   Integer);
begin
    {画线结尾时,将线重新填充一遍,以免有部分空白}
    if   not   ((x   =   xs)   and   (y   =   ys))   then
    begin
        Form1.Canvas.Pen.Mode   :=   pmCopy;
        Form1.Canvas.Pen.Color   :=   clRed;
        Form1.Canvas.Pen.Width   :=   PenWidth;
        Form1.Canvas.MoveTo(xs,   ys);
        Form1.Canvas.LineTo(x,   y);
        Form1.Canvas.MoveTo(x,   y);
        Form1.Canvas.LineTo(xl,   yl);
        Form1.Canvas.MoveTo(x,   y);
        Form1.Canvas.LineTo(xr,   yr);
    end;

    B   :=   False;
end;

procedure   TForm1.FormMouseDown(Sender:   TObject;   Button:   TMouseButton;
    Shift:   TShiftState;   X,   Y:   Integer);
begin
    xs   :=   x;
    ys   :=   y;
    xt   :=   x;
    yt   :=   y;
    xl   :=   -1;
    yl   :=   -1;
    xr   :=   -1;
    yr   :=   -1;
    B   :=   True;
end;

procedure   TForm1.FormMouseMove(Sender:   TObject;   Shift:   TShiftState;   X,
    Y:   Integer);
begin
    if   B   then
    begin
        Form1.Canvas.Pen.Mode   :=   pmNotXor;
        Form1.Canvas.Pen.Color   :=   clRed;
        Form1.Canvas.Pen.Width   :=   PenWidth;
        //绘旧线
        Form1.Canvas.MoveTo(xs,   ys);
        Form1.Canvas.LineTo(xt,   yt);
        //绘新线
        Form1.Canvas.MoveTo(xs,   ys);
        Form1.Canvas.LineTo(x,   y);
        if   xl   <>   -1   then
        begin
            Form1.Canvas.MoveTo(xt,   yt);
            Form1.Canvas.LineTo(xl,   yl);
            Form1.Canvas.MoveTo(xt,   yt);
            Form1.Canvas.LineTo(xr,   yr);

            Form1.Canvas.MoveTo(xl,   yl);
            Form1.Canvas.LineTo(xr,   yr);
        end;
        //记录下原坐标
        xt   :=   x;
        yt   :=   y;
        if   x   >   xs   then
        begin
            xl   :=   trunc(x   -   Len   *   Cos(ArcTan((y   -   ys)   /   (x   -   xs))   -   Pi   /   6));
            yl   :=   trunc(y   -   Len   *   Sin(ArcTan((y   -   ys)   /   (x   -   xs))   -   Pi   /   6));
            xr   :=   trunc(x   -   Len   *   Cos(ArcTan((y   -   ys)   /   (x   -   xs))   +   Pi   /   6));
            yr   :=   trunc(y   -   Len   *   Sin(ArcTan((y   -   ys)   /   (x   -   xs))   +   Pi   /   6));
        end
        else
            if   x   <   xs   then
            begin
                xl   :=   trunc(x   +   Len   *   Cos(ArcTan((y   -   ys)   /   (x   -   xs))   -   Pi   /   6));
                yl   :=   trunc(y   +   Len   *   Sin(ArcTan((y   -   ys)   /   (x   -   xs))   -   Pi   /   6));
                xr   :=   trunc(x   +   Len   *   Cos(ArcTan((y   -   ys)   /   (x   -   xs))   +   Pi   /   6));
                yr   :=   trunc(y   +   Len   *   Sin(ArcTan((y   -   ys)   /   (x   -   xs))   +   Pi   /   6));
            end
            else
                if   y   <   ys   then
                begin
                    xl   :=   trunc(x   -   Len   *   Sin(Pi   /   6));
                    yl   :=   trunc(y   +   Len   *   Cos(Pi   /   6));
                    xr   :=   trunc(x   +   Len   *   Sin(Pi   /   6));
                    yr   :=   trunc(y   +   Len   *   Cos(Pi   /   6));
                end
                else
                    if   y   >   ys   then
                    begin
                        xl   :=   trunc(x   -   Len   *   Sin(Pi   /   6));
                        yl   :=   trunc(y   -   Len   *   Cos(Pi   /   6));
                        xr   :=   trunc(x   +   Len   *   Sin(Pi   /   6));
                        yr   :=   trunc(y   -   Len   *   Cos(Pi   /   6));
                    end
                    else
                    begin
                        xl   :=   -1;
                        yl   :=   -1;
                        xr   :=   -1;
                        yr   :=   -1;
                    end;
        if   xl   <>   -1   then
        begin
            Form1.Canvas.MoveTo(x,   y);
            Form1.Canvas.LineTo(xl,   yl);
            Form1.Canvas.MoveTo(x,   y);
            Form1.Canvas.LineTo(xr,   yr);

            Form1.Canvas.MoveTo(xl,   yl);
            Form1.Canvas.LineTo(xr,   yr);
        end;
    end;
end;

procedure   TForm1.FormShow(Sender:   TObject);
begin
    Form1.Color   :=   clWhite;
    Form1.Caption   :=   '画带箭头的直线 ';
    Form1.WindowState   :=   wsMaximized;
    B   :=   False;
    xt   :=   -1;
    yt   :=   -1;
    xl   :=   -1;
    yl   :=   -1;
    xr   :=   -1;
    yr   :=   -1;
end;

procedure   TForm1.FormCreate(Sender:   TObject);
begin
//    Form1.BorderIcons   :=   [biSystemMenu];
end;

end.

3、如果用以起最终目标格式数据前能取得或者涂改数据的特性,就需以数据源与目标数据里要一个当中层结果,Marshalling[B]纵然是这么一个中级抽象层类型。通过Marshalling类型可以当数额实际上来前获得或修改数据性:

  

/**
 * Describes one possible option for marshalling a given value.
 */
sealed trait Marshalling[+A] {
  def map[B](f: A ⇒ B): Marshalling[B]

  /**
   * Converts this marshalling to an opaque marshalling, i.e. a marshalling result that
   * does not take part in content type negotiation. The given charset is used if this
   * instance is a `WithOpenCharset` marshalling.
   */
  def toOpaque(charset: HttpCharset): Marshalling[A]
}

object Marshalling {

  /**
   * A Marshalling to a specific [[akka.http.scaladsl.model.ContentType]].
   */
  final case class WithFixedContentType[A](
    contentType: ContentType,
    marshal:     () ⇒ A) extends Marshalling[A] {
    def map[B](f: A ⇒ B): WithFixedContentType[B] = copy(marshal = () ⇒ f(marshal()))
    def toOpaque(charset: HttpCharset): Marshalling[A] = Opaque(marshal)
  }

  /**
   * A Marshalling to a specific [[akka.http.scaladsl.model.MediaType]] with a flexible charset.
   */
  final case class WithOpenCharset[A](
    mediaType: MediaType.WithOpenCharset,
    marshal:   HttpCharset ⇒ A) extends Marshalling[A] {
    def map[B](f: A ⇒ B): WithOpenCharset[B] = copy(marshal = cs ⇒ f(marshal(cs)))
    def toOpaque(charset: HttpCharset): Marshalling[A] = Opaque(() ⇒ marshal(charset))
  }

  /**
   * A Marshalling to an unknown MediaType and charset.
   * Circumvents content negotiation.
   */
  final case class Opaque[A](marshal: () ⇒ A) extends Marshalling[A] {
    def map[B](f: A ⇒ B): Opaque[B] = copy(marshal = () ⇒ f(marshal()))
    def toOpaque(charset: HttpCharset): Marshalling[A] = this
  }
}

本人之代码改进版本:

俺们好在Marshalling类型里对信息内容类型(message-content-type)进行操作。为了便利操作,Akka-http提供了下就几乎单门类别名:

图片 3

type ToEntityMarshaller[T] = Marshaller[T, MessageEntity]
type ToByteStringMarshaller[T] = Marshaller[T, ByteString]
type ToHeadersAndEntityMarshaller[T] = Marshaller[T, (immutable.Seq[HttpHeader], MessageEntity)]
type ToResponseMarshaller[T] = Marshaller[T, HttpResponse]
type ToRequestMarshaller[T] = Marshaller[T, HttpRequest]
unit   Unit1;

interface

uses
    Windows,   Messages,   SysUtils,   Variants,   Classes,   Graphics,   Controls,   Forms,
    Dialogs;

const
    Penwidth   =   1;//画笔的粗细
    Len   =   15;//箭头线的长度
    {说明:这两个常量应该一起变化,具体值由效果来定。
    当Penwidth很小时,显示的效果不是太好}

type
    TForm1   =   class(TForm)
        procedure   FormMouseUp(Sender:   TObject;   Button:   TMouseButton;
            Shift:   TShiftState;   X,   Y:   Integer);
        procedure   FormMouseDown(Sender:   TObject;   Button:   TMouseButton;
            Shift:   TShiftState;   X,   Y:   Integer);
        procedure   FormMouseMove(Sender:   TObject;   Shift:   TShiftState;   X,
            Y:   Integer);
        procedure   FormShow(Sender:   TObject);
    private
        {   Private   declarations   }
    public
        {   Public   declarations   }
    end;

var
    Form1:   TForm1;
    xs,   ys:   integer;//画线开始处的坐标  start

    xl,   yl:   integer;//记录第一条箭头线的端点坐标   left       三角形左边顶点
    xr,   yr:   integer;//记录第二条箭头线的端点坐标    rift

    xt,   yt:   integer;//记录鼠标前一时刻的坐标     termoei


    B:   boolean;//判断是否已经开始画线

implementation

{$R   *.dfm}

procedure   TForm1.FormMouseUp(Sender:   TObject;   Button:   TMouseButton;
    Shift:   TShiftState;   X,   Y:   Integer);
begin
    B   :=   False;  //鼠标弹起,结束 画线
end;

procedure   TForm1.FormMouseDown(Sender:   TObject;   Button:   TMouseButton;
    Shift:   TShiftState;   X,   Y:   Integer);
begin
    xs   :=   x;
    ys   :=   y;

    xt   :=   x;     yt   :=   y;

    xl   :=   -1;      yl   :=   -1;



    xr   :=   -1;
    yr   :=   -1;
    B   :=   True; //鼠标按下 开始 画线
end;

procedure   TForm1.FormMouseMove(Sender:   TObject;   Shift:   TShiftState;   X,
    Y:   Integer);
var
    m ,n: array[0..2] of TPoint;
begin
    if   B   then
    begin
        Form1.Canvas.Pen.Mode   :=   pmNotXor;  //pmNotXor 将旧三角形用背景色 划线,即清除旧的
        Form1.Canvas.Pen.Color   :=   clRed;
        Form1.Canvas.Pen.Width   :=   PenWidth;


        if   xl   <>   -1   then       //pmNotXor 将旧三角形用背景色 划线,即
        begin

            Form1.Canvas.Brush.Color:=clRed;     //清除  三角形
            m[0]:=   Point(xt,   yt);
            m[1]:=   Point(xl,   yl);
            m[2]:=  Point(xr,   yr);
            Form1.Canvas.Polygon( m);
            //------------------------------------
            n[0]:=   Point(xs,   ys);
            n[1]:=   Point(xl,   yl);
            n[2]:=  Point(xr,   yr);
            Form1.Canvas.Polygon( n);
        end;
        //记录下原坐标
        xt   :=   x;        yt   :=   y;


        if   x   >   xs   then
        begin
            xl   :=   trunc(x   -   Len   *   Cos(ArcTan((y   -   ys)   /   (x   -   xs))   -   Pi   /   6));
            yl   :=   trunc(y   -   Len   *   Sin(ArcTan((y   -   ys)   /   (x   -   xs))   -   Pi   /   6));
            xr   :=   trunc(x   -   Len   *   Cos(ArcTan((y   -   ys)   /   (x   -   xs))   +   Pi   /   6));
            yr   :=   trunc(y   -   Len   *   Sin(ArcTan((y   -   ys)   /   (x   -   xs))   +   Pi   /   6));
        end
        else
            if   x   <   xs   then
            begin
                xl   :=   trunc(x   +   Len   *   Cos(ArcTan((y   -   ys)   /   (x   -   xs))   -   Pi   /   6));
                yl   :=   trunc(y   +   Len   *   Sin(ArcTan((y   -   ys)   /   (x   -   xs))   -   Pi   /   6));
                xr   :=   trunc(x   +   Len   *   Cos(ArcTan((y   -   ys)   /   (x   -   xs))   +   Pi   /   6));
                yr   :=   trunc(y   +   Len   *   Sin(ArcTan((y   -   ys)   /   (x   -   xs))   +   Pi   /   6));
            end
            else
                if   y   <   ys   then
                begin
                    xl   :=   trunc(x   -   Len   *   Sin(Pi   /   6));
                    yl   :=   trunc(y   +   Len   *   Cos(Pi   /   6));
                    xr   :=   trunc(x   +   Len   *   Sin(Pi   /   6));
                    yr   :=   trunc(y   +   Len   *   Cos(Pi   /   6));
                end
                else
                    if   y   >   ys   then
                    begin
                        xl   :=   trunc(x   -   Len   *   Sin(Pi   /   6));
                        yl   :=   trunc(y   -   Len   *   Cos(Pi   /   6));
                        xr   :=   trunc(x   +   Len   *   Sin(Pi   /   6));
                        yr   :=   trunc(y   -   Len   *   Cos(Pi   /   6));
                    end
                    else
                    begin
                        xl   :=   -1;
                        yl   :=   -1;
                        xr   :=   -1;
                        yr   :=   -1;
                    end;
        if   xl   <>   -1   then
        begin

            Form1.Canvas.Brush.Color:=clRed;     //填充三角形
            m[0]:=   Point(x,   y);
            m[1]:=   Point(xl,   yl);
            m[2]:=  Point(xr,   yr);
            Form1.Canvas.Polygon( m);

            //------------------------------------
            n[0]:=   Point(xs,   ys);
            n[1]:=   Point(xl,   yl);
            n[2]:=  Point(xr,   yr);
            Form1.Canvas.Polygon( n);            
        end;
    end;
end;

procedure   TForm1.FormShow(Sender:   TObject);
begin
    Form1.Color   :=   clWhite;
    Form1.Caption   :=   '画带箭头的直线 ';
    Form1.WindowState   :=   wsMaximized;
    B   :=   False;

    xt   :=   -1;      yt   :=   -1;

    xl   :=   -1;      yl   :=   -1;

    xr   :=   -1;
    yr   :=   -1;



end;


end.

差不多是因目标数据类型来分类代表的。Akka-http提供了许多品类的预设实例到Mashalling转换:

  使用GDI+,更进一步了

PredefinedToEntityMarshallers
Array[Byte]
ByteString
Array[Char]
String
akka.http.scaladsl.model.FormData
akka.http.scaladsl.model.MessageEntity
T <: akka.http.scaladsl.model.Multipart
PredefinedToResponseMarshallers
T, if a ToEntityMarshaller[T] is available
HttpResponse
StatusCode
(StatusCode, T), if a ToEntityMarshaller[T] is available
(Int, T), if a ToEntityMarshaller[T] is available
(StatusCode, immutable.Seq[HttpHeader], T), if a ToEntityMarshaller[T] is available
(Int, immutable.Seq[HttpHeader], T), if a ToEntityMarshaller[T] is available
PredefinedToRequestMarshallers
HttpRequest
Uri
(HttpMethod, Uri, T), if a ToEntityMarshaller[T] is available
(HttpMethod, Uri, immutable.Seq[HttpHeader], T), if a ToEntityMarshaller[T] is available
GenericMarshallers
Marshaller[Throwable, T]
Marshaller[Option[A], B], if a Marshaller[A, B] and an EmptyValue[B] is available
Marshaller[Either[A1, A2], B], if a Marshaller[A1, B] and a Marshaller[A2, B] is available
Marshaller[Future[A], B], if a Marshaller[A, B] is available
Marshaller[Try[A], B], if a Marshaller[A, B] is available
unit   Unit1;

interface

uses
    Windows,   Messages,   SysUtils,   Variants,   Classes,   Graphics,   Controls,   Forms,
    Dialogs;

const
    Penwidth   =   1;//画笔的粗细
    Len   =   15;//箭头线的长度
    {说明:这两个常量应该一起变化,具体值由效果来定。
    当Penwidth很小时,显示的效果不是太好}

type
    TForm1   =   class(TForm)
        procedure   FormMouseUp(Sender:   TObject;   Button:   TMouseButton;
            Shift:   TShiftState;   X,   Y:   Integer);
        procedure   FormMouseDown(Sender:   TObject;   Button:   TMouseButton;
            Shift:   TShiftState;   X,   Y:   Integer);
        procedure   FormMouseMove(Sender:   TObject;   Shift:   TShiftState;   X,
            Y:   Integer);
        procedure   FormShow(Sender:   TObject);
        procedure   FormCreate(Sender:   TObject);
    private
        {   Private   declarations   }
    public
        {   Public   declarations   }
    end;

var
    Form1:   TForm1;
    xs,   ys:   integer;//画线开始处的坐标  start

    xl,   yl:   integer;//记录第一条箭头线的端点坐标   left       三角形左边顶点
    xr,   yr:   integer;//记录第二条箭头线的端点坐标    rift

    xt,   yt:   integer;//记录鼠标前一时刻的坐标     termoei


    B:   boolean;//判断是否已经开始画线

implementation  {$R   *.dfm}
uses
GDIPAPI,GDIPOBJ; //包含这两个GDI+单元

procedure   TForm1.FormMouseUp(Sender:   TObject;   Button:   TMouseButton;
    Shift:   TShiftState;   X,   Y:   Integer);
begin
    B   :=   False;  //鼠标弹起,结束 画线
end;

procedure   TForm1.FormMouseDown(Sender:   TObject;   Button:   TMouseButton;
    Shift:   TShiftState;   X,   Y:   Integer);
begin
    xs   :=   x;
    ys   :=   y;

    xt   :=   x;     yt   :=   y;

    xl   :=   -1;      yl   :=   -1;



    xr   :=   -1;
    yr   :=   -1;
    B   :=   True; //鼠标按下 开始 画线
end;

procedure   TForm1.FormMouseMove(Sender:   TObject;   Shift:   TShiftState;   X,
    Y:   Integer);
var
    m : array[1..4] of TPoint;

var
g: TGPGraphics;
p: TGPPen;
sb: TGPSolidBrush;
pts: array[1..4] of TGPPoint;
begin
    if   B   then
    begin
//        Form1.Canvas.Pen.Mode   :=   pmNotXor;  //pmNotXor 将旧三角形用背景色 划线,即清除旧的
//        Form1.Canvas.Pen.Color   :=   clRed;
//        Form1.Canvas.Pen.Width   :=   PenWidth;


        if   xl   <>   -1   then       //pmNotXor 将旧三角形用背景色 划线,即
        begin




    //清除  三角形
//            Form1.Canvas.Brush.Color:=clRed;
//            m[1]:=   Point(xt,   yt);
//            m[2]:=   Point(xl,   yl);
//            m[3]:=  Point(xs,   ys);
//            m[4]:=  Point(xr,   yr);
//            Form1.Canvas.Polygon( m);

g := TGPGraphics.Create(Canvas.Handle);
g.SetSmoothingMode( SmoothingModeAntiAlias);{指定平滑(抗锯齿)}
p := TGPPen.Create(MakeColor(255,255,255),1);
sb := TGPSolidBrush.Create(MakeColor(255,255,255));


pts[1].X := xt;pts[1].Y := yt;
pts[2].X := xl;pts[2].Y := yl;
pts[3].X := xs; pts[3].Y := ys;
pts[4].X := xr; pts[4].Y := yr;


g.FillPolygon(sb, PGPPoint(@pts), 4); {第三个参数是顶点数}
g.DrawPolygon(p, PGPPoint(@pts), Length(pts));{第二个参数是指针类型, 需亚转换}

p.Free;
sb.Free;
g.Free;




        end;
        //记录下原坐标
        xt   :=   x;        yt   :=   y;


        if   x   >   xs   then
        begin
            xl   :=   trunc(x   -   Len   *   Cos(ArcTan((y   -   ys)   /   (x   -   xs))   -   Pi   /   6));
            yl   :=   trunc(y   -   Len   *   Sin(ArcTan((y   -   ys)   /   (x   -   xs))   -   Pi   /   6));
            xr   :=   trunc(x   -   Len   *   Cos(ArcTan((y   -   ys)   /   (x   -   xs))   +   Pi   /   6));
            yr   :=   trunc(y   -   Len   *   Sin(ArcTan((y   -   ys)   /   (x   -   xs))   +   Pi   /   6));
        end
        else
            if   x   <   xs   then
            begin
                xl   :=   trunc(x   +   Len   *   Cos(ArcTan((y   -   ys)   /   (x   -   xs))   -   Pi   /   6));
                yl   :=   trunc(y   +   Len   *   Sin(ArcTan((y   -   ys)   /   (x   -   xs))   -   Pi   /   6));
                xr   :=   trunc(x   +   Len   *   Cos(ArcTan((y   -   ys)   /   (x   -   xs))   +   Pi   /   6));
                yr   :=   trunc(y   +   Len   *   Sin(ArcTan((y   -   ys)   /   (x   -   xs))   +   Pi   /   6));
            end
            else
                if   y   <   ys   then
                begin
                    xl   :=   trunc(x   -   Len   *   Sin(Pi   /   6));
                    yl   :=   trunc(y   +   Len   *   Cos(Pi   /   6));
                    xr   :=   trunc(x   +   Len   *   Sin(Pi   /   6));
                    yr   :=   trunc(y   +   Len   *   Cos(Pi   /   6));
                end
                else
                    if   y   >   ys   then
                    begin
                        xl   :=   trunc(x   -   Len   *   Sin(Pi   /   6));
                        yl   :=   trunc(y   -   Len   *   Cos(Pi   /   6));
                        xr   :=   trunc(x   +   Len   *   Sin(Pi   /   6));
                        yr   :=   trunc(y   -   Len   *   Cos(Pi   /   6));
                    end
                    else
                    begin
                        xl   :=   -1;
                        yl   :=   -1;
                        xr   :=   -1;
                        yr   :=   -1;
                    end;
        if   xl   <>   -1   then
        begin

//            Form1.Canvas.Brush.Color:=clRed;     //填充三角形
//            m[1]:=   Point(x,   y);
//            m[2]:=   Point(xl,   yl);
//            m[3]:=  Point(xs,   ys);
//            m[4]:=  Point(xr,   yr);
//            Form1.Canvas.Polygon( m);


g := TGPGraphics.Create(Canvas.Handle);
g.SetSmoothingMode( SmoothingModeAntiAlias);{指定平滑(抗锯齿)}

sb := TGPSolidBrush.Create(MakeColor(255,0,255));


pts[1].X := x;  pts[1].Y := y;
pts[2].X := xl ;pts[2].Y := yl;
pts[3].X := xs; pts[3].Y := ys;
pts[4].X := xr; pts[4].Y := yr;

g.FillPolygon(sb, PGPPoint(@pts), 4); {第三个参数是顶点数}

sb.Free;
g.Free;


        end;
    end;
end;

procedure   TForm1.FormShow(Sender:   TObject);
begin
    Form1.Color   :=   clWhite;
    Form1.Caption   :=   '画带箭头的直线 ';
    Form1.WindowState   :=   wsMaximized;
    B   :=   False;

    xt   :=   -1;      yt   :=   -1;

    xl   :=   -1;      yl   :=   -1;

    xr   :=   -1;
    yr   :=   -1;



end;

procedure   TForm1.FormCreate(Sender:   TObject);
begin

end;

end.

Akka-http还提供了一个器类Marshal:

  

class Marshal[A](val value: A) {
  /**
   * Marshals `value` using the first available [[Marshalling]] for `A` and `B` provided by the given [[Marshaller]].
   * If the marshalling is flexible with regard to the used charset `UTF-8` is chosen.
   */
  def to[B](implicit m: Marshaller[A, B], ec: ExecutionContext): Future[B] =
    m(value).fast.map {
      _.head match {
        case Marshalling.WithFixedContentType(_, marshal) ⇒ marshal()
        case Marshalling.WithOpenCharset(_, marshal)      ⇒ marshal(HttpCharsets.`UTF-8`)
        case Marshalling.Opaque(marshal)                  ⇒ marshal()
      }
    }

  /**
   * Marshals `value` to an `HttpResponse` for the given `HttpRequest` with full content-negotiation.
   */
  def toResponseFor(request: HttpRequest)(implicit m: ToResponseMarshaller[A], ec: ExecutionContext): Future[HttpResponse] = {
    import akka.http.scaladsl.marshalling.Marshal._
    val ctn = ContentNegotiator(request.headers)

    m(value).fast.map { marshallings ⇒
      val supportedAlternatives: List[ContentNegotiator.Alternative] =
        marshallings.collect {
          case Marshalling.WithFixedContentType(ct, _) ⇒ ContentNegotiator.Alternative(ct)
          case Marshalling.WithOpenCharset(mt, _)      ⇒ ContentNegotiator.Alternative(mt)
        }(collection.breakOut)
      val bestMarshal = {
        if (supportedAlternatives.nonEmpty) {
          ctn.pickContentType(supportedAlternatives).flatMap {
            case best @ (_: ContentType.Binary | _: ContentType.WithFixedCharset | _: ContentType.WithMissingCharset) ⇒
              marshallings collectFirst { case Marshalling.WithFixedContentType(`best`, marshal) ⇒ marshal }
            case best @ ContentType.WithCharset(bestMT, bestCS) ⇒
              marshallings collectFirst {
                case Marshalling.WithFixedContentType(`best`, marshal) ⇒ marshal
                case Marshalling.WithOpenCharset(`bestMT`, marshal)    ⇒ () ⇒ marshal(bestCS)
              }
          }
        } else None
      } orElse {
        marshallings collectFirst { case Marshalling.Opaque(marshal) ⇒ marshal }
      } getOrElse {
        throw UnacceptableResponseContentTypeException(supportedAlternatives.toSet)
      }
      bestMarshal()
    }
  }
}

 图片 4

咱俩可用Marshal.to和toResponseFor(request)把Akka-http提供的预设可转换类实例转换成相关的toResponseMarshallable类实例。因为Server-Directive如complete接受一个toResponseMarshallable来构建HttpResponse:

 

  /**
   * Completes the request using the given arguments.
   *
   * @group route
   */
  def complete(m: ⇒ ToResponseMarshallable): StandardRoute =
    StandardRoute(_.complete(m))

QQ软件的箭头:离QQ的尚是有肯定的离开

以其它一个目标里提供了ToResponseMarshallable隐式转换:

图片 5

/** Something that can later be marshalled into a response */
trait ToResponseMarshallable {
  type T
  def value: T
  implicit def marshaller: ToResponseMarshaller[T]

  def apply(request: HttpRequest)(implicit ec: ExecutionContext): Future[HttpResponse] =
    Marshal(value).toResponseFor(request)
}

object ToResponseMarshallable {
  implicit def apply[A](_value: A)(implicit _marshaller: ToResponseMarshaller[A]): ToResponseMarshallable =
    new ToResponseMarshallable {
      type T = A
      def value: T = _value
      def marshaller: ToResponseMarshaller[T] = _marshaller
    }

  implicit val marshaller: ToResponseMarshaller[ToResponseMarshallable] =
    Marshaller { implicit ec ⇒ marshallable ⇒ marshallable.marshaller(marshallable.value) }
}

 

要在可视域内(implicit
scope)能发现Marshaller[A,B]的隐式实例就可知满足complete入参要求了。下面是有些Marshal用例:

import akka.util.ByteString
import akka.http.scaladsl.model.{HttpResponse, MessageEntity}
import akka.http.scaladsl.marshalling.Marshal
import akka.http.scaladsl.model._

object Marshalling  {

  val string = "Yeah"
  val entityFuture = Marshal(string).to[MessageEntity]
  val errorMsg = "Easy, pal!"
  val responseFuture = Marshal(420 -> errorMsg).to[HttpResponse]
  val request = HttpRequest(headers = List(headers.Accept(MediaTypes.`application/json`)))
  val responseText = "Plaintext"
  val respFuture = Marshal(responseText).toResponseFor(request) // with content negotiation!
  val bsFuture = Marshal("oh my!").to[ByteString]
  val reqFuture = Marshal("can you?").to[HttpRequest]
  val resp = reqFuture.flatMap {r => Marshal("ok").toResponseFor(r)}

}

那么对那些自定义的类型U,由于不容许来先设定对应之Marshaller[U,B],应该怎么收拾?如简单的case
class:

  case class User(id: Int, name: String)
  case class Item(id: Int, name: String, price: Double)
  val john = Marshal(User(1,"John")).to[MessageEntity]
  val fruit = Marshal(Item(1,"banana", 3.5)).to[MessageEntity]

  val route =
    get {
      path("items") {
        complete(fruit)
      } ~
      path("users") {
        complete(john)
      }
    }

看来将User,Item类型实例转成ToResponseMarshallable是没有问题的。但是,通过隐式转换ToResponseMarshallable被转移成Marshaller[U,B],而实例化这个类型的历程即构建网上传输格式的数码经常得重新多的支撑。这个可是网上传的消息是透过Json、XML这样的数量描述语言来产生实际数量的。Akka-http通过akka-http-spray-json模块直接支持由Spray-Json实现之Json读写工具库。具体Json读写是由此RootJsonFormat[T]当接口实现的:

/**
 * A special JsonFormat signaling that the format produces a legal JSON root object, i.e. either a JSON array
 * or a JSON object.
 */
trait RootJsonFormat[T] extends JsonFormat[T] with RootJsonReader[T] with RootJsonWriter[T]

RootJsonFormat[T]代表T类型实例的Json转换。RootJsonFormat[T]的继承父辈包括:
/**
  * Provides the JSON deserialization and serialization for type T.
 */
trait JsonFormat[T] extends JsonReader[T] with JsonWriter[T]

/**
 * A special JsonReader capable of reading a legal JSON root object, i.e. either a JSON array or a JSON object.
 */
@implicitNotFound(msg = "Cannot find RootJsonReader or RootJsonFormat type class for ${T}")
trait RootJsonReader[T] extends JsonReader[T]

/**
 * A special JsonWriter capable of writing a legal JSON root object, i.e. either a JSON array or a JSON object.
 */
@implicitNotFound(msg = "Cannot find RootJsonWriter or RootJsonFormat type class for ${T}")
trait RootJsonWriter[T] extends JsonWriter[T]

它们以继续了切实的Json读写工具类:

/**
  * Provides the JSON deserialization for type T.
 */
@implicitNotFound(msg = "Cannot find JsonReader or JsonFormat type class for ${T}")
trait JsonReader[T] {
  def read(json: JsValue): T
}

object JsonReader {
  implicit def func2Reader[T](f: JsValue => T): JsonReader[T] = new JsonReader[T] {
    def read(json: JsValue) = f(json)
  }
}

/**
  * Provides the JSON serialization for type T.
 */
@implicitNotFound(msg = "Cannot find JsonWriter or JsonFormat type class for ${T}")
trait JsonWriter[T] {
  def write(obj: T): JsValue
}

object JsonWriter {
  implicit def func2Writer[T](f: T => JsValue): JsonWriter[T] = new JsonWriter[T] {
    def write(obj: T) = f(obj)
  }
}

其提供了函数JsValue=>T到JsonReader[T]与T=>JsValue到JsonWriter直接的隐式转换。Akka-http的Json解决方案是百里挑一的type-class模式:是一致栽好随意创建效能的色继承模式(add-hoc
polymorphism)。它的特色就是是当可视域内(implicit
scope)应不同功能要求提供不同之成效实现种的隐式实例(implicit
instance)。具体用例如下:

trait Formats extends SprayJsonSupport with DefaultJsonProtocol
object Converters extends Formats {
  case class User(id: Int, name: String)
  case class Item(id: Int, name: String, price: Double)
  implicit val itemFormat = jsonFormat3(Item.apply)
  implicit val userFormat = jsonFormat2(User.apply)
}

jsonFormatXX是Spray-Json提供的Json读写实现。我们拿此隐式实例置于当前可是视域内即成功了同Akka-http的对接。我们来瞧JsonFormat的概念:

trait ProductFormatsInstances { self: ProductFormats with StandardFormats =>
  // Case classes with 1 parameters

  def jsonFormat1[P1 :JF, T <: Product :ClassManifest](construct: (P1) => T): RootJsonFormat[T] = {
    val Array(p1) = extractFieldNames(classManifest[T])
    jsonFormat(construct, p1)
  }
  def jsonFormat[P1 :JF, T <: Product](construct: (P1) => T, fieldName1: String): RootJsonFormat[T] = new RootJsonFormat[T]{
    def write(p: T) = {
      val fields = new collection.mutable.ListBuffer[(String, JsValue)]
      fields.sizeHint(1 * 2)
      fields ++= productElement2Field[P1](fieldName1, p, 0)
      JsObject(fields: _*)
    }
    def read(value: JsValue) = {
      val p1V = fromField[P1](value, fieldName1)
      construct(p1V)
    }
  }
...
}

我们看出了jsonFormat返回结果类型是RootJsonFormat[T]。如果发生个case
class T,通过jsonFormat可以获得read(value:
JsValue)及write(p:T)这有限单实际的Json读写函数。Spray-Json提供的预设了Json转换的品种包括下面各类别:

/**
  * Provides all the predefined JsonFormats.
 */
trait DefaultJsonProtocol
        extends BasicFormats
        with StandardFormats
        with CollectionFormats
        with ProductFormats
        with AdditionalFormats

object DefaultJsonProtocol extends DefaultJsonProtocol

例如BasicFormat:

/**
  * Provides the JsonFormats for the most important Scala types.
 */
trait BasicFormats {

  implicit object IntJsonFormat extends JsonFormat[Int] {
    def write(x: Int) = JsNumber(x)
    def read(value: JsValue) = value match {
      case JsNumber(x) => x.intValue
      case x => deserializationError("Expected Int as JsNumber, but got " + x)
    }
  }
...
}

这些品种的Json转换已经是具体的read/write操作了。在SprayJsonSupport
trait里有最后的Marshaller[U,B]链接:

/**
 * A trait providing automatic to and from JSON marshalling/unmarshalling using an in-scope *spray-json* protocol.
 */
trait SprayJsonSupport {
...
  implicit def sprayJsonUnmarshaller[T](implicit reader: RootJsonReader[T]): FromEntityUnmarshaller[T] =
    sprayJsValueUnmarshaller.map(jsonReader[T].read)
...
  //#sprayJsonMarshallerConverter
  implicit def sprayJsonMarshaller[T](implicit writer: RootJsonWriter[T], printer: JsonPrinter = CompactPrinter): ToEntityMarshaller[T] =
    sprayJsValueMarshaller compose writer.write
...
}

咱们于方提到过FromEntityUnmarshaller[T]和ToEntityMarshaller[T]的是Marshaller[A,B]的别名:

  type FromEntityUnmarshaller[T] = Unmarshaller[HttpEntity, T]

  type ToEntityMarshaller[T] = Marshaller[T, MessageEntity]

既然Akka-http的Json实现方式是type-class模式之,那么我们就是摸索其它Json库底成效实现方式,如:Json4s。我们要以build.sbt中在下面的凭:

  "de.heikoseeberger" %% "akka-http-json4s" % "1.19.0-M2",
  "org.json4s" %% "json4s-jackson" % "3.6.0-M1",
  "org.json4s" %% "json4s-ext" % "3.6.0-M1",

 akka-http-Json4s通过trait
Json4sSupport提供了Json4s实现方式:

trait Json4sSupport {
...
  /**
    * HTTP entity => `A`
    *
    * @tparam A type to decode
    * @return unmarshaller for `A`
    */
  implicit def unmarshaller[A: Manifest](implicit serialization: Serialization,
                                         formats: Formats): FromEntityUnmarshaller[A] = ...

  /**
    * `A` => HTTP entity
    *
    * @tparam A type to encode, must be upper bounded by `AnyRef`
    * @return marshaller for any `A` value
    */
  implicit def marshaller[A <: AnyRef](implicit serialization: Serialization,
                                       formats: Formats,
                                       shouldWritePretty: ShouldWritePretty =
                                         ShouldWritePretty.False): ToEntityMarshaller[A] = ...

一律提供了FromEntityUnMarshaller[A]和ToEntityMarshaller[A]即时片类似的隐式实例。Serialization提供了Json的切切实实读写函数:

trait Serialization {
  import java.io.{Reader, Writer}
  /** Serialize to String.
   */
  def write[A <: AnyRef](a: A)(implicit formats: Formats): String
...
  /** Deserialize from a String.
   */
  def read[A](json: String)(implicit formats: Formats, mf: Manifest[A]): A = read(StringInput(json))
...
}

Formats就是Json4s提供的所有Json转换预设类:

trait Formats extends Serializable { self: Formats =>
...
  def withBigInt: Formats = copy(wWantsBigInt = true)

  def withLong: Formats = copy(wWantsBigInt = false)

  def withBigDecimal: Formats = copy(wWantsBigDecimal = true)

...
}

在押起我们唯有需要在可视域内提供Serialization和Formats类型的隐式实例就实施了:

import de.heikoseeberger.akkahttpjson4s.Json4sSupport
import org.json4s.jackson
trait JsonCodec extends Json4sSupport {
  import org.json4s.DefaultFormats
  import org.json4s.ext.JodaTimeSerializers
  implicit val serilizer = jackson.Serialization
  implicit val formats = DefaultFormats ++ JodaTimeSerializers.all
}
object JsConverters extends JsonCodec

省现实用例:

  import scala.collection.mutable._
  case class User(id: Int, name: String)
  class Item(id: Int, name: String, price: Double)
  object AnyPic {
    val area = 10
    val title = "a picture"
    val data = ArrayBuffer[Byte](1,2,3)
  }

  val john = Marshal(User(1,"John")).to[MessageEntity]
  val fruit = Marshal(new Item(1,"banana", 3.5)).to[MessageEntity]
  val pic = Marshal(AnyPic).to[MessageEntity]

不但省却了重新的JsonFormatXX,而且效果更加灵活有力:因为不再局限为case
class这无异种从定义类型了,在无需额外代码情况下class,object等一切还支持。

下面是本篇讨论示范的源代码:

build.sbt

name := "learn-http"

version := "0.1"

scalaVersion := "2.12.3"

libraryDependencies ++= Seq(
  "de.heikoseeberger" %% "akka-http-json4s" % "1.19.0-M2",
  "org.json4s" %% "json4s-jackson" % "3.6.0-M1",
  "org.json4s" %% "json4s-ext" % "3.6.0-M1",
  "com.typesafe.akka" %% "akka-http" % "10.0.10",
  "com.typesafe.akka" %% "akka-actor" % "2.5.4",
  "com.typesafe.akka" %% "akka-stream" % "2.5.4",
  "com.typesafe.akka" %% "akka-http-spray-json" % "10.0.10"
)

Marshalling

import akka.actor._
import akka.stream._
import akka.util.ByteString
import akka.http.scaladsl.marshalling.Marshal
import akka.http.scaladsl.model._
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.marshallers.sprayjson._
import spray.json._

trait Formats extends SprayJsonSupport with DefaultJsonProtocol
object Converters extends Formats {
  case class User(id: Int, name: String)
  case class Item(id: Int, name: String, price: Double)
  implicit val itemFormat = jsonFormat3(Item.apply)
  implicit val userFormat = jsonFormat2(User.apply)
}


object Marshalling {
  import Converters._
  implicit val httpSys = ActorSystem("httpSystem")
  implicit val httpMat = ActorMaterializer()
  implicit val httpEC = httpSys.dispatcher



  val string = "Yeah"
  val entityFuture = Marshal(string).to[MessageEntity]
  val errorMsg = "Easy, pal!"
  val responseFuture = Marshal(420 -> errorMsg).to[HttpResponse]
  val request = HttpRequest(headers = List(headers.Accept(MediaTypes.`application/json`)))
  val responseText = "Plaintext"
  val respFuture = Marshal(responseText).toResponseFor(request)

//  val bsFuture = Marshal("oh my!").to[ByteString]
  //  val reqFuture = Marshal(400).to[HttpRequest]
  //  val resp = reqFuture.flatMap {r => Marshal("ok").toResponseFor(r)}


  val john = Marshal(User(1,"John")).to[MessageEntity]
  val fruit = Marshal(Item(1,"banana", 3.5)).to[MessageEntity]

  val route =
    get {
      path("items") {
        complete(fruit)
      } ~
        path("users") {
          complete(john)
        }
    }

}

 Json4sMarshalling

import akka.actor._
import akka.stream._
import akka.http.scaladsl.marshalling.Marshal
import akka.http.scaladsl.model._
import akka.http.scaladsl.server.Directives._
import de.heikoseeberger.akkahttpjson4s.Json4sSupport
import org.json4s.jackson
trait JsonCodec extends Json4sSupport {
  import org.json4s.DefaultFormats
  import org.json4s.ext.JodaTimeSerializers
  implicit val serilizer = jackson.Serialization
  implicit val formats = DefaultFormats ++ JodaTimeSerializers.all
}
object JsConverters extends JsonCodec


object Json4sMarshalling {
  import JsConverters._
  implicit val httpSys = ActorSystem("httpSystem")
  implicit val httpMat = ActorMaterializer()
  implicit val httpEC = httpSys.dispatcher

  val string = "Yeah"
  val entityFuture = Marshal(string).to[MessageEntity]
  val errorMsg = "Easy, pal!"
  val responseFuture = Marshal(420 -> errorMsg).to[HttpResponse]
  val request = HttpRequest(headers = List(headers.Accept(MediaTypes.`application/json`)))
  val responseText = "Plaintext"
  val respFuture = Marshal(responseText).toResponseFor(request)




  import scala.collection.mutable._
  case class User(id: Int, name: String)
  class Item(id: Int, name: String, price: Double)
  object AnyPic {
    val area = 10
    val title = "a picture"
    val data = ArrayBuffer[Byte](1,2,3)
  }

  val john = Marshal(User(1,"John")).to[MessageEntity]
  val fruit = Marshal(new Item(1,"banana", 3.5)).to[MessageEntity]
  val pic = Marshal(AnyPic).to[MessageEntity]

  val route =
    get {
      path("items") {
        complete(fruit)
      } ~
        path("users") {
          complete(john)
        } ~
      path("pic") {
        complete(pic)
      }
    }

}