Snapping drawn rectangles to each other - c#

I have a WPF application, wherein I draw rectangles in a canvas.I need to add a functionality in which when i draw a rectangle if there is a rectangle next to it (for eg: suppose first rectangle x coordinate is 236 and second rectangle coordinate is 235) i need to snap the second rectangle x coordinate to 236 as shown in the image.
The snap would be done only if the distance difference is 10.
I have written the following code to do this.
private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
startPos = e.GetPosition(Canvas);
System.Windows.Point curPosition = e.GetPosition(SectionCanvas);
rect = new System.Windows.Shapes.Rectangle
{
Stroke = brushColor,
StrokeDashArray = new DoubleCollection { 2, 2 },
Tag = "rectangle"
};
Canvas.SetLeft(rect, startPos.X);
Canvas.SetTop(rect, startPos.X);
SectionCanvas.Children.Add(rect);
}
private void Canvas_MouseMove(object sender, MouseEventArgs e)
{
currentPos = e.GetPosition(SectionCanvas);
var x = Math.Min(currentPos.X, startPos.X);
var y = Math.Min(currentPos.Y, startPos.Y);
var w = Math.Max(currentPos.X, startPos.X) - x;
var h = Math.Max(currentPos.Y, startPos.Y) - y;
rect.Width = w;
rect.Height = h;
Canvas.SetLeft(rect, x);
Canvas.SetTop(rect, y);
}
private void Canvas_MouseUp(object sender, MouseButtonEventArgs e)
{
if(rect == null)
{
MessageBox.Show("Could not capture section, Please try again");
return;
}
endPos = e.GetPosition(SectionCanvas);
IEnumerable<Rect> coordinates = rectCollection.Select(r => new Rect(Canvas.GetLeft(r), Canvas.GetTop(r), r.Width, r.Height));
Rect newCordinates = new Rect(Canvas.GetLeft(rect), Canvas.GetTop(rect), rect.Width, rect.Height);
if (coordinates.Any(c => c.IntersectsWith(newCordinates)))))
{
MessageBox.Show("New Rectangle intersects with existing rectangle");
Canvas.Children.Remove(rect);
return;
}
rectCollection.Add(rect);
rect = null;
foreach(Point p in tempCollection)
{
if((startPos.X <= (p.X + 10) && startPos.X >= (p.X -10)))
{
startPos.X = p.X;
}
if(endPos.X <= (p.X + 10) && endPos.X >= (p.X - 10))
{
var x1 = Math.Max(endPos.X,p.X) - Math.Min(endPos.X, p.X);
var w1 = startPos.X - x1;
endPos.X = p.X;
startPos.X = w1;
}
if ((startPos.Y <= (p.Y + 10) && startPos.Y >= (p.Y - 10)))
{
startPos.Y = p.Y;
}
if (endPos.Y <= (p.Y + 10) && endPos.Y >= (p.Y - 10))
{
var x1 = Math.Max(endPos.Y, p.Y) - Math.Min(endPos.Y, p.Y);
var w1 = startPos.Y - x1;
endPos.Y = p.Y;
}
}
var x = Math.Min(currentPos.X, startPos.X);
var y = Math.Min(currentPos.Y, startPos.Y);
var w = Math.Max(currentPos.X, startPos.X) - x;
var h = Math.Max(currentPos.Y, startPos.Y) - y;
rect.Width = w;
rect.Height = h;
rect.Stroke = Brushes.Coral;
Canvas.SetLeft(rect, x);
Canvas.SetTop(rect, y);
rect = null;
tempCollection.Add(startPos);
tempCollection.Add(endPos);
}
The above code doesnt work when I am changing the endpoints values. While debugging I can see that the end point value changes but the rectangle drawn doesn't change. I am not able to find out what I am doing wrong.

I figured out the answer which was a dumb mistake from my end.
While calculating the width and height after snapping, I am using currentPos, instead I should use endPos.
var x = Math.Min(endPos.X, startPos.X);
var y = Math.Min(endPos.Y, startPos.Y);
var w = Math.Max(endPos.X, startPos.X) - x;
var h = Math.Max(endPos.Y, startPos.Y) - y;

Related

Circle using Graphics.DrawLine()

I'm trying to make a circle using graphics.DrawLine() property and using BRESENHAM'S CIRCLE ALGORITHM but I'm not able to make it. Here is the method for making the circle
Pen pen = new Pen(Color.Red, 2);
Graphics graphics = this.Shape_PictureBox.CreateGraphics();
int radius = 40;
int x = 0, y = radius;
int xc = 50, yc = 50;
int d = 3 - 2 * radius;
// graphics.DrawLine(pen, xc, yc, x, y);
while (y >= x)
{
x++;
if (d > 0)
{
y--;
d = d + 4 * (x - y) + 10;
}
else
{
d = d + 4 * x + 6;
}
//drawCircle(xc, yc, x, y);
graphics.DrawLine(pen, xc, yc, x, y);
}
Well, there appears to be a bug in your algorithm implementation, as posted - but I suppose you're first and foremost asking as to why nothing is visible in the Shape_PictureBox? You should create a Bitmap buffer (think of it as a canvas) to draw to, and then assign it to the Shape_PictureBox.Image property.
IMPORTANT: Make sure to do this in the Form_Shown, not Form_Load event!
private void Child2_Shown(object sender, EventArgs e)
{
Pen pen = new Pen(Color.Red, 2);
Bitmap canvas = new Bitmap(Shape_PictureBox.Width, Shape_PictureBox.Height);
Graphics graphics = Graphics.FromImage(canvas);
int radius = 40;
int x = 0;
int y = radius;
int xc = 50;
int yc = 50;
int d = 3 - 2 * radius;
graphics.DrawLine(pen, xc, yc, x, y);
while (y >= x)
{
x++;
if (d > 0)
{
y--;
d = d + 4 * (x - y) + 10;
}
else
{
d = d + 4 * x + 6;
}
// drawCircle(xc, yc, x, y);
graphics.DrawLine(pen, xc, yc, x, y);
}
Shape_PictureBox.Image = canvas;
}
Currently, it looks like this:
You'll need to revise your implementation of Bresenham's Circle algorithm :)

Fractal renderer not displaying image at all?

I'm converting a fractal renderer from Java to C# for an assignment and I think I have everything set up but the fractal itself won't render.
This is a photo of when I run the program:
And here is how my files are laid out in the folder that contains the project itself:
This is the code that I am using for the actually rendering itself which I think has no errors but if I've missed something extremely obvious then I'm sorry for wasting all of your time:
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 WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
init();
start();
this.DoubleBuffered = true;
}
//code to convert HSB to RGB from HSB.cs. All your code so i made it take up less space.
public struct HSBColor
{
float h;
float s;
float b;
int a;
public HSBColor(float h, float s, float b) { this.a = 0xff; this.h = Math.Min(Math.Max(h, 0), 255); this.s = Math.Min(Math.Max(s, 0), 255); this.b = Math.Min(Math.Max(b, 0), 255); }
public HSBColor(int a, float h, float s, float b) { this.a = a; this.h = Math.Min(Math.Max(h, 0), 255); this.s = Math.Min(Math.Max(s, 0), 255); this.b = Math.Min(Math.Max(b, 0), 255); }
public float H { get { return h; } }
public float S { get { return s; } }
public float B { get { return b; } }
public int A { get { return a; } }
public Color Color { get { return FromHSB(this); } }
public static Color FromHSB(HSBColor hsbColor)
{
float r = hsbColor.b;
float g = hsbColor.b;
float b = hsbColor.b;
if (hsbColor.s != 0)
{
float max = hsbColor.b; float dif = hsbColor.b * hsbColor.s / 255f; float min = hsbColor.b - dif; float h = hsbColor.h * 360f / 255f;
if (h < 60f) { r = max; g = h * dif / 60f + min; b = min; }
else if (h < 120f) { r = -(h - 120f) * dif / 60f + min; g = max; b = min; }
else if (h < 180f) { r = min; g = max; b = (h - 120f) * dif / 60f + min; }
else if (h < 240f) { r = min; g = -(h - 240f) * dif / 60f + min; b = max; }
else if (h < 300f) { r = (h - 240f) * dif / 60f + min; g = min; b = max; }
else if (h <= 360f) { r = max; g = min; b = -(h - 360f) * dif / 60 + min; }
else { r = 0; g = 0; b = 0; }
}
return Color.FromArgb(hsbColor.a, (int)Math.Round(Math.Min(Math.Max(r, 0), 255)), (int)Math.Round(Math.Min(Math.Max(g, 0), 255)), (int)Math.Round(Math.Min(Math.Max(b, 0), 255)));
}
}
private const int MAX = 256; // max iterations
private const double SX = -2.025; // start value real
private const double SY = -1.125; // start value imaginary
private const double EX = 0.6; // end value real
private const double EY = 1.125; // end value imaginary
private static int x1, y1, xs, ys, xe, ye;
private static double xstart, ystart, xende, yende, xzoom, yzoom;
private static float xy;
private int c = 0;
//private Image picture; Taken out, not needed
// create rectangle variable JGB
Rectangle rec;
private Graphics g1;
//private Cursor c1, c2; Taken out, not needed
private System.Drawing.Bitmap bitmap;
public void init()
{
//setSize(640, 480); changed this code to JGB:
this.Size = new Size(640, 480);
// Taken all lines out below. Not needed.
/*finished = false;
addMouseListener(this);
addMouseMotionListener(this);
c1 = new Cursor(Cursor.WAIT_CURSOR);
c2 = new Cursor(Cursor.CROSSHAIR_CURSOR); */
x1 = 640;
y1 = 480;
xy = (float)x1 / (float)y1;
//picture = createImage(x1, y1); Taken out and replaced with JGB:
bitmap = new Bitmap(x1, y1);
//g1 = picture.getGraphics(); changed to get my bitmap
g1 = Graphics.FromImage(bitmap);
//finished = true; Finished variable deleted so not needed
}
//Code below didnt appear to do anything so i deleted it
/*public void destroy() // delete all instances
{
if (finished)
{
removeMouseListener(this);
removeMouseMotionListener(this);
picture = null;
g1 = null;
c1 = null;
c2 = null;
System.gc(); // garbage collection
}
} */
public void start()
{
//action = false;
//rectangle = false;
initvalues();
// added dialog box for instance loading and save varaibles needed for position and zoom to text file
DialogResult dialog = MessageBox.Show("Would You Like to Load Your Last Instance?", "Load Instance?", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
if (dialog == DialogResult.Yes)
{
string[] lines = System.IO.File.ReadAllLines(#"C:\Users\Public\Writelines.txt");
xzoom = System.Convert.ToDouble(lines[0]);
yzoom = System.Convert.ToDouble(lines[1]);
xstart = System.Convert.ToDouble(lines[2]);
ystart = System.Convert.ToDouble(lines[3]);
}
else
{
xzoom = (xende - xstart) / (double)x1;
yzoom = (yende - ystart) / (double)y1;
}
mandelbrot();
}
public void stop()
{
}
/*public void paint(Graphics g, PaintEventArgs e)
{
update(g);
}
public void update(Graphics g)
{
//g.DrawImage(picture, 0, 0);
}*/
private void mandelbrot()
{
int x, y;
float h, b, alt = 0.0f;
Color color;
Pen pen = new Pen(Color.Black);
for (x = 0; x < x1; x += 2)
for (y = 0; y < y1; y++)
{
h = pointcolour(xstart + xzoom * (double)x, ystart + yzoom * (double)y, c);
if (h != alt)
{
b = 1.0f - h * h;
color = HSBColor.FromHSB(new HSBColor(h * 255, 0.8f * 255, b * 255));
pen = new Pen(color);
alt = h;
}
g1.DrawLine(pen, x, y, x + 1, y);
}
}
private float pointcolour(double xwert, double ywert, int j)
{
double r = 0.0, i = 0.0, m = 0.0;
// int j = 0;
while ((j < MAX) && (m < 4.0))
{
j++;
m = r * r - i * i;
i = 2.0 * r * i + ywert;
r = m + xwert;
}
return (float)j / (float)MAX;
}
private void initvalues()
{
xstart = SX;
ystart = SY;
xende = EX;
yende = EY;
if ((float)((xende - xstart) / (yende - ystart)) != xy)
xstart = xende - (yende - ystart) * (double)xy;
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g1 = e.Graphics;
g1.DrawImage(bitmap, 0, 0, x1, y1);
using (Pen pen = new Pen(Color.White, 2))
{
e.Graphics.DrawRectangle(pen, rec);
}
Invalidate();
}
//added load method
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
xe = e.X;
ye = e.Y;
if (xs < xe)
{
if (ys < ye) rec = new Rectangle(xs, ys, (xe - xs), (ye - ys));
else rec = new Rectangle(xs, ye, (xe - xs), (ys - ye));
}
else
{
if (ys < ye) rec = new Rectangle(xe, ys, (xs - xe), (ye - ys));
else rec = new Rectangle(xe, ye, (xs - xe), (ys - ye));
}
this.Invalidate();
}
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
// e.consume();
xs = e.X;
ys = e.Y; // starting point y
this.Invalidate();
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
rec = new Rectangle(0, 0, 0, 0);
if (e.Button == MouseButtons.Left)
{
int z, w;
//e.consume();
//xe = e.X;
//ye = e.Y;
if (xs > xe)
{
z = xs;
xs = xe;
xe = z;
}
if (ys > ye)
{
z = ys;
ys = ye;
ye = z;
}
w = (xe - xs);
z = (ye - ys);
if ((w < 2) && (z < 2)) initvalues();
else
{
if (((float)w > (float)z * xy)) ye = (int)((float)ys + (float)w / xy);
else xe = (int)((float)xs + (float)z * xy);
xende = xstart + xzoom * (double)xe;
yende = ystart + yzoom * (double)ye;
xstart += xzoom * (double)xs;
ystart += yzoom * (double)ys;
}
xzoom = (xende - xstart) / (double)x1;
yzoom = (yende - ystart) / (double)y1;
mandelbrot();
string stringxzoom = xzoom.ToString();
string stringyzoom = yzoom.ToString();
string stringystart = ystart.ToString();
string stringxstart = xstart.ToString();
string[] lines = { stringxzoom, stringyzoom, stringxstart, stringystart };
System.IO.File.WriteAllLines(#"C:\Users\Public\Writelines.txt", lines);
this.Invalidate();
//Repaint();
}
}
private void restartToolStripMenuItem_Click(object sender, EventArgs e)
{
Application.Restart();
}
private void exitToolStripMenuItem1_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void menuToolStripMenuItem_Click(object sender, EventArgs e)
{
}
private void menuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
}
}
}
Change your Form1() code into these
InitializeComponent();
init();
start();
this.DoubleBuffered = true;
this.pictureBox1.Image = bitmap;
You took out the InitializeComponent call (which should be automatically generated) and you never set the resulting bitmap as the image of the pictureBox. Also, you might wanna set the picturebox Size mode to Zoom and enlarge it.

How can I scale my Windows forms chart using the mouse wheel?

I'm using windows forms chart control and this is the wheel mouse event:
void chart1_MouseWheel(object sender, MouseEventArgs e)
{
if (e.Delta < 0)
{
chart1.ChartAreas[0].AxisX.ScaleView.ZoomReset();
chart1.ChartAreas[0].AxisY.ScaleView.ZoomReset();
}
if (e.Delta > 0)
{
double xMin = chart1.ChartAreas[0].AxisX.ScaleView.ViewMinimum;
double xMax = chart1.ChartAreas[0].AxisX.ScaleView.ViewMaximum;
double yMin = chart1.ChartAreas[0].AxisY.ScaleView.ViewMinimum;
double yMax = chart1.ChartAreas[0].AxisY.ScaleView.ViewMaximum;
double posXStart = chart1.ChartAreas[0].AxisX.PixelPositionToValue(e.Location.X) - (xMax - xMin) / 4;
double posXFinish = chart1.ChartAreas[0].AxisX.PixelPositionToValue(e.Location.X) + (xMax - xMin) / 4;
double posYStart = chart1.ChartAreas[0].AxisY.PixelPositionToValue(e.Location.Y) - (yMax - yMin) / 4;
double posYFinish = chart1.ChartAreas[0].AxisY.PixelPositionToValue(e.Location.Y) + (yMax - yMin) / 4;
chart1.ChartAreas[0].AxisX.ScaleView.Zoom(posXStart, posXFinish);
chart1.ChartAreas[0].AxisY.ScaleView.Zoom(posYStart, posYFinish);
}
}
The problem is in the chart paint event when I draw points and connect them with lines when I use the wheel the points and lines are gone I don't think they are scaling right.
Pen pen = new Pen(Color.Blue, 2.5f);
SolidBrush myBrush = new SolidBrush(Color.Red);
private void chart1_Paint(object sender, PaintEventArgs e)
{
if (paintToCalaculate)
{
Series s = chart1.Series.FindByName("dummy");
if (s == null) s = chart1.Series.Add("dummy");
drawPoints.Clear();
s.Points.Clear();
foreach (PointF p in valuePoints)
{
s.Points.AddXY(p.X, p.Y);
DataPoint pt = s.Points[0];
double x = chart1.ChartAreas[0].AxisX.ValueToPixelPosition(pt.XValue);
double y = chart1.ChartAreas[0].AxisY.ValueToPixelPosition(pt.YValues[0]);
drawPoints.Add(new Point((int)x, (int)y));
s.Points.Clear();
}
paintToCalaculate = false;
chart1.Series.Remove(s);
}
foreach (Point p in drawPoints)
{
e.Graphics.FillEllipse(Brushes.Red, p.X - 2, p.Y - 2, 4, 4);
}
if (drawPoints.Count > 1)
{
e.Graphics.DrawLines(pen, drawPoints.ToArray());
}
}
How can I take care in the wheel mouse event also about the points and lines I draw in the paint event ?
I think you may need to set your 'paintToCalaculate' flag when zooming. It gets turned off during the first paint event and is not turned back on when zooming, so your lines are not being rescaled.

How to segmentation object c#

I used this code for segmentation, I'm trying to detect pixels one by one because my object is a binary, not a grayscale. when i run the program, it draws 2 object. The first object is successfully drawn (object still has a black color and a red rectangle), but the second object fails get drawn. Screenshot is here. Please help me, why does this happen?
#region Edge Detection
private void btnSegmentasi_Click(object sender, EventArgs e)
{
Segments = new List<ImageSegment>();
Bitmap bmp = (Bitmap)pb2.Image;
imageArea = new Rectangle(0, 0, pb2.Image.Width - 1, pb2.Image.Height - 1);
for (int y = 0; y < pb2.Image.Height; y++)
{
for (int x = 0; x < pb2.Image.Width; x++)
{
bool skip = false;
foreach (ImageSegment segment in Segments)
{
if (pointIsInRect(x, y, segment.Rect))
{
skip = true;
break;
}
}
if (skip) continue;
Color warna = bmp.GetPixel(x, y);
if (warna.G == 0)
startEdgeDetection(x, y, ref bmp);
}
}
DGVProses.DataSource = Segments;
if (Segments.Count > 0)
{
Graphics g = pb2.CreateGraphics();
Rectangle[] rects = (from theSegment in Segments select theSegment.Rect).ToArray();
g.DrawRectangles(new Pen(Brushes.Red), rects);
g.Dispose();
}
}
private void startEdgeDetection(int x, int y, ref Bitmap bmp)
{
Point startPoint = new Point(x, y);
Point currPoint = new Point(x, y);
int sudut = 180;
int xMin = x, yMin = y, xMax = x, yMax = y;
do
{
sudut -= 45;
Point offset = angleToPoint(ref sudut);
Point trialPoint = new Point(currPoint.X + offset.X, currPoint.Y + offset.Y);
if (!pointIsInRect(trialPoint.X, trialPoint.Y, imageArea))
continue;
Color theColor = bmp.GetPixel(trialPoint.X, trialPoint.Y);
if (theColor.G == 0)
{
currPoint = trialPoint;
sudut -= 180;
if (currPoint.X > xMax)
xMax = currPoint.X;
else if (currPoint.X < xMin)
xMin = currPoint.X;
if (currPoint.Y > yMax)
yMax = currPoint.Y;
else if (currPoint.Y < yMin)
yMin = currPoint.Y;
if (sudut < 0)
sudut += 360;
if (currPoint == startPoint && sudut == 180)
break;
}
}
while (!(currPoint == startPoint && sudut == 180));
Rectangle r = new Rectangle(xMin, yMin, xMax - xMin + 1, yMax - yMin + 1);
Bitmap newImage = new Bitmap(r.Width + 2, r.Height + 2);
using (Graphics g = Graphics.FromImage(newImage))
{
g.FillRectangle(Brushes.White, 0, 0, newImage.Width, newImage.Height);
g.DrawImage(bmp, new Rectangle(1, 1, r.Width, r.Height), r, GraphicsUnit.Pixel);
g.Dispose();
}
Segments.Add(new ImageSegment(r, newImage));
}
private Point angleToPoint(ref int sudut)
{
if (sudut < 0)
sudut += 360;
switch (sudut)
{
case 135: return new Point(-1, -1);
case 90: return new Point(0, -1);
case 45: return new Point(1, -1);
case 0: return new Point(1, 0);
case 315: return new Point(1, 1);
case 270: return new Point(0, 1);
case 225: return new Point(-1, 1);
default: return new Point(-1, 0);
}
}
private bool pointIsInRect(int x, int y, Rectangle rect)
{
if (x < rect.X)
return false;
if (x > rect.X + rect.Width)
return false;
if (x < rect.Y)
return false;
if (x > rect.Y + rect.Height)
return false;
return true;
}
#endregion
Okay, I think I've now got a clue of how your algorithm is supposed to work. I'd guess you are running around in circles within the object. I do not really know why it does not happen for the first object, but this is another story.
When you enter startEdgeDetection you start at some point, check if it's black, move by an angle and repeat the whole procedure. You stop when the current point reaches the starting point. The crux is, that this algorithm does not guarantee to walk the whole object, but may just do the following (I do not know it is exactly like this, but pretty much):
OOOOOO
O####O
O####O
OOOOOO
OOOOOO
O*###O
O####O
OOOOOO
OOOOOO
O**##O
O####O
OOOOOO
OOOOOO
O**##O
O#*##O
OOOOOO
OOOOOO
O**##O
O**##O
OOOOOO
O = pixels filled with white
# = pixels filled with black
* = pixels you stepped through
You've reached your starting point again and the algorithm stops, but the bounding box does not contain the whole object, but just a part. If all of your objects bounding boxes have either a width or a height of 1 you fill up your whole object with bounding boxes, hence it appears red.
You'll have to fix the startEdgeDetection to avoid the described case and make sure that you really detect the edge.
I made up a simple class that finds the bounding box of an object. It should be easy to apply it to your problem.
public class BoundingBoxCalculator
{
Bitmap bitmapToCalculateBoundingBoxFor;
Point startingPoint;
Point[] neighborOffsets =
{new Point(-1,-1),
new Point(0,-1),
new Point(1,-1),
new Point(-1, 0),
new Point(1, 0),
new Point(-1,1),
new Point(0,1),
new Point(1,1)};
public BoundingBoxCalculator(Bitmap bitmapContainingObject, Point borderPoint)
{
this.bitmapToCalculateBoundingBoxFor = bitmapContainingObject;
this.startingPoint = borderPoint;
}
public Rectangle CalculateBoundingBox()
{
List<Point> edgePoints = CalculateEdge();
int minX = edgePoints.Min(p => p.X);
int maxX = edgePoints.Max(p => p.X);
int minY = edgePoints.Min(p => p.Y);
int maxY = edgePoints.Max(p => p.Y);
return new Rectangle(minX, minY, maxX - minX, maxY - minY);
}
List<Point> CalculateEdge()
{
List<Point> edgePoints = new List<Point>();
Point currentPoint = startingPoint;
do
{
IEnumerable<Point> neighboringEdgePoints = GetNeighboringEdgePoints(currentPoint);
IEnumerable<Point> neighboringEdgePointsNotVisited = from p in neighboringEdgePoints where !edgePoints.Contains(p) select p;
edgePoints.Add(currentPoint);
if(neighboringEdgePointsNotVisited.Count() == 0
&& neighboringEdgePoints.Contains(startingPoint))
{
currentPoint = startingPoint;
}
else if(neighboringEdgePointsNotVisited.Count() == 1)
{
Point nextPoint = neighboringEdgePointsNotVisited.First();
currentPoint = nextPoint;
}
else if(neighboringEdgePointsNotVisited.Count() > 1)
{
Point nextPoint = GetPointWithMinDistance(currentPoint, neighboringEdgePointsNotVisited);
currentPoint = nextPoint;
}
else
{
throw new Exception();
}
} while(currentPoint != startingPoint);
return edgePoints;
}
Point GetPointWithMinDistance(Point origin, IEnumerable<Point> pointsToTest)
{
double minDistance = double.MaxValue;
Point pointWithMinDistance = new Point(0,0);
foreach(Point pointToTest in pointsToTest)
{
double currentDistance = GetPointsDistance(origin, pointToTest);
if(currentDistance < minDistance)
{
minDistance = currentDistance;
pointWithMinDistance = pointToTest;
}
}
return pointWithMinDistance;
}
double GetPointsDistance(Point p1, Point p2)
{
return Math.Sqrt((p1.X - p2.X) * (p1.X - p2.X) + (p1.Y - p2.Y) * (p1.Y - p2.Y));
}
IEnumerable<Point> GetNeighboringEdgePoints(Point currentPoint)
{
IEnumerable<Point> neighboringPoints = GetNeighboringPoints(currentPoint);
List<Point> neighboringEdgePoints = new List<Point>();
foreach(Point pointToTest in neighboringPoints)
{
if(GetNeighboringPoints(pointToTest).Count() < 8)
{
neighboringEdgePoints.Add(pointToTest);
}
}
return neighboringEdgePoints;
}
IEnumerable<Point> GetNeighboringPoints(Point currentPoint)
{
List<Point> neighbors = new List<Point>();
for(int offsetsCount = 0; offsetsCount < neighborOffsets.Length; offsetsCount++)
{
Point currentPointWithOffset = AddPointOffset(currentPoint, neighborOffsets[offsetsCount]);
if(IsInImage(currentPointWithOffset) &&
IsInObject(currentPointWithOffset))
{
neighbors.Add(currentPointWithOffset);
}
}
return neighbors;
}
bool IsInImage(Point pointToTest)
{
return pointToTest.X >= 0
&& pointToTest.X < bitmapToCalculateBoundingBoxFor.Width
&& pointToTest.Y >= 0
&& pointToTest.Y < bitmapToCalculateBoundingBoxFor.Height;
}
bool IsInObject(Point pointToTest)
{
Color colorInPointPosition = bitmapToCalculateBoundingBoxFor.GetPixel(pointToTest.X, pointToTest.Y);
//assume object is color is not white
return colorInPointPosition.R != 255
|| colorInPointPosition.G != 255
|| colorInPointPosition.B != 255;
}
Point AddPointOffset(Point point, Point offset)
{
return new Point(point.X + offset.X, point.Y + offset.Y);
}
}
Find an example at:
https://dotnetfiddle.net/49bnTV
I just tested it with a rectangle, but I guess it should work with any shape. Just give it a try.

How can i check that the pictureBox i'm moving around will not get out the borders top left right bottom of the second picturebox area?

private void picZoom_MouseMove(object sender, MouseEventArgs e)
{
if (PicImageClicked == false)
{
if (checkBox1.Checked)
{
int x = e.X + picZoom.Left - picImage.Left;
int y = e.Y + picZoom.Top - picImage.Top;
if (x <= picImage.Width && y <= picImage.Height &&
x <= picImage.Top && y <= picImage.Left)
{
MouseEventArgs e2 = new MouseEventArgs(MouseButtons.None, 0, x, y, 0);
picImageReposition(null, e2);
}
}
else
{
UpdateZoomedImage(e);
}
}
}
picImage is a bigger pictureBox and picZoom is a smaller pictureBox the picZoom i'm moving aorund inside the picImage are with the mouse.
This condition:
if (x <= picImage.Width && y <= picImage.Height
Is working if i'm moving the picZoom to the left border or the bottom border it stop on it and not continue.
But the second condition:
x <= picImage.Top && y <= picImage.Left
Is not working good it make everything slow and it's not stopping on the left or top borders.
I want to make a condition/s so the picZoom will stay in the picImage area borders.
What i tried now is:
private void picZoom_MouseMove(object sender, MouseEventArgs e)
{
Point pnt;
int x, y;
if (MouseButtons.Left == e.Button)
{
pnt = picZoom.PointToScreen(e.Location);
pnt = this.PointToClient(pnt);
x = pnt.X - mouseDown.X;
y = pnt.Y - mouseDown.Y;
if (x < picImage.Left)
{
x = picImage.Left;
}
else if (x + picZoom.Width > picImage.Left + picImage.Width)
{
x = picImage.Left + picImage.Width - picZoom.Width;
}
else
{ }
if (y < picImage.Top)
{
y = picImage.Top;
}
else if (y + picZoom.Height > picImage.Top + picImage.Height)
{
y = picImage.Top + picImage.Height - picZoom.Height;
}
else
{ }
picZoom.Location = new Point(x, y);
if (PicImageClicked == false)
{
if (checkBox1.Checked)
{
MouseEventArgs e2 = new MouseEventArgs(MouseButtons.None, 0, x, y, 0);
picImageReposition(null, e2);
}
else
{
UpdateZoomedImage(e);
}
}
}
}
picImageReposition is:
private void picImageReposition(object sender, MouseEventArgs e)
{
// If no picture is loaded, return
if (picImage.Image == null)
return;
if (PicImageClicked == false)
{
picZoom.BringToFront();
picZoom.Left = e.X + picImage.Left - picZoom.Width/2;
picZoom.Top = e.Y + picImage.Top - picZoom.Height/2;
UpdateZoomedImage(e);
}
}
And UpdateZoomedImage is:
private void UpdateZoomedImage(MouseEventArgs e)
{
// Calculate the width and height of the portion of the image we want
// to show in the picZoom picturebox. This value changes when the zoom
// factor is changed.
int zoomWidth = picZoom.Width / _ZoomFactor;
int zoomHeight = picZoom.Height / _ZoomFactor;
// Calculate the horizontal and vertical midpoints for the crosshair
// cursor and correct centering of the new image
int halfWidth = zoomWidth / 2;
int halfHeight = zoomHeight / 2;
// Create a new temporary bitmap to fit inside the picZoom picturebox
tempBitmap = new Bitmap(zoomWidth, zoomHeight, PixelFormat.Format24bppRgb);
// Create a temporary Graphics object to work on the bitmap
Graphics bmGraphics = Graphics.FromImage(tempBitmap);
// Clear the bitmap with the selected backcolor
bmGraphics.Clear(_BackColor);
// Set the interpolation mode
bmGraphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
// Draw the portion of the main image onto the bitmap
// The target rectangle is already known now.
// Here the mouse position of the cursor on the main image is used to
// cut out a portion of the main image.
bmGraphics.DrawImage(picImage.Image,
new Rectangle(0, 0, zoomWidth, zoomHeight),
new Rectangle(e.X - halfWidth, e.Y - halfHeight, zoomWidth, zoomHeight),
GraphicsUnit.Pixel);
// Draw the bitmap on the picZoom picturebox
picZoom.Image = tempBitmap;
// Draw a crosshair on the bitmap to simulate the cursor position
bmGraphics.DrawLine(Pens.Black, halfWidth + 1, halfHeight - 4, halfWidth + 1, halfHeight - 1);
bmGraphics.DrawLine(Pens.Black, halfWidth + 1, halfHeight + 6, halfWidth + 1, halfHeight + 3);
bmGraphics.DrawLine(Pens.Black, halfWidth - 4, halfHeight + 1, halfWidth - 1, halfHeight + 1);
bmGraphics.DrawLine(Pens.Black, halfWidth + 6, halfHeight + 1, halfWidth + 3, halfHeight + 1);
// Dispose of the Graphics object
bmGraphics.Dispose();
// Refresh the picZoom picturebox to reflect the changes
picZoom.Refresh();
}
If the formula of moving the picZoom control is what you want eg
int x = e.X + picZoom.Left - picImage.Left;
int y = e.Y + picZoom.Top - picImage.Top;
then the comparison is(x, y is the position in picImage meaning that 0,0 is the left top position):
if(x >= 0 && y >= 0 && x + picZoom.Width <= picImage.Width && y + picZoom.Height <= picImage.Height)
{
...
...
}
EDIT
When you click in picZoom and drag, the control moves with the mouse:
private Point mouseDown;
private void picZoom_MouseDown(object sender, MouseEventArgs e)
{
mouseDown = e.Location;
}
private void picZoom_MouseMove(object sender, MouseEventArgs e)
{
Point pnt;
int x, y;
if (MouseButtons.Left == e.Button)
{
pnt = picZoom.PointToScreen(e.Location);
pnt = this.PointToClient(pnt);
x = pnt.X - mouseDown.X;
y = pnt.Y - mouseDown.Y;
if (x < picImage.Left)
{
x = picImage.Left;
}
else if (x + picZoom.Width > picImage.Left + picImage.Width)
{
x = picImage.Left + picImage.Width - picZoom.Width;
}
else
{ }
if (y < picImage.Top)
{
y = picImage.Top;
}
else if (y + picZoom.Height > picImage.Top + picImage.Height)
{
y = picImage.Top + picImage.Height - picZoom.Height;
}
else
{ }
picZoom.Location = new Point(x, y);
}
}
valter
This is not an answer to your question as much as it is a suggestion. Could you not create a Rect() directly over your picture and simply check if the mouse position is within it's bounds.
Something along the lines of:
Rectangle rect = obj.GetBounds(e.Graphics);
if (!rect.Intersects(e.ClipRectangle))
continue;
(stolen from another post)
So I looked over your code again, and it struck me.
You are comparing an x value to the top bound of your picture and a y value to the left bound...
x <= picImage.Top && y <= picImage.Left
should be
x <= picImage.Left && y <= picImage.Top
That is, if I understand what you are trying to do.
Good luck!

Categories

Resources