How can I round off the edges of pie-chart slices? - c#

I've got C# code to draw a pie chart using the conventional code for each slice:
gr.FillPie(brFill, rect, start_angle, sweep_angle);
gr.DrawPie(penOutline, rect, start_angle, sweep_angle);
This works fine: the trouble is it looks very boring. I'd like to get the effect as below; that is, keeping it 2-D but rounding off the edges.
I presume I'd need to use a path gradient brush somehow, but none of the examples I've looked at have helped.
Grateful for any help or tips.
Tony Reynolds

I posted this 11 days ago hoping that someone would do my job for me. I now realise I was wrong and am a reformed character.
I tried drawing shading and highlights using ControlPaint.Dark() & Light() but couldn't get it to look good. Finally I decided that as most pie charts have a limited range of colours I should set up a series of complete discs with colouring and shading and clip sectors out as required.
A few sample discs are below:
I then set up an equivalent of the FillPie method as below.
private static void FillImagePie(Graphics gr, Bitmap bm, Rectangle rect,
float startAngle, float sweepAngle)
// Display a pie slice of a background image.
{
// Create a clipping Region
GraphicsPath pathClip = new GraphicsPath();
pathClip.AddPie(rect, startAngle, sweepAngle);
Region regionClip = new Region(pathClip);
// Use region to clip image to the pie sector
gr.Clip = regionClip;
// Draw the image portion
gr.DrawImage(bm, rect);
// Clean up
gr.ResetClip();
regionClip.Dispose();
pathClip.Dispose();
}
This takes a disc bitmap, bm, sets up a pie-shaped clip region and draws the image.
I then needed a control routine that can be called from the Paint overload of the form.
In the special case of the pie chart only having one category, the whole disc is displayed. Otherwise each sector is taken in turn.
I found in practice that the outline looked ragged, so I first flood the sector with a black brush, then call FillImagePie, then draw a black outline.
A sample result is here:
I'm happy enough with this effect.
All comments and tweaks welcome, and if anyone else has a way to jazz up pie charts please share!
Tony Reynolds

Related

How can I make the transparency from a PictureBox work properly when it's over another PictureBox?

I was doing a game project in Windows Forms and really loved how it turned out, except for one thing that was bugging me: the new picturebox's I am adding are "eating" away from the one behind it, showind the background of its parent and not showing the image behind him, as I thought it will. Apparently that's how transparency works in Windows Forms, it copies the colors behind him, basically.
This is how it looks, and I want the animals to be seen fully.
I also tried this from another post here, but it turned out like this.
There might be no solution to this, I have other things in this little game I made. There is another picturebox with other buttons and stuff, that represents the shop. And also you can see in both images that there is a pannel in the bottom section with some details. In that case, I would leave it as it is and maybe try another time to move it to WPF.
=================== EDIT ===================
The accepted answer helped me switch from a game with overlaying PictureBoxes to a game where I "paint" each frame of the game on the background. Check that answer's comment for more details about this :) This is how it turned out.
This is specifically for my code, where I have a static Resources class. Yours could look a lot cleaner, maybe you have this Render function where you have every other rectangle and image. I hope this helps everyone that visits this page :)
// ================ SOLUTION ================
public static void Render()
{
//draw the background again. This is efficient enough, maybe because the pixels that did not changed won't be redrawn
grp.DrawImage(Resources.gameBackground, 0, 0);
//draw the squirrel image on the position and length of the "squirrel" Rectangle
grp.DrawImage(Resources.currentSquirrelImage, Resources.squirrel.X, Resources.squirrel.Y, Resources.squirrel.Width, Resources.squirrel.Height);
//after that, draw each projectile (acorns, wallnuts) the same way
foreach (Projectile projectile in Resources.projectiles)
{
grp.DrawImage(projectile.image, projectile.rect.X, projectile.rect.Y, projectile.rect.Width, projectile.rect.Height);
}
//then draw each animal
foreach (Enemy animal in Resources.enemies)
{
grp.DrawImage(animal.image, animal.rect.X, animal.rect.Y, animal.rect.Width, animal.rect.Height);
}
//and finally, the image that shows where the squirrel is shooting
grp.DrawImage(Resources.selectionImge, Resources.selection.X, Resources.selection.Y, Resources.Selection.Width, Resources.Selection.Height);
//update the image of the game picturebox
form.TheGame.Image = bmp;
}
As you have noticed .net control transparency is not real transparency, it copies it's parent background, so if you have other sibiling controls the one with the higher Z index will occlude the others.
If you want to create a game avoid the usage of picture boxes, there are many options: use a game engine like Unity or roll your own.
Something easy to do is to create a Bitmap, render your game in it and then present it in your form, but beware, that can be slow.
EDIT: As you requested here is an example on how to use the Intersect function of the Rectangle struct to determine which parts of two rectangles overlap.
Rectangle R1 = new Rectangle (0,0,32,32);
Rectangle R2 = new Rectangle (16,16,32,32);
//To test if a rectangle intersects with another...
bool intersects = R1.IntersectsWith(R2); //If does not intersect then there's nothing to update
//To determine the area that two rectangles intersect
Rectangle intersection = Rectangle.Intersect(R1, R2); //In this example that would return a rectangle with (16,16,16,16).

Crop Image in Aspect Fill UIImageView

I have been trying to figure this out for hours with no answer.
I have an UIimageView with the ContentMode as UIViewContentMode.ScaleAspectFill which I would like to crop using an overlying resizable frame. The cropping frame no longer maintains a 1:1 relationship between the bounds that contains both the UIimageView and cropping tool. The cropping usually would be as simple as:
using (var imageRef = image.CGImage.WithImageInRect(frame)) {
return UIImage.FromImage(imageRef);
}
But, the calculations are required in the case, how would I calculate the offset to match the cropping tool frame to the newly inflated UIImageView (or rather UIImage)? Here's a image to help paint the picture:
This picture shows a few key things.
Upper Right Image: What will be cropped currently (area contained in blue section)
Blue Rectangle: Where the cropping is currently being taken place, notice the position and height is skewed compared to red.
Red Rectangle: The cropping control, essentially where the cropping should be taking place. INSTEAD of where blue is.
Upper Blue Textbox: Ignore this.
Essentially, I want the blue rect to be where the red frame is.
Any help would be greatly appeciated, I am using C# for this, but Objective C answers are more than welcomed.

Grid on top of image with editing ability

I'm hoping someone can give me some guidance here. I have been gogleing for a while now and I can't come up with anything that suits my needs. I'm a bit of a programmer but not a pro and I have no graphics experience. I am trying to develop a program for my wife to more easily transfer images to her needlepoint drawings. I want to write a C# application that will let me load an image of almost any type and overlay a "grid" on top of it. I want to also be able to implement simple "paint" operations like change the color of a grid square, color selector from the base image, bucket fill, etc. Any suggestions and examples would be greatly appreciated.
Thanks,
Tom
I've implemented something similar for my wife. My basic approach:
1) Scale the image down to the number of necessary pixels. For example, if she's stitching the image on a 10x10 13-mesh canvas, that equates to an image of 130x130 pixels.
Here's some example code to start you off:
// use NearestNeighbor algorithm
public static unsafe Bitmap Reduce(Bitmap source, SizeF toSize, int threadCount)
{
Bitmap reduced = new Bitmap((int)(toSize.Width * threadCount), (int)(toSize.Height * threadCount));
using (Graphics g = Graphics.FromImage(reduced))
{
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.DrawImage(source, new Rectangle(Point.Empty, reduced.Size));
}
return reduced;
}
2) Display the pixelated image full screen. This will provide a grid-like effect.
3) Display a color palette from DMC's yarn code card, or taken from the image (after down-scaling). Then have the mouse cursor pick up a color by clicking on it, then applying it to the cell that it was subsequently clicked on.
Here's some code for picking up the mouse cursor:
public Point GetPicturePointAtClick()
{
Point p = Cursor.Position;
Point picturePoint = previewBox.PointToClient(p);
if (Zoom != 0)
{
picturePoint.X = (int)(picturePoint.X / Zoom);
picturePoint.Y = (int)(picturePoint.Y / Zoom);
}
return picturePoint;
}
The idea here is to map the clicked area to the correct pixel in the reduced image, math:
Point reducedPoint =
new Point(
(int)(picPoint.X * (_reduced.Width / (float)WorkingBitmap.Width)),
(int)(picPoint.Y * (_reduced.Height / (float)WorkingBitmap.Height)));
There's a lot of code ahead of you. Did you try an online custom needlepoint provider? Try one of these sites, they're both pretty good and customization is free:
http://www.needlepaint.com/
http://www.pepitaneedlepoint.com/

Cropping the borders of image based on color in windows phone

Above is the image i am using. What i am trying to achieve is removing the red portion of the border from the image. How can I achieve this programmatically in windows phone? I found WriteableBitmapExtensions.Crop() method, but I am confused with the arguments (how i can find the x,y position of the image, as well as the size and the width?)
Also another issue I am facing is: I will get the images with differently sized borders, so I can't hardcode the x or y values.
Can anyone suggest a solution, or guide me to solve the issue?
This is not such a trivial thing and you haven't shared any code with us, so I can give you a few suggestions. Every WriteableBitmap has width and height defined. You should be able to access it via
wb.PixelWidth;
wb.PixelHeight;
where wb is your WriteableBitmap (the picture)
Having said that, it's trivial to crop a WriteableBitmap using WriteableBitmapEx library
var croppedBmp = wb.Crop(10, 10, 300, 220);
If your wb was 320x240 and the border was of width 10, then the above Crop call will do the trick - you will take the inner rectangle starting from point (10,10) and ending at (310, 230)
Now to your second issue - not knowing the width of the border. It would help if you know that
Border is of the same thickness on every side of the picture
Border is always in one color only
Assuming that's true, you could think of a simple algorithm (that may not be correct every time, but you can test it and adjust) which would take a few random points, for example
(0,randNumber < wb.PixelHeight), (randNumber < wb.PixelWidth, 0), (wb.PixelWidth, randNumber < wb.PixelHeight), (randNumber < wb.PixelWidth, wb.PixelHeight)
and then move towards the inner part of the picture as long as the neighbour pixel is the same color as the starting pixel. The more points you take randomly, the better chances you have of getting it right. The obvious problem with this is that it may happen that something on the picture is the same color as the border (exactly the same) which will make it seem like the border is wider than it really is. That's why you should take more points.
If you showed some code, I'd be happy to expand the answer.

Reading pixels set using Graphics object

I know several methods for reading Bitmap pixels or to get a Graphic object from an image, but what I am trying to understand is how to know what pixels have been drawn by the user by means of a Graphics object. Example: the user draw a line (but it could be any possible shape) using something like:
surface.DrawLine(aPen, X0, Y0, X1, Y1);
I need to know what pixels have been set by the user to perform some processing. This could be done quite easily for simple shapes using math (i.e. X = X0 + (X1-X0)*t) , but it seems to me possibly unefficient (specially for complex shapes). A solution I would like is to read a Bitmap looking for the pixels that have been set, but I do not know methods for getting a Bitmap image (or whatever relevant data structure) to work on from a Graphics object. Because this is an obvious need for any program allowing to the user do draw, I am for sure missing some points. Someone has a hint about this?
P.S. I am using Graphics object over a 8Bpp indexed Bitmap in a Windows Form and I need all the pixel coordinates and, possibly, the pixel values (they could be deduced from pixel coordinates, I guess)
Proposed solution
The best solution I can figure out after the contributions in this post is something similar to this (being sourceImage the image I want to draw on and surface the picturebox control where sourceImage is rendered):
private void DrawOverlay()
{
using (var tmpImg = new Bitmap (SourceImage.Width,SourceImage.Height, PixelFormat .Format32bppArgb))
{
var g = Graphics.FromImage(tmpImg);
g.DrawLine(pen1, Startx, Starty, Endx, Endy);
tmpImg.MakeTransparent(Color.FromArgb(0, 0, 0));
surface.DrawImage(tmpImg, new Point (0, 0));
// process here the tmpImg pixels drawn by the user
}
}
If someone has better answer, please, if you like, let us know; otherwise I'll close the post answering to my own question as above.
I suggest making a copy of the image before creating the Graphics context. After you have processed all paintings with the Graphics context, you can compare the image with the first one (backup) using XOR (see this example). The resulting contains only those pixels that have changed.
backupImage XOR drawnImage = changes
You can also use OpenCV wrapped by AForge.NET and it's Difference and Substract classes. They do exactly what you want.
As far as I know the proposed solution draft in the question after the feedback received seems to be the an acceptable solution to have an easy access to the pixels drawn.

Categories

Resources