I try to port simple game to silverlight (SameGame). The problem is that my old source code used pixel sizes to allight game marks to board. I draw simple grid using lines and game mark (using rectangle). How i can set rentacle position correctly?
Example 20 20 pixels to upper left corner).
private void DrawGrid()
{
LayoutRoot.Children.Clear();
Rectangle r = new Rectangle();
r.Width = 20;
r.Height = 20;
r.Fill = new SolidColorBrush(Color.FromArgb(255, 0, 255, 0));
r.Stroke = new SolidColorBrush(Color.FromArgb(255, 0, 255, 0));
r.SetValue(Canvas.LeftProperty, (double)0);
r.SetValue(Canvas.TopProperty, (double)0);
LayoutRoot.Children.Add(r);
Color GridColor = Color.FromArgb(0xFF, 0x00, 0x00, 0x00);
for (int y = 0; y < 11; y++)
{
Line l = new Line();
l.X1 = 0;
l.Y1 = 30 * y - 1;
l.X2 = 20 * 30;
l.Y2 = 30 * y - 1;
l.Stroke = new SolidColorBrush(GridColor);
l.StrokeThickness = 1;
LayoutRoot.Children.Add(l);
}
for (int x = 0; x < 21; x++)
{
Line l = new Line();
l.X1 = 30 * x;
l.Y1 = 0;
l.X2 = 30 * x;
l.Y2 = 10 * 30;
l.Stroke = new SolidColorBrush(GridColor);
l.StrokeThickness = 1;
LayoutRoot.Children.Add(l);
}
}
You need to put a Canvas below the LayoutRoot Grid or change LayoutRoot to a Canvas.
Then add the recangle to the Canvas.Children.
Related
How can I get x,y location of graph wher X and Y Axis starts (x,y location of point 0,0 in line chart)? This location is changable depending on text values on Y Axis probably.
Image is for illustrative purpose only.
How can I change the background color (currently is linear blue) of chart (I use PDFsharp NuGet package)?
Sample code:
ChartFrame chartFrame = new ChartFrame();
chartFrame.Location = new XPoint(xOffset, yLoc);
double chartHeight = Math.Min(250, (page.Height - yLoc - 10));
chartFrame.Size = new XSize((page.Width - (xOffset * 2)), chartHeight);
Chart chart = new Chart(ChartType.Line);
//chart.PlotArea.FillFormat.Color = XColor.FromArgb(255, 255, 255, 255); //plot background???
Series series = chart.SeriesCollection.AddSeries();
series.ChartType = ChartType.Line;
series.MarkerStyle = PdfSharp.Charting.MarkerStyle.None;
series.Name = "Horizontal"; //Series 1
series.MarkerBackgroundColor = XColor.FromArgb(255, 0, 0, 255); //blue
series.MarkerSize = 1;
series.Add(line1);
series = chart.SeriesCollection.AddSeries();
series.ChartType = ChartType.Line;
series.MarkerStyle = PdfSharp.Charting.MarkerStyle.None;
series.Name = "Vertical"; //Series 2
series.MarkerBackgroundColor = XColor.FromArgb(255, 0, 170, 0); //green
series.MarkerSize = 1;
series.Add(line2);
series = chart.SeriesCollection.AddSeries();
series.ChartType = ChartType.Line;
series.MarkerStyle = PdfSharp.Charting.MarkerStyle.None;
series.Name = "3D position"; //Series 3
series.MarkerBackgroundColor = XColor.FromArgb(255, 255, 0, 0); //red
series.MarkerSize = 1;
series.Add(line3);
chart.XAxis.MajorTickMark = TickMarkType.Outside;
chart.XAxis.Title.Caption = "No. Events"; //X-Axis
chart.YAxis.MajorTickMark = TickMarkType.Outside;
chart.YAxis.HasMajorGridlines = true;
double yOffset = ((maxYscale - minYscale) / 6);
if (yOffset < 0.01f)
yOffset = 0.01f;
chart.YAxis.MinimumScale = 0;
chart.YAxis.MaximumScale = Math.Round(Math.Round((maxYscale + yOffset), 3), 2);
double jump = Math.Round(yOffset, 2);
if (jump < 0.01f)
jump = 0.01f;
chart.YAxis.MajorTick = jump;
chart.YAxis.TickLabels.Format = "#0.00";
//chart.YAxis.HasMinorGridlines = true;
chart.YAxis.Title.Caption = "[m]"; //Y-Axis
chart.YAxis.HasMajorGridlines = true;
chart.PlotArea.LineFormat.Color = XColors.DarkGray;
chart.PlotArea.LineFormat.Width = 1;
chart.PlotArea.LineFormat.Visible = true;
chart.Legend.Docking = DockingType.Bottom;
chart.Legend.LineFormat.Visible = true;
XSeries xseries = chart.XValues.AddXSeries();
xseries.Add(eventLine);
chartFrame.Add(chart);
chartFrame.Draw(gfx);
Re:for X,Y location:
I made quick check for text length on YAxis and then according to that calculate new X,Y position.
Re: Background color:
These colours are hard-coded in the ChartFrame class (Draw method). So the nugget package for PDFSharp is not good you need to download the library source code.
Search for "XColor.FromArgb(0xFFD0DEEF)" and update the source code as needed.
I have an Bitmap with various color patterns and I need to find the bounding rectangles of one given color (For example: Red) within the Bitmap. I found some code to process images but unable to figure out how to achieve this.
Any help would be highly appreciated.
This is my code.
private void LockUnlockBitsExample(PaintEventArgs e)
{
// Create a new bitmap.
Bitmap bmp = new Bitmap("c:\\fakePhoto.jpg");
// Lock the bitmap's bits.
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
System.Drawing.Imaging.BitmapData bmpData =
bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
bmp.PixelFormat);
// Get the address of the first line.
IntPtr ptr = bmpData.Scan0;
// Declare an array to hold the bytes of the bitmap.
int bytes = Math.Abs(bmpData.Stride) * bmp.Height;
byte[] rgbValues = new byte[bytes];
// Copy the RGB values into the array.
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
// Set every third value to 255. A 24bpp bitmap will look red.
for (int counter = 2; counter < rgbValues.Length; counter += 3)
rgbValues[counter] = 255;
// Copy the RGB values back to the bitmap
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
// Unlock the bits.
bmp.UnlockBits(bmpData);
// Draw the modified image.
e.Graphics.DrawImage(bmp, 0, 150);
}
Edit: The Bitmap contains solid color shapes, multiple shapes with same color can appear. I need to find the bounding rectangle of each shape.
Just like the paint fills color with bucket tool, I need the bounding rectangle of the filled area.
I can provide x, y coordinates of point on Bitmap to find the bound rectangle of color.
You would do this just like any other code where you want to find the min or max value in a list. With the difference that you want to find both min and max in both X and Y dimensions. Ex:
public static Rectangle GetBounds(this Bitmap bmp, Color color)
{
int minX = int.MaxValue;
int minY = int.MaxValue;
int maxX = int.MinValue;
int maxY = int.MinValue;
for (int y = 0; y < bmp.Height; y++)
{
for (int x = 0; x < bmp.Width; x++)
{
var c = bmp.GetPixel(x, y);
if (color == c)
{
if (x < minX) minX = x;
if (x > maxX) maxX = x;
if (y < minY) minY = y;
if (y > maxY) maxY = y;
}
}
}
var width = maxX - minX;
var height = maxY - minY;
if (width <= 0 || height <= 0)
{
// Handle case where no color was found, or if color is a single row/column
return default;
}
return new Rectangle(minX, minY, width, height);
}
There are plenty of resources on how to use LockBits/pointers. So converting the code to use this instead of GetPixel is left as an exercise.
If you are not concerned with the performance, and an exact color match is enough for you, then just scan the bitmap:
var l = bmp.Width; var t = bmp.Height; var r = 0; var b = 0;
for (var i = 0; i<rgbValues.Length, i++)
{
if(rgbValues[i] == 255) // rgb representation of red;
{
l = Math.Min(l, i % bmpData.Stride); r = Math.Max(r, i % bmpData.Stride);
t = Math.Min(l, i / bmpData.Stride); b = Math.Max(b, i / bmpData.Stride);
}
}
if(l>=r) // at least one point is found
return new Rectangle(l, t, r-l+1, b-t+1);
else
return new Rectangle(0, 0, 0, 0); // nothing found
You can search for the first point of each shape that fills a different area on the Bitmap, read a single horizontal row to get the points of the given color, then loop vertically within the horizontal range to get the adjacent points.
Once you get all the points of each, you can calculate the bounding rectangle through the first and last points.
public static IEnumerable<Rectangle> GetColorRectangles(Bitmap src, Color color)
{
var rects = new List<Rectangle>();
var points = new List<Point>();
var srcRec = new Rectangle(0, 0, src.Width, src.Height);
var srcData = src.LockBits(srcRec, ImageLockMode.ReadOnly, src.PixelFormat);
var srcBuff = new byte[srcData.Stride * srcData.Height];
var pixSize = Image.GetPixelFormatSize(src.PixelFormat) / 8;
Marshal.Copy(srcData.Scan0, srcBuff, 0, srcBuff.Length);
src.UnlockBits(srcData);
Rectangle GetColorRectangle()
{
var curX = points.First().X;
var curY = points.First().Y + 1;
var maxX = points.Max(p => p.X);
for(var y = curY; y < src.Height; y++)
for(var x = curX; x <= maxX; x++)
{
var pos = (y * srcData.Stride) + (x * pixSize);
var blue = srcBuff[pos];
var green = srcBuff[pos + 1];
var red = srcBuff[pos + 2];
if (Color.FromArgb(red, green, blue).ToArgb().Equals(color.ToArgb()))
points.Add(new Point(x, y));
else
break;
}
var p1 = points.First();
var p2 = points.Last();
return new Rectangle(p1.X, p1.Y, p2.X - p1.X, p2.Y - p1.Y);
}
for (var y = 0; y < src.Height; y++)
{
for (var x = 0; x < src.Width; x++)
{
var pos = (y * srcData.Stride) + (x * pixSize);
var blue = srcBuff[pos];
var green = srcBuff[pos + 1];
var red = srcBuff[pos + 2];
if (Color.FromArgb(red, green, blue).ToArgb().Equals(color.ToArgb()))
{
var p = new Point(x, y);
if (!rects.Any(r => new Rectangle(r.X - 2, r.Y - 2,
r.Width + 4, r.Height + 4).Contains(p)))
points.Add(p);
}
}
if (points.Any())
{
var rect = GetColorRectangle();
rects.Add(rect);
points.Clear();
}
}
return rects;
}
Demo
private IEnumerable<Rectangle> shapesRects = Enumerable.Empty<Rectangle>();
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
var sx = 1f * pictureBox1.Width / pictureBox1.ClientSize.Width;
var sy = 1f * pictureBox1.Height / pictureBox1.ClientSize.Height;
var p = Point.Round(new PointF(e.X * sx, e.Y * sy));
var c = (pictureBox1.Image as Bitmap).GetPixel(p.X, p.Y);
shapesRects = GetColorRectangles(pictureBox1.Image as Bitmap, c);
pictureBox1.Invalidate();
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (shapesRects.Any())
using (var pen = new Pen(Color.Black, 2))
e.Graphics.DrawRectangles(pen, shapesRects.ToArray());
}
I want to create a 3D Graph in 4 quadrants form in C#.NET. For instant, I could do as shown below. If you see the corner of the chart begins with (-150, -200). I wish to start with (0,0) and the extend into 4 quadrant form.
Kindly enlighten me how can I transform this 3D graph in 4 quadrant form ?
Below is the corresponding code:
void prepare3dChart(Chart chart, ChartArea ca)
{
ca.Area3DStyle.Enable3D = true;
Series s = new Series();
chart.Series.Add(s);
s.ChartType = SeriesChartType.Bubble;
s.MarkerStyle = MarkerStyle.Diamond;
s["PixelPointWidth"] = "100";
s["PixelPointGapDepth"] = "1";
chart.ApplyPaletteColors();
addTestData(chart);
}
void addTestData(Chart chart)
{
Random rnd = new Random(9);
double x = 0, y = 0, z = 0;
for (int i = 0; i < 100; i++)
{
AddXY3d(chart.Series[0], x, y, z);
x = Math.Sin(i / 11f) * 88 + rnd.Next(3);
y = Math.Cos(i / 10f) * 88 + rnd.Next(5);
z = (Math.Sqrt(i * 2f) * 88 + rnd.Next(6));
}
}
int AddXY3d(Series s, double xVal, double yVal, double zVal)
{
int p = s.Points.AddXY(xVal, yVal, zVal);
s.Points[p].Color = Color.Transparent;
return p;
}
private void chart1_PostPaint(object sender, ChartPaintEventArgs e)
{
Chart chart = sender as Chart;
if (chart.Series.Count < 1) return;
if (chart.Series[0].Points.Count < 1) return;
ChartArea ca = chart.ChartAreas[0];
List<List<PointF>> data = new List<List<PointF>>();
foreach (Series s in chart.Series)
data.Add(GetPointsFrom3D(ca, s, s.Points.ToList(), e.ChartGraphics));
renderLines(data, e.ChartGraphics.Graphics, chart, true);
renderPoints(data, e.ChartGraphics.Graphics, chart, 6);
}
List<PointF> GetPointsFrom3D(ChartArea ca, Series s,
List<DataPoint> dPoints, ChartGraphics cg)
{
var p3t = dPoints.Select(x => new Point3D((float)ca.AxisX.ValueToPosition(x.XValue),
(float)ca.AxisY.ValueToPosition(x.YValues[0]),
(float)ca.AxisY.ValueToPosition(x.YValues[1]))).ToArray();
ca.TransformPoints(p3t.ToArray());
return p3t.Select(x => cg.GetAbsolutePoint(new PointF(x.X, x.Y))).ToList();
}
void renderLines(List<List<PointF>> data, Graphics graphics, Chart chart, bool curves)
{
for (int i = 0; i < chart.Series.Count; i++)
{
if (data[i].Count > 1)
using (Pen pen = new Pen(Color.FromArgb(64, chart.Series[i].Color), 2.5f))
if (curves) graphics.DrawCurve(pen, data[i].ToArray());
else graphics.DrawLines(pen, data[i].ToArray());
}
}
void renderPoints(List<List<PointF>> data, Graphics graphics, Chart chart, float width)
{
for (int s = 0; s < chart.Series.Count; s++)
{
Series S = chart.Series[s];
for (int p = 0; p < S.Points.Count; p++)
using (SolidBrush brush = new SolidBrush(Color.FromArgb(64, S.Color)))
graphics.FillEllipse(brush, data[s][p].X - width / 2,
data[s][p].Y - width / 2, width, width);
}
}
I want my 3D graph to have 4 quadrants like this:
Thanks #TaW. I got the code right.
void prepare3dChart(Chart chart, ChartArea ca)
{
ca.Area3DStyle.Enable3D = true;
ca.BackColor = Color.Transparent;
ca.AxisX.Minimum = -300;
ca.AxisX.Maximum = 300;
ca.AxisY.Minimum = -300;
ca.AxisY.Maximum = 300;
ca.AxisX.Crossing = 0; // move both axes..
ca.AxisY.Crossing = 0; // to the middle
ca.AxisX.Interval = 50;
ca.AxisY.Interval = 50;
ca.AxisX.MajorGrid.LineColor = Color.LightGray;
ca.AxisY.MajorGrid.LineColor = Color.LightGray;
chart.Series.Clear();
Series s = new Series();
chart.Series.Add(s);
s.ChartType = SeriesChartType.Bubble;
s.MarkerStyle = MarkerStyle.Diamond;
s["PixelPointWidth"] = "100";
s["PixelPointGapDepth"] = "1";
chart.ApplyPaletteColors();
addTestData(chart);
}
You can style the chart easily to look like this by moving both axes to the middle; this is done by setting their Crossings:
The code used is this:
ChartArea ca = chart1.ChartAreas[0];
ca.BackColor = Color.Transparent;
ca.AxisX.Minimum = -300;
ca.AxisX.Maximum = 300;
ca.AxisY.Minimum = -300;
ca.AxisY.Maximum = 300;
ca.AxisX.Crossing = 0; // move both axes..
ca.AxisY.Crossing = 0; // to the middle
ca.AxisX.Interval = 100;
ca.AxisY.Interval = 100;
ca.AxisX.MajorGrid.LineColor = Color.LightGray;
ca.AxisY.MajorGrid.LineColor = Color.LightGray;
Note that the real problem with MSChart in 3d-mode always remains the z-axis because there really isn't one. (If anybody is interested in how one can simulate it by having a lot of series see here. My example uses 32 series..)
You could draw it yourself, using the built-in function for the 3d conversions (TransformPoints) but this is a lot of tedious work, especially when it comes to labelling..
The updated code :
void prepare3dChart(Chart chart, ChartArea ca)
{
ca.Area3DStyle.Enable3D = true;
ca.BackColor = Color.Transparent;
ca.AxisX.Minimum = -300;
ca.AxisX.Maximum = 300;
ca.AxisY.Minimum = -300;
ca.AxisY.Maximum = 300;
ca.AxisX.Crossing = 0; // move both axes..
ca.AxisY.Crossing = 0; // to the middle
ca.AxisX.Interval = 50;
ca.AxisY.Interval = 50;
ca.AxisX.MajorGrid.LineColor = Color.LightGray;
ca.AxisY.MajorGrid.LineColor = Color.LightGray;
chart.Series.Clear();
Series s = new Series();
chart.Series.Add(s);
s.ChartType = SeriesChartType.Bubble;
s.MarkerStyle = MarkerStyle.Diamond;
s["PixelPointWidth"] = "100";
s["PixelPointGapDepth"] = "1";
chart.ApplyPaletteColors();
addTestData(chart);
}
How to optimise Canvas drawing in WPF, when i have 10000 Line like in program "Paint"? When I draw in "Paint" i can use how much I need lines and circles, but in my program agter +-10000 i have lags.
I create a test program with 10000 lines and when I move mouse on canvas rectangle is change position to a cursor.
here code
for (int i=0; i < 10000; i++)
{
Line l = new Line();
l.Stroke = Brushes.Black;
l.StrokeThickness = 1;
l.X1 = 50+ privi;
l.Y1 = 50 + privi;
l.X2 = 100 ;
l.Y2 = 100 + privi;
MainCanvas.Children.Add(l);
privi += 5;
}
and here i moving
if (clicked)
{
Point p = Mouse.GetPosition(MainCanvas);
rect.Margin = new Thickness(p.X-25, p.Y - 25, 0, 0);
}
enter code here
UPDATE
privi = 5;
Rectangle rect = new Rectangle();
rect.Fill = Brushes.Black;
rect.Width = 50;
rect.Height = 50;
MainCanvas.Children.Add(rect)
I don't know if you need lines and rect to be in the same canvas, otherwise I found that adding the rectangle in a second transparent canvas over the MainCanvas improves the reactivity.
<Window x:Class="WpfApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="1080" Width="1024">
<Canvas Name="MainCanvas" MouseMove="MainCanvas_MouseMove">
<Canvas Name="RectCanvas" Background="Transparent" MouseMove="RectCanvas_MouseMove">
</Canvas>
</Canvas>
</Window>
public partial class MainWindow : Window
{
double privi = 5;
Rectangle rect;
public MainWindow()
{
InitializeComponent();
for (int i = 0; i < 10000; i++)
{
Line l = new Line();
l.Stroke = Brushes.Black;
l.StrokeThickness = 1;
l.X1 = 50 + privi;
l.Y1 = 50 + privi;
l.X2 = 100;
l.Y2 = 100 + privi;
MainCanvas.Children.Add(l);
privi += 5;
}
rect = new Rectangle();
rect.Width = 50;
rect.Height = 50;
rect.Fill = Brushes.Black;
Canvas.SetLeft(rect, 0);
Canvas.SetTop(rect, 0);
SecondCanvas.Children.Add(rect);
}
private void RectCanvas_MouseMove(object sender, MouseEventArgs e)
{
//if (clicked)
{
Point p = Mouse.GetPosition(MainCanvas);
rect.Margin = new Thickness(p.X - 25, p.Y - 25, 0, 0);
}
}
}
Color[] brickcolor = new Color[] { Color.Red, Color.Orange, Color.Pink, Color.Purple, Color.Blue, Color.Green, Color.Honeydew, Color.Lavender };
for (int c = 0; c <= 10; c++)
{
for (int r = 0; r <= 8; r++)
{
Label bricks = new Label();
bricks.Location = new Point(x, y);
bricks = brickcolor;
bricks.Width = 90;
bricks.Height = 25;
pnlGame.Controls.Add(bricks);
y += 30;
}
}
for (int r = 0; r < 8; r++)
{
Label bricks = new Label();
bricks.Location = new Point(x, y);
bricks.BackColor = brickcolor[r]; //or bricks.ForeColor
bricks.Width = 90;
bricks.Height = 25;
pnlGame.Controls.Add(bricks);
y += 30;
}