1

C++ 6 で作成されたアプリがあり、交通マップの空白のポリゴンを埋めて現在の交通状況を表示します。緑は良い、黄色は混雑している、など。

「シェル マップ」は、何も塗りつぶされていない長方形と多角形を使用した道路のビットマップです。データは道路センサー (ワイヤ インダクタ ループ) から収集され、ポリゴンはループ検出器のデータに基づいて塗りつぶされます。

マップが変更されると、誰かがペイントでビットマップを手動で拡大し、混雑色が塗りつぶされるそれぞれの新しい形状の内側の座標を取得する必要があります。マップのスケルトンを構成するポリゴンはすべてネイビー ブルーで描画されます。 、白い背景の上。

アプリを作りました。ここで、ユーザーがポリゴンの白い部分の内側をクリックすると、内側の境界のポイントがユーザーに表示され、内側の許可証がペイントされていることを示す拡大されたサムネイルが表示されます。

.Net では、周囲が完全にペイントされます。

C++ 6 アプリでは、一部のポリゴンがアプリを指しています。コレクションが正しく表示されません。

msPaint を調べたところ、.Net は MS Paint と同じようにポイントを描画しません。

簡単な例を次に示します。コードは、1 つのボタンと 1 つのラベルを持つ 1 つのフォームから作成されます。ビットマップに線が描かれ、ビットマップが見えるように「拡大」され、ラベルに表示されます。

描画される線分は、同じ 2 点を使用してペイントで線を描画する場合、MS ペイントで描画する線分と同じではありません。

  private void button1_Click(object sender, EventArgs e)
    {
        Bitmap bm = new Bitmap(16, 16);
        Graphics g = Graphics.FromImage(bm);
        //g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half;
        //g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
        //g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighSpeed;
        //g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.None;
        g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Default;
        Point pt = new Point(1, 3);
        Point pt2 = new Point(5, 1);
        // If you reverse the points, the same line is drawn.
        g.DrawLine(Pens.Orange, pt, pt2);
        // label1.Image = bm;
        Bitmap bm2 = ZoomMap(8, bm);
        g.Dispose();
        bm.Dispose();
        label1.Image = bm2;
    }

    private Bitmap ZoomMap(int zoomValue, Bitmap bm)
    {
        Bitmap zoomedBitMap;
        Size sz = bm.Size;// new Size(75, 75);
        Size newSize = new Size(sz.Width * zoomValue, sz.Height * zoomValue);
        zoomedBitMap = new Bitmap(newSize.Width, newSize.Height);
        Graphics gr = Graphics.FromImage(zoomedBitMap);
        gr.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
        gr.PageUnit = GraphicsUnit.Pixel;
        gr.DrawImage(bm, 1, 1, newSize.Width, newSize.Height);
        gr.Dispose();
        return zoomedBitMap;
    }

代替テキスト

どのような設定を適用しても、C# で MS ペイントを模倣する方法はありませんが、C++ 6 では MS ペイントを完全に模倣します。

既存のビットマップに描画するために呼び出すことができる Windows API の種類はありますか?

返信ありがとうございます。

4

1 に答える 1

4

デジタル微分解析器 (DDA) または Bresenham アルゴリズムのいずれかを使用すると、GDI+ で表示されるのと同じ結果が得られますが、標準の GDI 線描画の実装を見ると、標準の GDI LineTo実装が実際には 1 ピクセル短い線を描画することに気付くでしょう。指定したもの、MSDN を引用する

' LineTo 関数は、現在の位置から指定された点までの線を描画します。'

このため、GDI を使用すると、線は (1,3)-(4,1) から描画されます。GDI+ でこれらの同じ座標を使用すると、線のピクセル構造が以前のバージョンのペイントで見られるものと一致することがわかります。ただし、(5,1) の最後のピクセルは描画されません。ペイントなどのプログラムは、追加のピクセルを追加して線を完成させます。

ストレート GDI を使用するには、ペンの作成、DC へのオブジェクトの選択、オブジェクトの削除などの相互運用を処理する必要があります。すべて可能ですが、最終的には不便です。GDI+ でこれをシミュレートするには、1 ピクセル短い線を描画してから、そのエンドポイントから最終エンドポイントまで線を描画します。これにより、最後のピクセルが塗りつぶされます。

注:たとえば、Windows 7 でペイントを使用すると、線が正しく描画されることがわかるため、古いバージョンのペイントと言います。

楽しみのために、.NET から従来の GDI を使用する方法を簡単に示したいと思いました。相互運用コードを次に示します。

[DllImport("gdi32")]
static extern bool MoveToEx(IntPtr hdc, int x, int y, out Point point);

[DllImport("gdi32")]
static extern bool LineTo(IntPtr hdc, int x, int y);

[DllImport("gdi32")]
static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);

[DllImport("gdi32")]
static extern IntPtr CreatePen(int penStyle, int width, int color);

[DllImport("gdi32")]
static extern bool DeleteObject(IntPtr hgiobj);

private void Form1_Paint(object sender, PaintEventArgs e)
{
  Point ignore;
  IntPtr hdc = e.Graphics.GetHdc();
  IntPtr pen = CreatePen(1, 1, ColorTranslator.ToWin32(Color.Red));
  IntPtr oldPen = SelectObject(hdc, pen);
  MoveToEx(hdc, 1, 3, out ignore);
  LineTo(hdc, 5, 1);                
  SelectObject(hdc, oldPen);
  DeleteObject(pen);      
}

線が実際には 1 ピクセル短いことに注目してください。個人的には、グラフィックス デバイスを使用するネイティブ .NET ソリューションを使用し、正しいライン座標を決定して従来の GDI 機能を複製します。

GDIが最後のピクセルを除外する理由を知りたいと思うかもしれませんが、XORを使用して画面上に線を描画するのが一般的でした。これにより、同じ線を非常に簡単に削除できます。XORで線を再描画するだけで、次のコマンドで削除されます元の背景はそのまま。もちろん、ピクセルを 2 回描画しないように注意する必要があります。そうしないと、画面にアーティファクトが残ります。

複数の呼び出しを使用して形状を描画することは一般的であるため、LineToLineTo を 3 回呼び出して、たとえば三角形を描画できます。各線の最初の点が前の線の最後の点と重なり、前述のアーティファクトが発生することを心配する必要はありません。たとえば、XOR を使用する場合、LineTo への後続の呼び出しは、前の行の最後のピクセルが描画されていないため、前の行が終了した場所から安全に開始できます。

于 2011-01-01T21:34:04.997 に答える