how can I add more convex hulls in one picture - c#

i'm doing homework in Visual Studio 2017.
I have to create a convex hull and then add more convex hulls to it, without changing others. So I find out how to make one convex hull but I don't know how to add more in this code. I have to create new botton (Add convex hull) in a code and then I don't know how to continue.
Thank you for all your answers.
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
Point zacasna = new Point();
zacasna.X = e.X;
zacasna.Y = e.Y;
seznamTock.Add(zacasna);
pictureBox1.Image = Image.FromFile(file);
using (var g = Graphics.FromImage(pictureBox1.Image))
{
for (int i = 0; i < seznamTock.Count; i++)
{
g.DrawEllipse(barva_tock, seznamTock[i].X, seznamTock[i].Y,
5, 5);
}
pictureBox1.Refresh();
}
}
private List<Point> konveksnaLupina(List<Point> tocka)
{
List<Point> hull = new List<Point>();
Point vPointOnHull = tocka.Where(p => p.X == tocka.Min(min =>
min.X)).First();
Point vEndpoint;
do
{
hull.Add(vPointOnHull);
vEndpoint = tocka[0];
for (int i = 1; i < tocka.Count; i++)
{
if ((vPointOnHull == vEndpoint)
|| (Orientacija(vPointOnHull, vEndpoint, tocka[i]) ==
-1))
{
vEndpoint = tocka[i];
}
}
vPointOnHull = vEndpoint;
}
while (vEndpoint != hull[0]);
return hull;
}
private static int Orientacija(Point p1, Point p2, Point p)
{
// Determinanta
int Orin = (p2.X - p1.X) * (p.Y - p1.Y) - (p.X - p1.X) * (p2.Y -
p1.Y);
if (Orin > 0)
{
return -1; //orientacija v levo
}
if (Orin < 0)
{
return 1; //orientacija v desno
}
return 0; //neutralna orientacija
}
private void button2_Click(object sender, EventArgs e)
{
if (seznamTock.Count < 3)
{
MessageBox.Show("Premalo tock!");
return;
}
List<Point> hull = new List<Point>();
hull = konveksnaLupina(seznamTock);
pictureBox1.Image = Image.FromFile(file);
using (var g = Graphics.FromImage(pictureBox1.Image))
{
for (int j = 0; j < seznamTock.Count; j++)
{
g.DrawEllipse(barva_tock, seznamTock[j].X, seznamTock[j].Y,
5, 5);
}
for (int j = 0; j < hull.Count; j++)
{
Point tocka1 = new Point(hull[j].X, hull[j].Y);
Point tocka2 = new Point(hull[(j + 1) % hull.Count].X,
hull[(j + 1) % hull.Count].Y);
g.DrawLine(barva_kon_lupine, tocka1, tocka2);
}
for (int j = 0; j < hull.Count; j++)
{
g.DrawEllipse(barva_tock_kon_lupine, hull[j].X, hull[j].Y,
`enter code here`5, 5);
}
pictureBox1.Refresh();
}
}
}

add new points in to the new list, but without changing previous figure
You are thinking List<Point> is figure. Well, it's not. It's a list of points. Figures may have more properties and if you have several figures stored as array of points - how would you know which point belong to which figure?
OOP can make it more clear:
abstract class Figure
{
public abstract void Draw(Graphics graphics);
}
class Convex: Figure
{
public List<Point> Points { get; set; }
public Color Color { get; set; } = Color.Black;
... // more properties
public override void Draw(Graphics graphics)
{
if(Points != null)
using(var pen = new Pen(Color))
graphics.DrawLines(pen, Points.ToArray());
}
}
... // more figures
You can hold different figures in List<Figure> and simply add new figure to it:
class Billboard
{
public List<Figure> Figures { get; } = new List<Figure>();
public void Add(Figure figure) => Figures.Add(figure);
... // more methods
}
Redraw:
Billboard _billboard = new Billboard();
void pictureBox1_Paint(object sender, PaintEventArgs e)
{
foreach(var figure in _billboard.Figures)
figure.Draw(e.Graphics);
}

I like Sinatrs approach. But, here's an alternative, just using a collection and your existing code. It's not, the best mod. Think, it does what you want.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
Collection<List<Point>> test = new Collection<List<Point>>();
List<Point> seznamTock = new List<Point>();
Pen barva_tock = new Pen(Color.Blue);
Pen barva_kon_lupine = new Pen(Color.Black);
Pen barva_tock_kon_lupine = new Pen(Color.Yellow);
public Form1()
{
InitializeComponent();
test.Add(seznamTock);
}
private List<Point> konveksnaLupina(List<Point> tocka)
{
List<Point> hull = new List<Point>();
Point vPointOnHull = tocka.Where(p => p.X == tocka.Min(min =>
min.X)).First();
Point vEndpoint;
do
{
hull.Add(vPointOnHull);
vEndpoint = tocka[0];
for (int i = 1; i < tocka.Count; i++)
{
if ((vPointOnHull == vEndpoint)
|| (Orientacija(vPointOnHull, vEndpoint, tocka[i]) ==
-1))
{
vEndpoint = tocka[i];
}
}
vPointOnHull = vEndpoint;
}
while (vEndpoint != hull[0]);
return hull;
}
private static int Orientacija(Point p1, Point p2, Point p)
{
// Determinanta
int Orin = (p2.X - p1.X) * (p.Y - p1.Y) - (p.X - p1.X) * (p2.Y - p1.Y);
return (Orin == 0) ? Orin : ((Orin > 0) ? -1 : 1);
//if (Orin > 0)
//{
// return -1; //orientacija v levo
//}
//if (Orin < 0)
//{
// return 1; //orientacija v desno
//}
//return 0; //neutralna orientacija
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
Point zacasna = new Point();
zacasna.X = e.X;
zacasna.Y = e.Y;
seznamTock.Add(zacasna);
//pictureBox1.Image = Image.FromFile(file);
using (var g = Graphics.FromImage(pictureBox1.Image))
{
for (int i = 0; i < seznamTock.Count; i++) { g.DrawEllipse(barva_tock, seznamTock[i].X, seznamTock[i].Y, 5, 5); }
pictureBox1.Refresh();
}
}
private void button1_Click(object sender, EventArgs e)
{
//if (seznamTock.Count < 3)
//{
// MessageBox.Show("Premalo tock!");
// return;
//}
List<Point> hull = new List<Point>();
hull = konveksnaLupina(seznamTock);
//pictureBox1.Image = Image.FromFile(file);
using (var g = Graphics.FromImage(pictureBox1.Image))
{
for (int j = 0; j < seznamTock.Count; j++)
{
g.DrawEllipse(barva_tock, seznamTock[j].X, seznamTock[j].Y,
5, 5);
}
for (int j = 0; j < hull.Count; j++)
{
Point tocka1 = new Point(hull[j].X, hull[j].Y);
Point tocka2 = new Point(hull[(j + 1) % hull.Count].X,
hull[(j + 1) % hull.Count].Y);
g.DrawLine(barva_kon_lupine, tocka1, tocka2);
}
for (int j = 0; j < hull.Count; j++)
{
g.DrawEllipse(barva_tock_kon_lupine, hull[j].X, hull[j].Y, 5, 5);
}
pictureBox1.Refresh();
test.Add(seznamTock);
seznamTock = new List<Point>();
}
}
}
}

Related

C# OutOfRangeException that should be impossible

I am so confessed right now I don't even know how to properly form this question.
I have some code (as shown below) that is run on a different thread with the variable i not being referenced anywhere else that could interfere with it here. I just don't understand what is happening to cause this error, I put some watchers down with visual studio code and the values all seem to be fine and in range but almost randomly out of nowhere I will get this error.
Is it possible that this is caused by another section of code despite to my best knowledge being completely isolated from it? I even went as far to rename all other uses of i to different letters and I still get this problem.
Is it just something with for loops?
Am I somehow modifying i without even know it?
I just don't even know what to ask.
Here is the full code
`
using SFML.Graphics;
using SFML.Window;
using System.Diagnostics;
using System.Numerics;
namespace RenderEngine
{
public class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
PhysicsEngine re = new PhysicsEngine();
for (int i = 0; i < 100; i++)
{
Debug.WriteLine(i);
}
}
}
public class PhysicsEngine
{
Solver solver = new Solver();
public void RenderEngine2()
{
ContextSettings settings = new ContextSettings();
settings.AntialiasingLevel = 8;
RenderWindow window = new RenderWindow(new VideoMode(2000, 1000), "Poop", Styles.Default, settings);
SFML.Graphics.Color color = new SFML.Graphics.Color(0, 0, 0, 0);
window.SetVerticalSyncEnabled(true);
CircleShape shape = new CircleShape(5);
shape.FillColor = new SFML.Graphics.Color(0, 0, 255, 255);
window.Closed += handelclose;
int drawcount = 0;
while (window.IsOpen)
{
window.Clear(color);
window.DispatchEvents();
try
{
foreach (Partical partical in solver.Particals)
{
shape.Position = new SFML.System.Vector2f((partical.position.X), (partical.position.Y));
window.Draw(shape);
drawcount++;
}
drawcount = 0;
}
catch
{
Debug.WriteLine("notready yet");
}
window.Display();
}
void handelclose(object sender, EventArgs e)
{
window.Close();
Environment.Exit(Environment.ExitCode);
}
}
List<Partical> todraw = new List<Partical>();
void EngineLoop()
{
while (true)
{
foreach (Partical partical in solver.Particals)
{
int x = (int)Math.Round(partical.position.X/10);
int y = (int)Math.Round(partical.position.Y/10);
List<int> ts = solver.Grid[x, y];
if (ts != null)
{
for (int brokenint = 0; brokenint < ts.Count; brokenint++)
{
Debug.WriteLine(partical.ID);
Debug.WriteLine(ts[brokenint]);
if (partical.ID != ts[brokenint])
{
Vector2 pos = new Vector2(partical.ID, ts[brokenint]);
if (solver.Collision.Count > 0)
{
if (!solver.Collision.Contains(pos))
solver.Collision.Add(pos);
}
else
{
solver.Collision.Add(pos);
}
}
}
}
}
}
}
private int particalcount = 10;
bool canstart = false;
public PhysicsEngine()
{
Parallel.Invoke(() =>
{
while (!canstart) { Thread.Sleep(100); }
Debug.WriteLine("third thread");
RenderEngine2();
},
() =>
{
while (!canstart) { Thread.Sleep(100); }
Debug.WriteLine("engine started");
EngineLoop();
},
() =>
{
Debug.WriteLine("first thread");
PhysicsLoop(this);
}
);
}
void PhysicsLoop(PhysicsEngine PhyEng)
{
int frames = 0;
long second = 0;
PhysicsStart(PhyEng);
Thread.Sleep(1000);
Stopwatch sw = Stopwatch.StartNew();
solver.startupdate();
while (true)
{
sw.Start();
todraw = solver.Particals;
solver.update();
frames++;
if (second != (Stopwatch.GetTimestamp() / Stopwatch.Frequency))
{
second = (Stopwatch.GetTimestamp() / Stopwatch.Frequency);
Debug.WriteLine(frames);
frames = 0;
}
sw.Stop();
sw.Reset();
if (sw.ElapsedMilliseconds < 15)
Thread.Sleep(15 - (int)sw.ElapsedMilliseconds);
}
}
void PhysicsStart(PhysicsEngine phyeng)
{
for (int i = 0; i < 210; i++)
{
for (int j = 0; j < 110; j++)
{
solver.Grid[i,j] = new List<int>();
}
}
Random rand = new Random();
for (int i = 0; i < particalcount; i++)
{
Partical partical = new Partical();
partical.position = new Vector2(rand.Next(0, 2000), rand.Next(0, 1000));
partical.oldposition = partical.position;
partical.ID = i;
int x1 = (int)Math.Round((partical.position.X + 5) / 10);
int y1 = (int)Math.Round((partical.position.Y + 5) / 10);
int x2 = (int)Math.Round((partical.position.X - 5) / 10);
int y2 = (int)Math.Round((partical.position.Y - 5) / 10);
solver.Grid[x1, y1].Add(partical.ID);
solver.Grid[x2, y1].Add(partical.ID);
solver.Grid[x1, y2].Add(partical.ID);
solver.Grid[x2, y2].Add(partical.ID);
solver.Particals.Add(partical);
}
canstart = true;
}
}
public class Partical
{
public Vector2 position = new Vector2(0, 0);
public Vector2 oldposition = new Vector2(0, 0);
public Vector2 acceleration = new Vector2(0, 0);
Vector2 zero = new Vector2(0, 0);
public int ID = new int();
public void updatePosition(float sub)
{
Vector2 velocity = position - oldposition;
oldposition = position;
position = position + (velocity * 0.9f) + acceleration * sub;
acceleration = zero;
}
public void accelerate(Vector2 accel)
{
acceleration = acceleration + accel;
}
}
public class Solver
{
public List<Partical> Particals = new List<Partical>();
public List<Vector2> Collision = new List<Vector2>();
public List<int>[,] Grid = new List<int>[2100,1100];
public void update()
{
int subcount = 8;
float sub = 1f / (float)subcount;
for (int i = 0; i < subcount; i++)
{
applyGravity(sub);
updatePositions(sub);
for (int j = 0; j < Collision.Count; j++)
{
solvecolisions((int)Collision[j].X, (int)Collision[j].Y);
}
Collision.Clear();
}
}
public void startupdate()
{
applyGravity(0.5f);
updatePositions(0.5f);
applyGravity(0.5f);
updatePositions(0.5f);
}
void updatePositions(float sub)
{
foreach (Partical partical in Particals)
{
partical.updatePosition(sub);
int x1 = (int)Math.Round((partical.oldposition.X + 5) / 10);
int y1 = (int)Math.Round((partical.oldposition.Y + 5) / 10);
int x2 = (int)Math.Round((partical.oldposition.X - 5) / 10);
int y2 = (int)Math.Round((partical.oldposition.Y - 5) / 10);
Grid[x1,y1].Remove(partical.ID);
Grid[x2,y1].Remove(partical.ID);
Grid[x1,y2].Remove(partical.ID);
Grid[x2,y2].Remove(partical.ID);
x1 = (int)Math.Round((partical.position.X + 5) / 10);
y1 = (int)Math.Round((partical.position.Y + 5) / 10);
x2 = (int)Math.Round((partical.position.X - 5) / 10);
y2 = (int)Math.Round((partical.position.Y - 5) / 10);
Grid[x1,y1].Add(partical.ID);
Grid[x2,y1].Add(partical.ID);
Grid[x1,y2].Add(partical.ID);
Grid[x2,y2].Add(partical.ID);
}
}
void applyGravity(float sub)
{
float gravitystrangth = -0.1f;
foreach (Partical partical in Particals)
{
float a = partical.position.Y;
float b = partical.position.X;
b -= 1000;
a -= 500;
double angle = Math.Atan2(a, b);
float newA = gravitystrangth * (float)(Math.Sin(angle));
float newB = gravitystrangth * (float)(Math.Sin((Math.PI / 180) * 90 - angle));
Vector2 gravity = new Vector2(newB, newA);
partical.accelerate(gravity);
}
}
void solvecolisions(int id1, int id2)
{
Partical part = Particals[id1];
Partical part2 = Particals[id2];
if (part != part2)
{
Vector2 colisionaxis = part.position - part2.position;
float dist = colisionaxis.Length();
if (dist < 10)
{
Vector2 n = colisionaxis / dist;
float delta = 10 - dist;
part.position += 0.5f * delta * n;
part2.position -= 0.5f * delta * n;
}
}
}
public List<Partical> GetParticals()
{
return Particals;
}
}
}
`
You ts list depends on solver.Grid[x,y]. I am sure that some of your code that is not visible on the screen makes some changes of solver.Grid, probably deletes some times, or replaces them. This is what causing the error.

Zoom on Canvas in WPF C#

I implemented Canvas and ToolBar (in WPF C#) and vector graphics editor like Paint almost. I have a problem with the implementation of the Zoom. As I understand the Zoom:
0) I choose the tool ZoomTool;
1) I choose a point on Canvas;
2) I click on it and all the necessary work happens here :
1. Moving (shifting) the selected point to the center of Canvas;
2. Zoom in 2 times (as an example) relative to the center
The problem is the implementation of this work (shift and zoom in), how to do it?
enter image description here
This is my code:
class RecZoomTool : Tool
{
public RecZoomTool()
{
}
public override void MouseDown(Point mousePosition)
{
Point pointDirection = new Point(Creator.CanvasWidth / 2, Creator.CanvasHeight /2);
Creator.ShearingZoom(Point.Subtract(pointDirection, mousePosition));
Creator.Zooming(2);
}
}
then --->
public static void Zooming(double delta)
{
foreach (var figure in Figures)
{
for (int j = 0; j < figure.coordinates.Count; j++)
{
figure.coordinates[j] = new Point(
figure.coordinates[j].X * scaleZoom,
figure.coordinates[j].Y * scaleZoom
);
}
}
// scaleZoom += delta;
}
public static void ShearingZoom(Point dPoint, Point mPoint)
{
foreach (var figure in Figures)
{
Vector delta = Point.Subtract(mPoint, dPoint);
for (int j = 0; j < figure.coordinates.Count; j++)
{
figure.coordinates[j] = new Point(dPoint.X, dPoint.Y);
//counterZoom++;
//delta = Point.Subtract(figure.coordinates[j], dPoint);
figure.coordinates[j] = Point.Add(figure.coordinates[j], delta);
}
offsetPosition += delta;
}
}
Correct answer for every MouseClick:
public override void MouseDown(Point mousePosition)
{
double valueZoom = 2.0;
Point pointDirection = new Point(0.0, 0.0);
Creator.Shifting(Point.Subtract(pointDirection, mousePosition));
Creator.Zooming(valueZoom);
}
And there's in main class:
public static int scaleZoom = 2;
public static Vector offsetPosition = new Vector(0.0, 0.0);
public static int counterZoom = 0;
public static void Zooming(double scaleZoom)
{
foreach (var figure in Figures)
{
for (int j = 0; j < figure.coordinates.Count; j++)
{
figure.coordinates[j] = new Point(
figure.coordinates[j].X * scaleZoom,
figure.coordinates[j].Y * scaleZoom
);
}
}
}
public static void Shifting(Vector delta)
{
offsetPosition = delta / scaleZoom;
foreach (var figure in Figures)
{
for (int j = 0; j < figure.coordinates.Count; j++)
{
figure.coordinates[j] = Point.Add(figure.coordinates[j], offsetPosition);
}
}
}

how do I paint one of the check when user click mouse on it

I have something like chessboard, 21x21 checks, each of one have 10x10pixels. I have no idea how do I paint one of the check when user click mouse on it.
Probably i have to use arrays but i dont know how can I assign 10x10 pixels to one element of other array. Can i assign array wiht 100 elements to one elemnet of other array?
This is my code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace gotowa_mapa
{
public partial class Form1 : Form
{
Bitmap mapa;
private int szer_pb = 200;
private int wys_pb = 200;
private int ilosc_kratek_x = 41;
private int ilosc_kratek_y = 41;
// private void wpisanie_tablic()
//{
// int[,] tablica_kratki = new int[ilosc_kratek_x, ilosc_kratek_y];
// int[,] tablica_piksele = new int[szer_pb, wys_pb];
//for(int i=0;i<ilosc_kratek_x; i++)
// {
// for(int j=0; j<ilosc_kratek_y; j++)
//{
// tablica_kratki[ilosc_kratek_x, ilosc_kratek_y] = tablica_piksele[2,2];
//}
//}
//}
private void siatka1()
{
mapa = new Bitmap(szer_pb, wys_pb);
int factor_x = (int)(szer_pb / ilosc_kratek_x);
int factor_y = (int)(wys_pb / ilosc_kratek_y);
for (int i = 0; i < szer_pb; i++)
{
if (i > (factor_x * ilosc_kratek_x))
break;
for (int j = 0; j < wys_pb; j++)
{
if (j > (factor_y * ilosc_kratek_y))
break;
if (i % (factor_x) == 0 || j % (factor_y) == 0)
{
mapa.SetPixel(i, j, Color.Black);
mapa.SetPixel(j, i, Color.Black);
}
else
{
mapa.SetPixel(i, j, Color.White);
mapa.SetPixel(j, i, Color.White);
}
}
}
}
// private void rysowanie_scian(int x, int y)
// {
// }
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
siatka1();
pictureBox1.Image = mapa;
}
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
int x, y;
x = e.X;
y = e.Y;
MessageBox.Show(x + " " + y);
}
}
}
I've made an example for you, although there is probably better ways of doing this, using some simple math you can achieve this.
A neat trick is overriding the onPaint method of a panel, making a new Bitmap with the same size as the panel, drawing this image over the panel during the onPaint method, making changes directly to the image, then invalidating the panel so it draws the image. (You can then save the image with Bitmap.Save)
Keep in mind, if a game of some sort is what you are aiming for, GDI is not ideal, look into managed DirectX or similar.
//declare variables
public const int offset = 50;
public const int boardX = 10;
public const int boardY = 10;
public const int checkSize = 40;
int[] checks;
//set initial values for the checks array
if(checks == null)
{
checks = new int[boardX * boardY];
}
//start iterating through the array of checks
for (int i = 0; i < checks.Length; i++)
{
//if the check is empty (assuming you will use integers as identifiers for the pieces on the board)
if (checks[i] < 1)
{
//check if the check in array is odd number & paint odd numbers black on alternating rows
if (i % 2 != 0)
{
//check if row is odd
if (Math.Ceiling((double)(i + 1) / boardX) % 2 != 0)
{
drawCheck(Brushes.Black, e.Graphics, i);
}
else
{
drawCheck(Brushes.White, e.Graphics, i)
}
}
else
{
//check if row is odd
if (Math.Ceiling((double)(i+1) / boardX) % 2 != 0;
{
drawCheck(Brushes.White, e.Graphics, i);
}
else
{
drawCheck(Brushes.Black, e.Graphics, i)
}
}
}
else if (checks[i] == 1)
{
//the check is a "clicked check" - draw it red
drawCheck(Brushes.Red, e.Graphics, i);
}
}
//The Methods
private void YOURDRAWINGSURFACE_MouseClick(object sender, MouseEventArgs e)
{
if(e.X < (boardX * checkSize) + offset && e.Y < (boardY * checkSize) + offset && e.X > offset && e.Y > offset )
{
//you have clicked somewhere on the board. if that square isn't red, make it so, else turn it back to a normal square
if (checks[checkClicked(e.X, e.Y)] != 1)
{
checks[checkClicked(e.X, e.Y)] = 1;
}
else
{
checks[checkClicked(e.X, e.Y)] = 0;
}
}
//this is only relevant for GDI drawing code. It will invalidate the form to redraw the surface (needs to be called whenever you make a change)
this.Invalidate();
}
public int checkClicked(int mouseX, int mouseY)
{
//this method returns the int of the particular check that was clicked in the array.
return ((int)Math.Ceiling((double)(mouseX - offset) / checkSize) + (int)((Math.Ceiling((double)(mouseY - offset) / checkSize)) * boardX) - (1 + boardX));
}
public void drawCheck(Brush brush, Graphics graphics, int checkNumber)
{
//this method draws the check given the parameters.
graphics.FillRectangle(brush, ((checkNumber % boardX) * checkSize) + offset, (int)(Math.Ceiling((double)(checkNumber-(boardX-1)) / boardX) * checkSize) + offset, checkSize, checkSize);
}

Why do I get the error "NullReferenceException was unhandled"?

I am trying to make a slider puzzle game and I keep getting the error "NullReferenceException was unhandled" when I call myBoard.paint(e.Graphics) in my form1. Please help me!!!
Here is my code for Form1 (Let me know if I need to post some of my other classes code):
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
namespace SliderPuzzle
{
public partial class Form1 : Form
{
private int tileSize;
private int rowsCols;
private SlidePuzzle myBoard;
private Stopwatch timer;
private int moveCount;
public Form1()
{
InitializeComponent();
pictureBox1.TabIndex = 3;
pictureBox1.Size = new Size(100, 50);
pictureBox1.Location = new Point(16, 71);
pictureBox1.BackColor = Color.PaleGreen;
pictureBox1.BorderStyle = BorderStyle.Fixed3D;
pictureBox1.TabStop = false;
tileSize = imageList1.ImageSize.Width;
rowsCols = 3;
pictureBox1.Width = rowsCols * tileSize;
pictureBox1.Height = rowsCols * tileSize;
}
public void initGame()
{
myBoard = new SlidePuzzle(rowsCols, tileSize, imageList1);
timer = new Stopwatch();
moveCount = 0;
timer.Start();
}
private void Form1_Load(object sender, EventArgs e)
{
initGame();
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
this.myBoard.paint(e.Graphics);
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (myBoard.move(e.Y / tileSize, e.X / tileSize))
++moveCount;
Refresh();
if (!myBoard.winner())
return;
timer.Stop();
if (MessageBox.Show(string.Format("You won!!\nIt took you {0} moves and {1:F2} seconds.\nPlay again?", (object)moveCount, (object)timer.Elapsed.TotalSeconds), "Game Over", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.No)
{
Close();
}
else
{
initGame();
Refresh();
}
}
}
}
Update #1: Okay, so I moved myBoard = new SlidePuzzle(rowsCols, tileSize, imageList1); to my constructor, but now none of the images are showing up on it. Here is what It looks like vs what it is supposed to look like:
Edit #2: Okay, I moved it back to where it was before and put
if (this.myBoard != null)
this.myBoard.paint(e.Graphics);
instead, and it works a little better and looks better as well. But the images not showing up is still a problem.
Edit #3: Here is the SliderPuzzle.Paint Code:
public void paint(Graphics g)
{
for (int r = 0; r < this.myGrid.getNumRows(); ++r)
{
for (int c = 0; c < this.myGrid.getNumCols(); ++c)
this.myGrid.get(new Location(r, c)).paint(g);
}
}
Edit #4: Here is the code for the SliderPuzzle Class:
using System;
using System.Drawing;
using System.Windows.Forms;
namespace SliderPuzzle
{
internal class SlidePuzzle
{
private static Random rand = new Random();
private int myTileSize;
private BoundedGrid myGrid;
private ImageList myImages;
private Location myBlankLoc;
static SlidePuzzle()
{
}
public SlidePuzzle(int rowsCols, int tileSize, ImageList images)
{
this.myTileSize = tileSize;
this.myGrid = new BoundedGrid(rowsCols, rowsCols);
this.myImages = images;
this.myBlankLoc = new Location(rowsCols - 1, rowsCols - 1);
this.initBoard();
}
private void initBoard()
{
int index1 = 0;
for (int r = 0; r < this.myGrid.getNumRows(); ++r)
{
for (int c = 0; c < this.myGrid.getNumCols(); ++c)
{
this.myGrid.put(new Location(r, c), new Tile(index1, this.myTileSize, new Location(r, c), this.myImages.Images[index1]));
++index1;
}
}
for (int index2 = 0; index2 < 1000; ++index2)
{
Location adjacentLocation = this.myBlankLoc.getAdjacentLocation(SlidePuzzle.rand.Next(4) * 90);
if (this.myGrid.isValid(adjacentLocation))
{
this.swap(this.myBlankLoc, adjacentLocation);
this.myBlankLoc = adjacentLocation;
}
}
}
public bool move(int row, int col)
{
Location loc1 = new Location(row, col);
if (Math.Abs(this.myBlankLoc.getRow() - row) + Math.Abs(this.myBlankLoc.getCol() - col) != 1)
return false;
this.swap(loc1, this.myBlankLoc);
this.myBlankLoc = loc1;
return true;
}
public bool winner()
{
int num = 0;
for (int r = 0; r < this.myGrid.getNumRows(); ++r)
{
for (int c = 0; c < this.myGrid.getNumCols(); ++c)
{
if (this.myGrid.get(new Location(r, c)).getValue() != num)
return false;
++num;
}
}
return true;
}
private void swap(Location loc1, Location loc2)
{
Tile tile1 = this.myGrid.put(loc2, this.myGrid.get(loc1));
Tile tile2 = this.myGrid.put(loc1, tile1);
tile1.setLocation(loc1);
tile2.setLocation(loc2);
}
public void paint(Graphics g)
{
for (int r = 0; r < this.myGrid.getNumRows(); ++r)
{
for (int c = 0; c < this.myGrid.getNumCols(); ++c)
this.myGrid.get(new Location(r, c)).paint(g);
}
}
}
}
Update #5: Here is the Tile Class:
using System.Drawing;
namespace SliderPuzzle
{
internal class Tile
{
private int myValue;
private int mySize;
private Location myLoc;
private Image myImage;
public Tile(int value, int tileSize, Location loc, Image img)
{
this.myValue = value;
this.mySize = tileSize;
this.myLoc = loc;
this.myImage = img;
}
public int getValue()
{
return this.myValue;
}
public void setLocation(Location newLoc)
{
this.myLoc = newLoc;
}
public void paint(Graphics g)
{
g.DrawImage(this.myImage, this.myLoc.getCol() * this.mySize, this.myLoc.getRow() * this.mySize);
}
}
}
Edit #6: Here is the Location Class:
namespace SliderPuzzle
{
internal class Location
{
public const int LEFT = -90;
public const int RIGHT = 90;
public const int HALF_LEFT = -45;
public const int HALF_RIGHT = 45;
public const int FULL_CIRCLE = 360;
public const int HALF_CIRCLE = 180;
public const int AHEAD = 0;
public const int NORTH = 0;
public const int NORTHEAST = 45;
public const int EAST = 90;
public const int SOUTHEAST = 135;
public const int SOUTH = 180;
public const int SOUTHWEST = 225;
public const int WEST = 270;
public const int NORTHWEST = 315;
private int row;
private int col;
public Location(int r, int c)
{
this.row = r;
this.col = c;
}
public int getRow()
{
return this.row;
}
public int getCol()
{
return this.col;
}
public Location getAdjacentLocation(int direction)
{
int num1 = (direction + 22) % 360;
if (num1 < 0)
num1 += 360;
int num2 = num1 / 45 * 45;
int num3 = 0;
int num4 = 0;
if (num2 == 90)
num3 = 1;
else if (num2 == 135)
{
num3 = 1;
num4 = 1;
}
else if (num2 == 180)
num4 = 1;
else if (num2 == 225)
{
num3 = -1;
num4 = 1;
}
else if (num2 == 270)
num3 = -1;
else if (num2 == 315)
{
num3 = -1;
num4 = -1;
}
else if (num2 == 0)
num4 = -1;
else if (num2 == 45)
{
num3 = 1;
num4 = -1;
}
return new Location(this.getRow() + num4, this.getCol() + num3);
}
public bool equals(Location other)
{
if (this.getRow() == other.getRow())
return this.getCol() == other.getCol();
else
return false;
}
public int hashCode()
{
return this.getRow() * 3737 + this.getCol();
}
public int compareTo(Location otherLoc)
{
if (this.getRow() < otherLoc.getRow())
return -1;
if (this.getRow() > otherLoc.getRow())
return 1;
if (this.getCol() < otherLoc.getCol())
return -1;
return this.getCol() > otherLoc.getCol() ? 1 : 0;
}
public string toString()
{
return "(" + (object)this.getRow() + ", " + (string)(object)this.getCol() + ")";
}
}
}
Edit #7: Here is the last class, the BoundedGrid Class:
using System;
using System.Collections.Generic;
namespace SliderPuzzle
{
internal class BoundedGrid
{
private Tile[,] occupantArray;
public BoundedGrid(int rows, int cols)
{
this.occupantArray = new Tile[rows, cols];
}
public int getNumRows()
{
return this.occupantArray.GetLength(0);
}
public int getNumCols()
{
return this.occupantArray.GetLength(1);
}
public bool isValid(Location loc)
{
if (0 <= loc.getRow() && loc.getRow() < this.getNumRows() && 0 <= loc.getCol())
return loc.getCol() < this.getNumCols();
else
return false;
}
public List<Location> getOccupiedLocations()
{
List<Location> list = new List<Location>();
for (int r = 0; r < this.getNumRows(); ++r)
{
for (int c = 0; c < this.getNumCols(); ++c)
{
Location loc = new Location(r, c);
if (this.get(loc) != null)
list.Add(loc);
}
}
return list;
}
public Tile get(Location loc)
{
if (!this.isValid(loc))
throw new Exception("Location " + (object)loc + " is not valid");
else
return this.occupantArray[loc.getRow(), loc.getCol()];
}
public Tile put(Location loc, Tile obj)
{
if (!this.isValid(loc))
throw new Exception("Location " + (object)loc + " is not valid");
if (obj == null)
throw new NullReferenceException("obj == null");
Tile tile = this.get(loc);
this.occupantArray[loc.getRow(), loc.getCol()] = obj;
return tile;
}
public Tile remove(Location loc)
{
if (!this.isValid(loc))
throw new Exception("Location " + (object)loc + " is not valid");
Tile tile = this.get(loc);
this.occupantArray[loc.getRow(), loc.getCol()] = (Tile)null;
return tile;
}
}
}
Edit #8: When I click on the picturebox, the program crashes and it says the the timer.Stop(); in form1 gives me a NullReferenceException!!!
Edit #9: Okay, THAT worked... I have found that the images still do not show up, but I think that they are never being placed on the grid. When I click on the grid ( still has no images) It says that I have won. This should only display after I move the tiles into the correct order. Any idea what is going on?
Edit #10: My program finally works now! It turns out I had something missplaced in the constructor of form1, now everything works! The images show up and everything! How cool is that!!!
THANK YOU EVERYONE FOR YOU CONTRIBUTIONS, I WILL NOW GET A GREAT GRADE ON MY SCHOOL PROJECT!
This is one of those problems that will give you headaches. Trying to nail down the exact sequence of events is fine, when you can guarantee that the events are never going to be invoked out of sequence. Unfortunately the Paint event is one that gets fired at all sorts of odd times, any may be fired even before the Load event.
The only real answer is to never rely on events being fired in a particular sequence. Always check that your myBoard object is valid before trying to paint it:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (this.myBoard != null)
this.myBoard.paint(e.Graphics);
}
And yes, as others have noted, it is better to create all of your objects as soon as possible - in the constructor for instance, which is what a constructor is for after all. Even then, you can still get events being fired by actions in the constructor that will ruin your whole day. Your even handlers should be set as late as possible in the constructor code to account for this.
Rule(s) of thumb:
if you're creating custom objects that will be used in event handlers, always try to create and initialize them prior to calling InitializeComponent in the constructor.
Wire up your event handlers as late as possible, especially for things like Paint - it won't be useful before your constructor is done, so do it last in the constructor.
Your actual Form1_Load event never gets called (the one where you are initializing your board).
Add this code at the end of the Form1 constructor this.Load +=Form1_Load;
Your pictureBox1.Paint event is raised before your Form1.Load event. Move
myBoard = new SlidePuzzle(rowsCols, tileSize, imageList1);
to your constructor and you should be fine.

Hover is not working properly in windows form Drawing

here's my code,
private bool isMouseOverPin(int x, int y, Pin pin)
{
int left, top, right, bottom,size;
size=5;
left = pin.theRectangle.Left-size;
right = pin.theRectangle.Right + size;
top = pin.theRectangle.Top - size;
bottom = pin.theRectangle.Bottom + size;
if (x >= left && y >= top && x <= right && y <= bottom)
{
return true;
}
else
{
return false;
}
}
private void pinHover()
{
for (int i = 0; i < pins.Count; i++)
{
if (isMouseOverPin(Cursor.Position.X, Cursor.Position.Y, pins[i]) == true)
{
using (Graphics gr=canvas.CreateGraphics())
{
gr.DrawRectangle(10,10,10,10);
}
}
}
}
private void canvas_MouseMove(object sender, MouseEventArgs e)
{
pinHover();
}
i want when some one place a mouse over a pin it draws a rectangle, pin size is 5, i am unable to understand why its not working properly. help plz
I suspect that your pins location is relative to canvas instead of to screen.
You should pass e.Location from the MouseEventArgs to pinHover, or you could use PointToClient
e.g.
List<Int32> DrawPinRects;
private void initBuffer()
{
DrawPinRects = new List<Int32>();
}
private void pinHover(Point Position)
{
DrawPinRects.Clear();
for (int i = 0; i < pins.Count; i++)
{
if (isMouseOverPin(Position.X, Position.Y, pins[i]) == true)
{
DrawPinRects.Add(i);
}
}
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
pinHover(e.Location);
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
foreach(Int32 index in DrawPinRects)
{
Int32 y = panel1.VerticalScroll.Value + 10;
e.Graphics.DrawRectangle(Pens.Black, 10, y, 10, 10);
}
}
Also this:
int left, top, right, bottom,size;
size=5;
left = pin.theRectangle.Left-size;
right = pin.theRectangle.Right + size;
top = pin.theRectangle.Top - size;
bottom = pin.theRectangle.Bottom + size;
if (x >= left && y >= top && x <= right && y <= bottom)
can be simplified to
int size = 5;
Rectangle TestRect = pin.theRectangle;
TestRect.Inflate(size,size);
if (TestRect.Contains(x,y))
which will do the same thing.

Categories

Resources