GraphicsPath - Why does order of AddLine methods matter - c#

I am drawing a triangle with the following code
int x = x coordinate for center;
int ax = x coordinate for left;
int bx = x coordinate for right;
int top = y coordinate for top;
int bottom = y coordinate for bottom;
// (x, top)
//(ax, bottom) (bx, bottom)
GraphicsPath path = new GraphicsPath();
// _
path.AddLine(ax, bottom, bx, bottom);
// /
path.AddLine(ax, bottom, x, top);
// \
path.AddLine(bx, bottom, x, top);
// order of drawing is _ / \ (bottom line, left side, right side)
When I call DrawPath, it always draws my lines, no matter the order. But when I call FillPath, it does nothing. Only when my order is / _ \ or \ _ / does my triangle actually fill. Why is this?

It turns out that the answer I posted originally didn't really solve the problem and that it worked on my machine because of an additional change I introduced, which is to change the FillMode:
GraphicsPath path = new GraphicsPath(FillMode.Winding);
When you use the Winding mode, the algorithm will detect a closed path even if you didn't add the lines in order.

Related

How to fill rectangle in c# using bounding boxes

I have listed bounding boxes X top left, Y top left , X top right , Y top right, X bottom right , Y bottom right , X bottom left , Y bottom left
Need to create fill rectangle on image.
How can i calculate x,y,width and height for Rectangle
Have used Pen and DrawRectangle
Bitmap bmp = (Bitmap)Bitmap.FromFile(imageFilePath);
Graphics g = Graphics.FromImage(bmp);
Pen snowPen = new Pen(Color.Black, width);
g.DrawRectangle(snowPen, x , y , width, height);
How can i convert the boundingboxes data to get x,y,height and width ?
If you look at the documentation of DrawRectangle here to know how are expressed x and y:
The x-coordinate of the upper-left corner of the rectangle to draw.
The y-coordinate of the upper-left corner of the rectangle to draw.
And based on the fact that you mentioned that your input info is:
X top left, Y top left, X top right, Y top right, X bottom right , Y bottom right , X bottom left , Y bottom left
Then:
x= X top left
y= Y top left
Height= (Y top left - Y bottom left) or Y top right - Y bottom right: if you have a boundingbox value which was a rectangle, the values are equals)
Width= (X top right - X top left) or X bottom right - X bottom left: if you have a boundingbox value which was a rectangle, the values are equals)
Remarks:
As you did not mention how your boundingbox values were expressed (int? float?), keep in mind that here your values should be int values.
If your bounding box is not a rectangle, you should use DrawPolygon instead

Find the center coordinate of a circle from a list of pixel coordinates C#

I have a BitMap image where the image contains a black circle. I have found all the pixels from the image that are black which represent the circle and have saved the points into a List.
Where I am lost is finding the center of the circle from coordinates saved in the list. I am thinking that I need to find the diameter of the circle somehow but how do I loop though the pixels to do that to determine that?
One naive approach could be to find the bounding box for the circle.
Seeing as you already have all of the points in a list you can find the top, bottom, left and right.
Assuming the (0,0) is the top left of the co-ordinate system:
The top is the point with min Y.
The bottom is the point with max Y.
The left is the point with min X.
The right is the point with max X.
The center of the bounding box is the center of the circle.
Similarly the width/height of the bounding box is its diameter.
Edit: an alternative solution
Find the mean of all the points in the circle.
This will then give you the center of the circle.
var aggregate = points.Aggregate((point, result) => new Point{ X = point.X + result.X, Y = point.Y + result.Y });
var center = new Point { X = aggregate.X / points.Count, Y = aggregate.Y / points.Count };
This may be a more optimal solution because it could be done while you are scanning the image for the black pixels. Rather than finding the black pixels and then using LINQ.
Circle is a relative term when it comes to images, that's to say, that the shape you are referring to is shown in pixels and may only be representative of a circle.
However to get the midpoint all you need to do is get the extents.
Assuming you have a List<Point>
var left = list.Min(x => x.X);
var right = list.Max(x => x.X);
var top= list.Min(x => x.Y);
var bottom = list.Max(x => x.Y);
Point mid = new Point();
mid.X = left + (right-left) / 2; //calculate mid point x
mid.Y = top + (bottom-top) / 2; //calculate mid point y
Note : Totally untested

itextsharp rotate image at point [duplicate]

double degPi = degrees * Math.PI / 180;
double a = Math.cos(degPi)*tImgCover.getScaledHeight();
double b = Math.sin(degPi)*tImgCover.getScaledWidth();
double c = -Math.sin(degPi) * tImgCover.getScaledHeight();
double d = Math.cos(degPi)* tImgCover.getScaledWidth();
double e = absX;
double f = absY;
contentByte.addImage(imgae, a, b, c, d, e, f);/*add image*/
How to rotate around the image center by itext?
If we have an Image image and coordinates x, y, we can draw the image without rotation with its lower left corner at the given coordinates like this
contentByte.addImage(image, image.getWidth(), 0, 0, image.getHeight(), x, y);
A bitmap image from the resources has a size of 1x1 with the coordinate origin at its lower left. Thus, this operation stretches the image to its correct size and moves it so its lower left is at the given coordinates.
If we want to draw the same image as if the one drawn above was rotated around its center by an angle rotate, therefore, we can do this by moving the 1x1 image so that the origin is in its center, stretch it to its correct size, rotate it, and then move the origin (which still is at the center of the rotated image) to the center of the unrotated image. These operations are easier to express using AffineTransform instances (from package com.itextpdf.awt.geom) instead number tupels. Thus:
// Draw image as if the previous image was rotated around its center
// Image starts out being 1x1 with origin in lower left
// Move origin to center of image
AffineTransform A = AffineTransform.getTranslateInstance(-0.5, -0.5);
// Stretch it to its dimensions
AffineTransform B = AffineTransform.getScaleInstance(image.getWidth(), image.getHeight());
// Rotate it
AffineTransform C = AffineTransform.getRotateInstance(rotate);
// Move it to have the same center as above
AffineTransform D = AffineTransform.getTranslateInstance(x + image.getWidth()/2, y + image.getHeight()/2);
// Concatenate
AffineTransform M = (AffineTransform) A.clone();
M.preConcatenate(B);
M.preConcatenate(C);
M.preConcatenate(D);
//Draw
contentByte.addImage(image, M);
(AddRotatedImage.java test method testAddRotatedImage)
For example drawing both images using
int x = 200;
int y = 300;
float rotate = (float) Math.PI / 3;
results in something like this:
With a Flip
The OP asked in a comment
how to add rotate and flip image?
For this you simply insert a mirroring affine transformation into the sequence of transformations above.
Unfortunately the OP did not mention which he meant a horizontal or a vertical flip. But as changing the rotation angle accordingly transforms one in the other, that isn't really necessary, either.
// Draw image as if the previous image was flipped and rotated around its center
// Image starts out being 1x1 with origin in lower left
// Move origin to center of image
AffineTransform A = AffineTransform.getTranslateInstance(-0.5, -0.5);
// Flip it horizontally
AffineTransform B = new AffineTransform(-1, 0, 0, 1, 0, 0);
// Stretch it to its dimensions
AffineTransform C = AffineTransform.getScaleInstance(image.getWidth(), image.getHeight());
// Rotate it
AffineTransform D = AffineTransform.getRotateInstance(rotate);
// Move it to have the same center as above
AffineTransform E = AffineTransform.getTranslateInstance(x + image.getWidth()/2, y + image.getHeight()/2);
// Concatenate
AffineTransform M = (AffineTransform) A.clone();
M.preConcatenate(B);
M.preConcatenate(C);
M.preConcatenate(D);
M.preConcatenate(E);
//Draw
contentByte.addImage(image, M);
(AddRotatedImage.java test method testAddRotatedFlippedImage)
The result with the same image as above:
With Interpolation
The OP asked in a yet another comment
How anti aliasing ?
The iText Image class knows an Interpolation property. By setting it to true (before adding the image to the document, obviously),
image.setInterpolation(true);
low resolution images are subject to interpolation when drawn.
E.g. using a 2x2 image with differently colored pixels instead of the image of Willi, you get the following results, first without interpolation, then with interpolation:
Confer the AddRotatedImage.java test testAddRotatedInterpolatedImage which adds this image:
Beware: iText Image property Interpolation effectively sets the Interpolate entry in the PDF image dictionary. The PDF specification notes in this context:
NOTE A conforming Reader may choose to not implement this feature of PDF, or may use any specific implementation of interpolation that it wishes.
Thus, on some viewers interpolation may occur differently than in your viewer, maybe even not at all. If you need a specific kind of interpolation on every viewer, upscale the image with the desired amount of interpolation / anti-aliasing before loading it into an iText Image.
public static BufferedImage rotateClockwise90( BufferedImage inputImage ){
int width = inputImage.getWidth();
int height = inputImage.getHeight();
BufferedImage returnImage = new BufferedImage( height, width , inputImage.getType() );
for( int x = 0; x < width; x++ ) {
for( int y = 0; y < height; y++ ) {
returnImage.setRGB( height-y-1, x, inputImage.getRGB( x, y ) );
}
}
return returnImage;
}

C# Rect class y axis not created correctly

I am creating a Rect in C# with two points. These points are actually Geographical bounds. The problem I am having is what when I create the rectangle the y axis is flipped.
For example say my data is west="5.42194487004" south="46.407494" east="17.166386" north="55.056664"
I pass that into Rect geoBounds = new Rect(new Point(west, north),new Point(east, south));
The Rectangle that is created has the following properties
Bottom 55.056664 double
Height 7.781945 double
IsEmpty false bool
Left 5.864166 double
Right 15.038887000000003 double
Top 47.274719 double
Width 9.1747210000000017 double
X 5.864166 double
Y 47.274719 double
The Y axis is flipped. I have triple checked that the data being fed into the call is correct. What is wrong? Also I know that I did not supply much code but did not feel any more was needed. Will provide more if needed.
The coordinate system has 0,0 at the top left of the screen, with Y increasing in the downward direction. You can see this at the example page for the Rect.Bottom property: http://msdn.microsoft.com/en-us/library/system.windows.rect.bottom.aspx
Note on that page this comment:
// Bottom property gets the y-axis value of the bottom of the rectangle.
// For this rectangle the value is 55.
rectInfo = rectInfo + "Bottom: " + myRectangle.Bottom;
and this one:
// Top property gets the y-axis position of the top of the rectangle which is
// equivalent to getting the rectangle's Y property.
// For this rectangle the value is 5.
rectInfo = rectInfo + "| Top: " + myRectangle.Top;
This is further supported by the explicit constructor for Rect: http://msdn.microsoft.com/en-us/library/ms587929%28v=vs.95%29.aspx
Note that x and y describe the top left corner, where width extends that in the rightward direction and height extends downwards.
Rect geoBounds = new Rect(west, north, (east - west), (north - south));

Per Pixel Collision - Code explanation

I'm currently trying to understand per pixel collision detection.
This is the code I don't understand:
static bool IntersectPixels(Rectangle rectangleA, Color[] dataA,
Rectangle rectangleB, Color[] dataB)
{
// Find the bounds of the rectangle intersection
int top = Math.Max(rectangleA.Top, rectangleB.Top);
int bottom = Math.Min(rectangleA.Bottom, rectangleB.Bottom);
int left = Math.Max(rectangleA.Left, rectangleB.Left);
int right = Math.Min(rectangleA.Right, rectangleB.Right);
// Check every point within the intersection bounds
for (int y = top; y < bottom; y++)
{
for (int x = left; x < right; x++)
{
// Get the color of both pixels at this point
Color colorA = dataA[(x - rectangleA.Left) +
(y - rectangleA.Top) * rectangleA.Width];
Color colorB = dataB[(x - rectangleB.Left) +
(y - rectangleB.Top) * rectangleB.Width];
// If both pixels are not completely transparent,
if (colorA.A != 0 && colorB.A != 0)
{
// then an intersection has been found
return true;
}
}
}
// No intersection found
return false;
}
I really haven't understood the all loop. I'll be glad for some explanation how it works.
First up, it finds the region the two image rectangles intersect, then it iterates through each pixel in that region, and compares the alpha values of each image of each pixel. If neither has an alpha value of 0, they are both considered 'solid' and therefore colliding.
it's not that hard (in this case) - you give the algorithm the two bounding-boxes of your objects (so the hole object is inside this box), and a array with color-information for them.
Tha algorithm assumes that a point belongs to the object IFF it is not transparent - this is important.
The first step is to calculate the intersecting rectangle - if you intersect two rectangles that have sides parallel to the axes like in this case - you will get a rectangle again or an empty set.
The next step is to iterate in this intersecting rectangle for all (x,y) -coordinates insiede - first y, then x -so you get your normal first x, then y inside, but this is minor point and not important.
Then finally the algorithm gets the color for object A and B at the current pixel (x,y) - if both colors are NOT transparent then the pixel is in both objects and the objects have to intersect at this point - so the algorithm terminates with "YES they intersect"
If all pixels in the intersection of the bounding boxes where checked and no common (e.g. not transparent) pixel was found the object don't intersect and so the algorithm terminates with "NO they don't intersect"
I hope this helps.
for (int y = top; y < bottom; y++) loops over the lines of the resulting rectangle from top to bottom, and for (int x = left; x < right; x++) loops over pixels inside each line, left to right.

Categories

Resources