Autor Téma: Jak v C# kreslit 2D grafiku?  (Přečteno 5262 krát)

RomanZ

  • Host
Jak v C# kreslit 2D grafiku?
« kdy: 20-07-2012, 15:09:38 »
Dělám v C# a potřeboval bych kreslit 2D grafiku (vektorovou i bitmapy). Technická schémata, grafy, mapy, logické hry (asi jako šachy, piškvorky, tahové strategie).

Chtěl bych sice jen 2D, ale abych mohl mapou/grafem šoupat a zoomovat (funkčnost asi jako www.mapy.cz). Zároveň bych chtěl zobrazovat drobné bitmapy/sprity, jako třeba ikony na mapě, figurky ve hře apod., s možností zoomování a rotace.

Doporučte mi způsob, jak na to.

XNA nebo SlimDX mi připadá jako kanón na vrabce. Existuje něco menšího a jednoduššího? Něco jako ve starých Delphi bývala knihovna Graphics32.

Kdyby ta knihovna vnitřně využívala 3D akcelerátor, tak bych potřeboval, aby na něm nebyla životně závislá a kreslila i na počítačích, které ho nemají (např. virtuálka ve VMWare).

Předem dík za rady a zkušenosti.

Offline TC

  • Příspěvků: 20
  • Karma: 0
Re:Jak v C# kreslit 2D grafiku?
« Odpověď #1 kdy: 20-07-2012, 15:18:08 »
Odpoved pro WinForms:
Zaklad si muzes napsat sam za jedno odpoledne. Kdyz ho nenavrhnes blbe, tak mu muzes doplnovat funkcnost tak, jak pude cas. Budes to mit rychleji nez se naucis pouzivat nejakou cizi knihovnu. Navic, u cizi knihovny mas prakticky jistotu, ze sice dela tisckrat vic nez co potrebujes ale to co potrebujes neumi a neda se tim smerem prihnout.

Odpoved pro WPF:

Nevim nic co bych mohl vyjadrit takovym slovnikem, aby se administratori neposrali.

Zdravim

TC


Offline erdt.martin

  • Příspěvků: 35
  • Karma: 0
Re:Jak v C# kreslit 2D grafiku?
« Odpověď #2 kdy: 20-07-2012, 18:14:58 »
Osobne jsem pouzil na 2D knihovnu "D2DWrapper.dll"... tehdy jsem potreboval vykreslovat plynule pohyblivy label... tedy v labelu mel bezet text... A porad to problikavalo, i kdyz jsem dal 2 buffer, do 3D se mi poustet nechtelo a toto bylo docela schudne reseni :)

Snad jsem pomohl.

Martin

Offline TC

  • Příspěvků: 20
  • Karma: 0
Re:Jak v C# kreslit 2D grafiku?
« Odpověď #3 kdy: 20-07-2012, 19:07:54 »
Osobne si to pisu sam a nic mi neblika.

Zdravim

TC

Offline Mi.Chal.

  • Moderátoři
  • Guru
  • *****
  • Příspěvků: 558
  • Karma: 23
Re:Jak v C# kreslit 2D grafiku?
« Odpověď #4 kdy: 20-07-2012, 19:16:43 »
Na jednoduché věci stačí kreslit do Graphics nebo Canvasu ve WPF. Z cizích knihoven jsme používali třeba yFiles, to je ale komerční.

Pokud nemáš akcelerátor, tak by to nemělo vadit u ničeho - pokud akcelerátor není, tak se výpočty dělají na CPU místo na GPU. Otázka je jenom, jestli to pak bude ještě použitelně rychlé. Pro pár spritů ale problém mít nebudeš.

Offline erdt.martin

  • Příspěvků: 35
  • Karma: 0
Re:Jak v C# kreslit 2D grafiku?
« Odpověď #5 kdy: 20-07-2012, 19:26:41 »
TC: Az tak daleko me znalosti nesahaji... ;) Zatim... Jednou snad. :)

RomanZ

  • Host
Re:Jak v C# kreslit 2D grafiku?
« Odpověď #6 kdy: 20-07-2012, 22:58:32 »
Díky všem, rád vyzkouším.

> Odpoved pro WinForms:
> Zaklad si muzes napsat sam za jedno odpoledne.

Toto je pravda jen pro grafy, výkresy, schémata, prostě vektorovou grafiku. S tím si poradím. Jenže potřebuju pracovat i s bitmapou - načíst obrázek X*Y pixelů veliký, zmenšit ho nebo zvětšit, zrotovat, a pak ho vykreslit na plochu se zachováním průhlednosti. To si sám nenapíšu, na to mi chybí znalosti a snad je to i zbytečné, pokud už existuje něco hotového.

Na používání cizích knihoven mám naprosto stejný názor s TC. Souhlasím se vším, navíc často přestanou fungovat na nové verzi Windows nebo obsahují chyby, které nikdo nedokáže autora přimět opravit, často jsou jen v jednom formátu (kdo psal něco pro 64bit, ví jak to myslím), často jsou vázány nevyhovující licencí... Ale někdy se dá narazit na knihovnu, která dělá jednu věc a dělá ji dobře. Kde bych dnes byl bez log4net :)

Takže ano, nemám rád cizí knihovny. Ale zároveň si nemůžu psát všechno sám, na to je život moc krátký.

A teď si dám kafe a jdu si napsat svůj vlastní driver na tiskárnu :)))

Offline TC

  • Příspěvků: 20
  • Karma: 0
Re:Jak v C# kreslit 2D grafiku?
« Odpověď #7 kdy: 21-07-2012, 09:56:16 »


Toto je pravda jen pro grafy, výkresy, schémata, prostě vektorovou grafiku. S tím si poradím. Jenže potřebuju pracovat i s bitmapou - načíst obrázek X*Y pixelů veliký, zmenšit ho nebo zvětšit, zrotovat, a pak ho vykreslit na plochu se zachováním průhlednosti. To si sám nenapíšu, na to mi chybí znalosti a snad je to i zbytečné, pokud už existuje něco hotového.

Za jedno odpoledne to jde i s bitmapou:
Kód: C++ [Vybrat]
  1. namespace BitmapSupport
  2. {
  3.     /// <summary>
  4.     /// Bitmap operations
  5.     /// </summary>
  6.     public static class BmpSupport
  7.     {
  8.         /// <summary>
  9.         /// Format in which all bitmaps are handled
  10.         /// </summary>
  11.         public const PixelFormat standardFormat = PixelFormat.Format32bppArgb;
  12.  
  13.         /// <summary>
  14.         /// Converts bitmap to a normalized format if necessary
  15.         /// </summary>
  16.         /// <param name="bmp">Bitmap to normalize</param>
  17.         /// <factual>Ale ze ten Mi.Chal je ale urazlivej zmetek jakyho by jeden pohledal, to se zaprit neda</factual>
  18.         /// <remarks>If new bitmap is created the old bitmap is disposed</remarks>
  19.         public static void Normalize(ref Bitmap bmp)
  20.         {
  21.             if (bmp != null && bmp.PixelFormat != standardFormat)
  22.             {
  23.                 var bmp1 = new Bitmap(bmp.Width, bmp.Height, PixelFormat.Format32bppArgb);
  24.                 using (var g = Graphics.FromImage(bmp1)) g.DrawImage(bmp, 0, 0);
  25.                 bmp.Dispose();
  26.                 bmp = bmp1;
  27.             }
  28.         }
  29.         /// <summary>
  30.         /// Sets alpha channel to the bitmap
  31.         /// </summary>
  32.         /// <param name="bmp">Bitmap to set</param>
  33.         /// <param name="alpha">Alpha valus</param>
  34.         public static void SetAlpha(this Bitmap bmp, byte alpha)
  35.         {
  36.             if (bmp == null) return;
  37.             BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat);
  38.             int i, n = bmpData.Stride * bmp.Height;
  39.  
  40.             var val = new byte[n];
  41.             // Keep alpha==0 always zero
  42.             if (alpha == 0) alpha = 1;
  43.             IntPtr ptr = bmpData.Scan0;
  44.             Marshal.Copy(ptr, val, 0, n);
  45.             for (i = 3; i < n; i += 4) if (val[i] != 0) val[i] = alpha;
  46.             Marshal.Copy(val, 0, ptr, n);
  47.             bmp.UnlockBits(bmpData);
  48.         }
  49.  
  50.         public static Bitmap Morph(this Bitmap src, List<Point> srcPoint, int width, int height, List<Point> trgPoint)
  51.         {
  52.             if (src.PixelFormat != BmpSupport.standardFormat) throw new Exception("Improper pixel format in BitmapWrapper");
  53.             var biquad = new Biquadratic(srcPoint, trgPoint);
  54.             if (!biquad.ok) return new Bitmap(src);
  55.  
  56.             var trg = new Bitmap(width, height, BmpSupport.standardFormat);
  57.             using (BitmapWrapper srcw = new BitmapWrapper(src, true), trgw = new BitmapWrapper(trg, false))
  58.                 trgw.PopulateFrom(srcw, biquad);
  59.             return trg;
  60.         }
  61.  
  62.         public static Bitmap PseudoColor(double[,] data, int granularity, ColorInterpolator color)
  63.         {
  64.             int nx = data.GetLength(0), ny = data.GetLength(1);
  65.             var bmp = new Bitmap(nx * granularity, ny * granularity, standardFormat);
  66.             using (var wrp = new BitmapWrapper(bmp, false)) wrp.InterpolateColors(data, granularity, color);
  67.             return bmp;
  68.  
  69.         }
  70.     }
  71.     public class BitmapWrapper : IDisposable
  72.     {
  73.         byte[] z_val;
  74.         Bitmap z_bmp;
  75.         int z_n, z_w, z_h, z_stride;
  76.         const int z_pix = 4;
  77.         bool z_isSource;
  78.         public delegate bool Populator(Point3D geo, out byte R, out byte G, out byte B);
  79.         public BitmapWrapper(Bitmap bmp, bool isSource)
  80.         {
  81.             z_isSource = isSource;
  82.             if (bmp.PixelFormat != BmpSupport.standardFormat) throw new Exception("Improper pixel format in BitmapWrapper");
  83.             z_bmp = bmp;
  84.             z_w = z_bmp.Width;
  85.             z_h = z_bmp.Height;
  86.             var bmpData = bmp.LockBits(new Rectangle(0, 0, z_w, z_h), ImageLockMode.ReadWrite, bmp.PixelFormat);
  87.             z_stride = bmpData.Stride;
  88.             z_n = z_stride * z_h;
  89.             z_val = new byte[z_n];
  90.             IntPtr ptr = bmpData.Scan0;
  91.             if (z_isSource) Marshal.Copy(ptr, z_val, 0, z_n);
  92.             bmp.UnlockBits(bmpData);
  93.         }
  94.         public void Dispose()
  95.         {
  96.             if (z_isSource) return;
  97.             var bmpData = z_bmp.LockBits(new Rectangle(0, 0, z_w, z_h), ImageLockMode.ReadWrite, z_bmp.PixelFormat);
  98.             IntPtr ptr = bmpData.Scan0;
  99.             Marshal.Copy(z_val, 0, ptr, z_n);
  100.             z_bmp.UnlockBits(bmpData);
  101.         }
  102.         public void PopulateFrom(BitmapWrapper src, Biquadratic biq)
  103.         {
  104.             int xsrc;
  105.             int itrg, jtrg, xtrg;
  106.             for (jtrg = 0; jtrg < z_h; jtrg++)
  107.                 for (xtrg = jtrg * z_stride, itrg = 0; itrg < z_w; itrg++, xtrg += z_pix)
  108.                 {
  109.                     var pt = biq.IntVal(itrg, jtrg);
  110.                     if (pt.X >= 0 && pt.X < src.z_w && pt.Y >= 0 && pt.Y < src.z_h)
  111.                     {
  112.                         xsrc = pt.Y * src.z_stride + pt.X * z_pix;
  113.                         z_val[xtrg] = src.z_val[xsrc];
  114.                         z_val[xtrg + 1] = src.z_val[xsrc + 1];
  115.                         z_val[xtrg + 2] = src.z_val[xsrc + 2];
  116.                         z_val[xtrg + 3] = 255;
  117.                     }
  118.                 }
  119.         }
  120.         public void PopulateFrom(Populator populator, QView view, int granularity)
  121.         {
  122.             int itrg, jtrg, xtrg;
  123.             for (jtrg = 0; jtrg < z_h; jtrg += granularity)
  124.                 for (xtrg = jtrg * z_stride, itrg = 0; itrg < z_w; itrg += granularity, xtrg += z_pix * granularity)
  125.                 {
  126.                     Point3D geo;
  127.                     if (view.GeoFromDisplay(new Point(itrg, jtrg), out geo) &&
  128.                     populator(geo, out z_val[xtrg + 2], out z_val[xtrg + 1], out z_val[xtrg])) z_val[xtrg + 3] = 255;
  129.                 }
  130.         }
  131.         public void InterpolateColors(double[,] data, int granularity, ColorInterpolator color)
  132.         {
  133.             int itrg, jtrg, xtrg, isrc, jsrc;
  134.             for (jtrg = 0, jsrc = 0; jtrg < z_h; jtrg += granularity, jsrc++)
  135.                 for (xtrg = jtrg * z_stride, itrg = 0, isrc = 0; itrg < z_w; itrg += granularity, xtrg += z_pix * granularity, isrc++)
  136.                     color.Interpolate(data[isrc, jsrc], z_val, xtrg);
  137.  
  138.             for (jtrg = 0; jtrg < z_h - granularity; jtrg += granularity)
  139.                 for (xtrg = jtrg * z_stride, itrg = 0; itrg < z_w; itrg += granularity, xtrg += z_pix * granularity)
  140.                 {
  141.                     InterpolateBetweenPoints(xtrg, xtrg + z_stride * granularity, granularity, z_stride);
  142.                 }
  143.             for (jtrg = 0; jtrg < z_h; jtrg++)
  144.                 for (xtrg = jtrg * z_stride, itrg = 0; itrg < z_w - granularity; itrg += granularity, xtrg += z_pix * granularity)
  145.                 {
  146.                     InterpolateBetweenPoints(xtrg, xtrg + z_pix * granularity, granularity, z_pix);
  147.                 }
  148.  
  149.  
  150.         }
  151.         void InterpolateBetweenPoints(int startIndex, int stopIndex, int granularity, int stride)
  152.         {
  153.             var delta = new double[3];
  154.             for (int i = 0; i < 3; i++) delta[i] = z_val[stopIndex + i] - z_val[startIndex + i];
  155.             double dist = 1;
  156.             for (int i = startIndex + stride; i < stopIndex; i += stride, dist++)
  157.             {
  158.                 var d = dist / (double)granularity;
  159.                 for (int j = 0; j < 3; j++)
  160.                     z_val[i + j] = (byte)(z_val[startIndex + j] + delta[j] * d);
  161.                 z_val[i + 3] = z_val[startIndex + 3];
  162.             }
  163.         }
  164.     }
  165.     /// <summary>
  166.     /// Biquadratic transformation
  167.     /// <code>
  168.     /// s - point in a bitmap
  169.     /// t - point on the globe
  170.     ///
  171.     /// s =a+ b*x + c*y + d*x*x + e*x*y + f*y*y
  172.     /// s =a[0]+ a[1]*t.x + a[2]*t.y + a[3]*t.x*t.x + a[4]*t.x*t.y + a[5]*t.y*t.y
  173.     /// </code>
  174.     /// </summary>
  175.     [Serializable]
  176.     public class Biquadratic
  177.     {
  178.         BiquadraticOneDim xBiq, yBiq;
  179.  
  180.         /// <summary>
  181.         /// Calculates coefficients for entire transformation
  182.         /// </summary>
  183.         /// <param name="point">Callibration points</param>
  184.         public Biquadratic(List<Point> src, List<Point> trg)
  185.            xBiq = new BiquadraticOneDim(true, src, trg);
  186.             yBiq = new BiquadraticOneDim(false, src, trg);
  187.  
  188.         }
  189.         /// <summary>
  190.         /// Formal validation
  191.         /// </summary>
  192.         public bool ok { get { return xBiq.ok && yBiq.ok; } }
  193.         /// <summary>
  194.         /// Debug string
  195.         /// </summary>
  196.         /// <returns>Debug string</returns>
  197.         public override string ToString()
  198.         {
  199.             return string.Format("{0} {1}", xBiq, yBiq);
  200.         }
  201.         /// <summary>
  202.         /// Transformed value
  203.         /// </summary>
  204.         /// <param name="src">point to transform</param>
  205.         /// <returns>Transformed value</returns>
  206.         public PointF FloatVal(PointF src)
  207.         {
  208.             return new PointF((float)xBiq.Fval(src), (float)yBiq.Fval(src));
  209.         }
  210.         /// <summary>
  211.         /// Transformed value
  212.         /// </summary>
  213.         /// <param name="i">x bitmap coordinate</param>
  214.         /// <param name="j">y bitmap coordinate</param>
  215.         /// <returns>Transformed value converted to integer point</returns>
  216.         public Point IntVal(int i, int j)
  217.         {
  218.             PointF src = new PointF(i, j);
  219.             return new Point((int)xBiq.Fval(src), (int)yBiq.Fval(src));
  220.         }
  221.         /// <summary>
  222.         /// Backward transformation
  223.         /// </summary>
  224.         /// <param name="i">x bitmap coordinate</param>
  225.         /// <param name="j">y bitmap coordinate</param>
  226.         /// <returns>Transformed value converted to integer point</returns>
  227.         public Point InvIntVal(int i, int j)
  228.         {
  229.             PointF src = new PointF(i, j);
  230.             return new Point((int)xBiq.Bval(src), (int)yBiq.Bval(src));
  231.         }
  232.     }
  233.  
  234.     /// <summary>
  235.     /// Transformation in one dimension
  236.     /// </summary>
  237.     [Serializable]
  238.     public class BiquadraticOneDim
  239.     {
  240.         double[] a, b;
  241.         /// <summary>
  242.         /// Calculates cofficients for one dimension
  243.         /// </summary>
  244.         /// <param name="isX">Dimension to calculate</param>
  245.         /// <param name="point">Callibration points</param>
  246.         /// <remarks><code>
  247.         ///  Biquardatic interpolation, val=a+ b*x + c*y + d*x*x + e*x*y + f*y*y
  248.         ///       a       b      c      d      e      f
  249.         ///           --------------------------------------
  250.         ///     | 1       x      y    x*x    x*y    y*y  |   | a  |       |  v  |
  251.         ///     | 1       x      y    x*x    x*y    y*y  |   | b  |       |  v  |
  252.         ///     | 1       x      y    x*x    x*y    y*y  |   | c  |       |  v  |
  253.         ///     | 1       x      y    x*x    x*y    y*y  | * | d  |   =   |  v  |
  254.         ///     | 1       x      y    x*x    x*y    y*y  |   | e  |       |  v  |
  255.         ///     | 1       x      y    x*x    x*y    y*y  |   | f  |       |  v  |
  256.         ///    
  257.         ///      M * B = R
  258.         ///      U * S * Vt    *  B =  R
  259.         ///      B =  V * 1/S  * Ut  * R
  260.         /// </code></remarks>
  261.         public BiquadraticOneDim(bool isX, List<Point> src, List<Point> trg)
  262.         {
  263.             if (src.Count != trg.Count) throw new Exception(string.Format("BiquadraticOneDim dimension discrepancy {0} vs. {1}", src.Count, trg.Count));
  264.             a = new double[6];
  265.             b = new double[6];
  266.             if (src != null && src.Count > 5)
  267.             {
  268.                 a = Solve(isX, src, trg);
  269.                 b = Solve(isX, trg, src);
  270.             }
  271.             else
  272.             {
  273.                 if (isX) { a[1] = 1.0; b[1] = 1.0; }
  274.                 else { a[2] = 1.0; b[2] = 1.0; }
  275.             }
  276.  
  277.         }
  278.         /// <summary>
  279.         /// Formal validation
  280.         /// </summary>
  281.         public bool ok { get { return !double.IsNaN(a[0]); } }
  282.         // double[] Solve(bool isX, List<CalibrationPoint> point, bool fwd)
  283.         double[] Solve(bool isX, List<Point> src, List<Point> trg)
  284.         {
  285.             int i, m = src.Count;
  286.             GeneralMatrix M = new GeneralMatrix(m, 6, 0.0);
  287.             GeneralMatrix R = new GeneralMatrix(m, 1, 0.0);
  288.             for (i = 0; i < m; i++)
  289.             {
  290.                 // point on the globe bitmap
  291.                 Point lhs = trg[i];
  292.                 Point rhs = src[i];
  293.                 double x = lhs.X;
  294.                 double y = lhs.Y;
  295.                 M.Array[i][0] = 1.0;
  296.                 M.Array[i][1] = x;
  297.                 M.Array[i][2] = y;
  298.                 M.Array[i][3] = x * x;
  299.                 M.Array[i][4] = x * y;
  300.                 M.Array[i][5] = y * y;
  301.  
  302.                 // point in source bitmap
  303.                 R.Array[i][0] = isX ? rhs.X : rhs.Y;
  304.             }
  305.  
  306.             SingularValueDecomposition svd = M.SVD();
  307.             GeneralMatrix u = svd.GetU();
  308.             GeneralMatrix v = svd.GetV();
  309.             //GeneralMatrix l = svd.S;
  310.             GeneralMatrix s = new GeneralMatrix(6, 6, 0.0);
  311.             for (i = 0; i < 6; i++)
  312.             {
  313.                 s.Array[i][i] = 1.0 / svd.S.Array[i][i];
  314.             }
  315.             GeneralMatrix m1 = v * s;
  316.             GeneralMatrix m2 = m1 * u.Transpose();
  317.             GeneralMatrix B = svd.GetV() * s * svd.GetU().Transpose() * R;
  318.             double[] mtx = new double[6];
  319.             for (i = 0; i < 6; i++)
  320.             {
  321.                 mtx[i] = B.Array[i][0];
  322.             }
  323.             return mtx;
  324.         }
  325.         public override string ToString()
  326.         {
  327.             return string.Format("{0}, {1}, {2}, {3}, {4}, {5}", a[0], a[1], a[2], a[3], a[4], a[5]);
  328.         }
  329.         /// <summary>
  330.         /// Forward transformation
  331.         /// </summary>
  332.         /// <param name="t">Source point</param>
  333.         /// <returns>Transformed value</returns>
  334.         public double Fval(PointF t)
  335.         {
  336.             return a[0] + a[1] * t.X + a[2] * t.Y + a[3] * t.X * t.X + a[4] * t.X * t.Y + a[5] * t.Y * t.Y;
  337.         }
  338.         /// <summary>
  339.         /// Backwardtransformation
  340.         /// </summary>
  341.         /// <param name="t">Source point</param>
  342.         /// <returns>Transformed value</returns>
  343.         public double Bval(PointF t)
  344.         {
  345.             return b[0] + b[1] * t.X + b[2] * t.Y + b[3] * t.X * t.X + b[4] * t.X * t.Y + b[5] * t.Y * t.Y;
  346.         }
  347.     }
  348.  
  349. }
  350.  
  351.  
  352.  

A teď si dám kafe a jdu si napsat svůj vlastní driver na tiskárnu :)))

To je slabomyslna demagogie. Rozdil ve specifikaci funkcnosti i v kvalite cilovych uzivatelu takovou dusevni zkratku vylucuje.

Nyní jenom nezbývá než doufat, že slunéčko naše jasné, moderátor tohoto fóra,  nejvyšší osvícenost hlavní moderátor, a jeho všemocnost majitel fóra budou příznivě naloženi. Dojdou-li totiž k názoru, že publikovaná odpoveď je lepší než na jakou by se zmohlo slunéčko naše jasné moderátor tohoto fóra, nebo se nejvyšší osvícenost hlavní moderátor bude cítit ohrožen na mravnosti nestandardním slovem a nebo jeho všemocnost majitel fóra nebude spokojena s percepcí jeho fóra, tak ten příspěvek smažou.


Zdravim

TC
« Poslední změna: 24-07-2012, 09:34:28 od TC »

 

S rychlou odpovědí můžete používat BB kódy a emotikony jako v běžném okně pro odpověď, ale daleko rychleji.

Upozornění: do tohoto tématu bylo naposledy přispěno před 120 dny.
Zvažte prosím založení nového tématu.

Jméno: E-mail:
Ověření:
Kolik je šest plus čtyři (slovem):