I'm trying to get an image and apply a drop shadow to it and save back as an image.
So far, the only way to do that, while not using third party solutions is to use the DropShadowEffect in a DrawingVisual:
var drawingVisual = new DrawingVisual();
drawingVisual.Effect = new DropShadowEffect
{
Color = Color.FromArgb(255, 0, 0, 0),
BlurRadius = 5,
Opacity = 1,
Direction = 45,
ShadowDepth = 6
};
using (var drawingContext = drawingVisual.RenderOpen())
{
var left = 0; //??
var top = 0; //??
var totalWidth = left + image.Width; //??
var totalHeight = top + image.Height; //??
//Background.
drawingContext.DrawRectangle(new SolidColorBrush(Colors.White), null, new Rect(0,0, totalWidth, totalHeight));
//Image.
drawingContext.DrawImage(image, new Rect(left, top, image.Width, image.Height));
}
var frameHeight = image.PixelHeight; //??
var frameWidth = image.PixelWidth; //??
//Converts the Visual (DrawingVisual) into a BitmapSource.
var bmp = new RenderTargetBitmap(frameWidth, frameHeight, imageDpi, imageDpi, PixelFormats.Pbgra32);
bmp.Render(drawingVisual);
//Creates a PngBitmapEncoder and adds the BitmapSource to the frames of the encoder.
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bmp));
//Saves the image into a file using the encoder.
using (Stream stream = File.Create(frame.Path))
encoder.Save(stream);
I have no idea the math required to detect the exact pixel offsets at all sides for a given DropShadowEffect.
Is there any built in way to measure it or should I do it manually?
How can be done manually?
If you take a look at the .NET source code for the DropShadowEffect there is an internal method GetRenderBounds that you can use to formulate the answer you're looking for.
While GetRenderBounds is not available for you to use, the code is simple enough that you can create your own helper method.
Here's the code for reference:
/// <summary>
/// Takes in content bounds, and returns the bounds of the rendered
/// output of that content after the Effect is applied.
/// </summary>
internal override Rect GetRenderBounds(Rect contentBounds)
{
Point topLeft = new Point();
Point bottomRight = new Point();
double radius = BlurRadius;
topLeft.X = contentBounds.TopLeft.X - radius;
topLeft.Y = contentBounds.TopLeft.Y - radius;
bottomRight.X = contentBounds.BottomRight.X + radius;
bottomRight.Y = contentBounds.BottomRight.Y + radius;
double depth = ShadowDepth;
double direction = Math.PI/180 * Direction;
double offsetX = depth * Math.Cos(direction);
double offsetY = depth * Math.Sin(direction);
// If the shadow is horizontally aligned or to the right of the original element...
if (offsetX >= 0.0f)
{
bottomRight.X += offsetX;
}
// If the shadow is to the left of the original element...
else
{
topLeft.X += offsetX;
}
// If the shadow is above the original element...
if (offsetY >= 0.0f)
{
topLeft.Y -= offsetY;
}
// If the shadow is below the original element...
else
{
bottomRight.Y -= offsetY;
}
return new Rect(topLeft, bottomRight);
}
I hope this helps.
Update from the author of the question
Here's the actual code that I'm using:
//Draws image with shadow.
using (var drawingContext = drawingVisual.RenderOpen())
{
//Measure drop shadow space.
var point1 = new Point(0 - model.BlurRadius / 2d, 0 - model.BlurRadius / 2d);
var point2 = new Point(image.PixelWidth + model.BlurRadius / 2d, image.PixelHeight + model.BlurRadius / 2d);
var num1 = Math.PI / 180.0 * model.Direction;
var num2 = model.Depth * Math.Cos(num1);
var num3 = model.Depth * Math.Sin(num1);
if (num2 >= 0.0)
point2.X += num2; //If the shadow is horizontally aligned or to the right of the original element...
else
point1.X += num2; //If the shadow is to the left of the original element...
if (num3 >= 0.0)
point1.Y -= num3; //If the shadow is above the original element...
else
point2.Y -= num3; //If the shadow is below the original element...
var left = Math.Abs(point1.X);
var top = Math.Abs(point1.Y);
var totalWidth = left + point2.X;
var totalHeight = top + point2.Y;
//Image.
drawingContext.DrawImage(image, new Rect((int)left, (int)top, image.PixelWidth, image.PixelHeight));
frameHeight = (int)totalHeight;
frameWidth = (int)totalWidth;
}
Related
I would like to draw a thick, transparent arrow with an arrowhead:
Here's the code that draws the arrow shaft. Notice that I have to offset the rectangle so the calculations are done from the midpoint of the rectangle.
private void DrawMovementArrow(bool color, double StartX, double StartY, double EndX, double EndY)
{
SolidColorBrush partiallyTransparentSolidColorBrush;
Rectangle myRectangle = new Rectangle();
// This will be replaced by piece size
int width = 35;
myRectangle.Width = width;
// Apparently necessary to offset the drawing of the path so that the point is in the center of the path; not the edge.
StartX -= width / 2;
EndX -= width / 2;
myRectangle.Height = Map.EuclideanDistance(StartX, StartY, EndX, EndY) ;
int angle = CalculateAngle(StartX , StartY , EndX , EndY );
// This selects the midpoint of edge of the rectangle to rotate around (weird system)
myRectangle.RenderTransformOrigin = new Point(0.5, 0);
angle = angle - 180;
RotateTransform rotateTransform1 = new RotateTransform(angle, 0 , 0 );
myRectangle.RenderTransform = rotateTransform1;
if (color)
partiallyTransparentSolidColorBrush = new SolidColorBrush(Colors.Blue);
else
partiallyTransparentSolidColorBrush = new SolidColorBrush(Colors.Red);
partiallyTransparentSolidColorBrush.Opacity = 0.4;
myRectangle.Fill = partiallyTransparentSolidColorBrush;
MovementCanvas1.Children.Clear();
MovementCanvas1.Children.Add(myRectangle);
Canvas.SetTop(myRectangle, StartY);
Canvas.SetLeft(myRectangle, StartX);
DrawArrowhead(color, EndX, EndY, angle + 90, width);
ShowUnitCenter(MovementArrowList[0]);
}
Note that this code selects a point in the middle of the edge to rotate the rectangle:
// This selects the midpoint of edge of the rectangle to rotate around (weird system)
myRectangle.RenderTransformOrigin = new Point(0.5, 0);
The problem is that I can't find that point with the arrowhead (triangle). Here's the code that draws the arrowhead:
public void DrawArrowhead(bool color, double x, double y, int angle, int width)
{
x += width /2 ;
width = width + (width / 2);
//Add the Polygon Element
Polygon myPolygon = new Polygon();
myPolygon.Opacity = 0.4;
if (color)
{
myPolygon.Fill = new SolidColorBrush(Colors.Blue);
myPolygon.Stroke = System.Windows.Media.Brushes.Blue;
}
else
{
myPolygon.Fill = new SolidColorBrush(Colors.Red);
myPolygon.Stroke = System.Windows.Media.Brushes.Red;
}
myPolygon.StrokeThickness = 0;
RotateTransform rotateTransform1 = new RotateTransform(angle, 0, 0);
myPolygon.RenderTransform = rotateTransform1;
// This selects the midpoint of edge of the triangle to rotate around (weird system)
myPolygon.RenderTransformOrigin = new Point(0.0, 0.5);
System.Windows.Point Point1 = new System.Windows.Point(0, 0);
System.Windows.Point Point2 = new System.Windows.Point(width / 2, width / 2);
System.Windows.Point Point3 = new System.Windows.Point(0,width);
PointCollection myPointCollection = new PointCollection();
myPointCollection.Add(Point1);
myPointCollection.Add(Point2);
myPointCollection.Add(Point3);
myPolygon.Points = myPointCollection;
MovementCanvas1.Children.Add(myPolygon);
Canvas.SetTop(myPolygon, y );
Canvas.SetLeft(myPolygon, x );
}
Note the myPointCollection that creates the triangle. The problem is that I've tried almost every conceivable combination of values in RenderTransformOrigin to find the point that (center bottom of triangle) to use for the rotation point. Nothing seems to be working out.
Can anybody suggest the correct value?
Edit Solved
I solved it by changing the points of the triangle. That was easier than trying to figure out the rotation point.
Changing the points that made up the triangle solved the problem. This was easier than trying to find the rotation point.
Why does the following code affect a page's ability to find its top, bottom, right and left?
Before applying it, reader.GetCropBox(i).GetLeft(0) and reader.GetPageSize(i).GetLeft(0) return the far left point of every page in an assorted set. After applying it, GetLeft(0) is the far left on some pages and on others the left most point AFTER the margin ends.
I'm trying to create a header on any given set of preexisting pages (ie, create white space and then put text in it)
using (Stream stream = new FileStream(outputPdfPath2, System.IO.FileMode.Create))
{
using (PdfReader reader = new PdfReader(outputPdfPath))
{
using (PdfStamper stamper = new PdfStamper(reader, stream))
{
int n = reader.NumberOfPages;
for (int i = 1; i <= n; i++)
{
//iTextSharp.text.Rectangle size = reader.GetPageSize(i);
iTextSharp.text.Rectangle size = reader.GetCropBox(i);
//////////
// Create Margin
float marginTop = 160;
float marginBottom = 160;
float marginLeft = 160;
float marginRight = 160;
float width = size.Width + marginLeft + marginRight; // 8.5f * 72;
float height = size.Height + marginTop + marginBottom; // 11f * 72;
float tolerance = 1f;
iTextSharp.text.Rectangle cropBox = reader.GetCropBox(i);
float widthToAdd = width - cropBox.Width;
float heightToAdd = height - cropBox.Height;
if (Math.Abs(widthToAdd) > tolerance || Math.Abs(heightToAdd) > tolerance)
{
float[] newBoxValues = new float[] {
cropBox.Left - marginLeft, // widthToAdd / 2,
cropBox.Bottom - marginBottom,// heightToAdd / 2,
cropBox.Right + marginRight, // widthToAdd / 2,
cropBox.Top + marginTop // heightToAdd / 2
};
PdfArray newBox = new PdfArray(newBoxValues);
PdfDictionary pDict = reader.GetPageN(i);
pDict.Put(PdfName.CROPBOX, newBox);
pDict.Put(PdfName.MEDIABOX, newBox);
}
//////////
}
}
}
}
The original code is borrowed from the answer given here: How to resize existing pdf page size
I am attempting to extract the audio content of a wav file and export the resultant waveform as an image (bmp/jpg/png).
So I have found the following code which draws a sine wave and works as expected:
string filename = #"C:\0\test.bmp";
int width = 640;
int height = 480;
Bitmap b = new Bitmap(width, height);
for (int i = 0; i < width; i++)
{
int y = (int)((Math.Sin((double)i * 2.0 * Math.PI / width) + 1.0) * (height - 1) / 2.0);
b.SetPixel(i, y, Color.Black);
}
b.Save(filename);
This works completely as expected, what I would like to do is replace
int y = (int)((Math.Sin((double)i * 2.0 * Math.PI / width) + 1.0) * (height - 1) / 2.0);
with something like
int y = converted and scaled float from monoWaveFileFloatValues
So how would I best go about doing this in the simplest manner possible?
I have 2 basic issues I need to deal with (i think)
convert float to int in a way which does not loose information, this is due to SetPixel(i, y, Color.Black); where x & y are both int
sample skipping on the x axis so the waveform fits into the defined space audio length / image width give the number of samples to average out intensity over which would be represented by a single pixel
The other options is find another method of plotting the waveform which does not rely on the method noted above. Using a chart might be a good method, but I would like to be able to render the image directly if possible
This is all to be run from a console application and I have the audio data (minus the header) already in a float array.
UPDATE 1
The following code enabled me to draw the required output using System.Windows.Forms.DataVisualization.Charting but it took about 30 seconds to process 27776 samples and whilst it does do what I need, it is far too slow to be useful. So I am still looking towards a solution which will draw the bitmap directly.
System.Windows.Forms.DataVisualization.Charting.Chart chart = new System.Windows.Forms.DataVisualization.Charting.Chart();
chart.Size = new System.Drawing.Size(640, 320);
chart.ChartAreas.Add("ChartArea1");
chart.Legends.Add("legend1");
// Plot {sin(x), 0, 2pi}
chart.Series.Add("sin");
chart.Series["sin"].LegendText = args[0];
chart.Series["sin"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Spline;
//for (double x = 0; x < 2 * Math.PI; x += 0.01)
for (int x = 0; x < audioDataLength; x ++)
{
//chart.Series["sin"].Points.AddXY(x, Math.Sin(x));
chart.Series["sin"].Points.AddXY(x, leftChannel[x]);
}
// Save sin_0_2pi.png image file
chart.SaveImage(#"c:\tmp\example.png", System.Drawing.Imaging.ImageFormat.Png);
Output shown below:
So I managed to figure it out using a code sample found here, though I made some minor changes to the way I interact with it.
public static Bitmap DrawNormalizedAudio(List<float> data, Color foreColor, Color backColor, Size imageSize, string imageFilename)
{
Bitmap bmp = new Bitmap(imageSize.Width, imageSize.Height);
int BORDER_WIDTH = 0;
float width = bmp.Width - (2 * BORDER_WIDTH);
float height = bmp.Height - (2 * BORDER_WIDTH);
using (Graphics g = Graphics.FromImage(bmp))
{
g.Clear(backColor);
Pen pen = new Pen(foreColor);
float size = data.Count;
for (float iPixel = 0; iPixel < width; iPixel += 1)
{
// determine start and end points within WAV
int start = (int)(iPixel * (size / width));
int end = (int)((iPixel + 1) * (size / width));
if (end > data.Count)
end = data.Count;
float posAvg, negAvg;
averages(data, start, end, out posAvg, out negAvg);
float yMax = BORDER_WIDTH + height - ((posAvg + 1) * .5f * height);
float yMin = BORDER_WIDTH + height - ((negAvg + 1) * .5f * height);
g.DrawLine(pen, iPixel + BORDER_WIDTH, yMax, iPixel + BORDER_WIDTH, yMin);
}
}
bmp.Save(imageFilename);
bmp.Dispose();
return null;
}
private static void averages(List<float> data, int startIndex, int endIndex, out float posAvg, out float negAvg)
{
posAvg = 0.0f;
negAvg = 0.0f;
int posCount = 0, negCount = 0;
for (int i = startIndex; i < endIndex; i++)
{
if (data[i] > 0)
{
posCount++;
posAvg += data[i];
}
else
{
negCount++;
negAvg += data[i];
}
}
if (posCount > 0)
posAvg /= posCount;
if (negCount > 0)
negAvg /= negCount;
}
In order to get it working I had to do a couple of things prior to calling the method DrawNormalizedAudio you can see below what I needed to do:
Size imageSize = new Size();
imageSize.Width = 1000;
imageSize.Height = 500;
List<float> lst = leftChannel.OfType<float>().ToList(); //change float array to float list - see link below
DrawNormalizedAudio(lst, Color.Red, Color.White, imageSize, #"c:\tmp\example2.png");
* change float array to float list
The result of this is as follows, a waveform representation of a hand clap wav sample:
I am quite sure there needs to be some updates/revisions to the code, but it's a start and hopefully this will assist someone else who is trying to do the same thing I was.
If you can see any improvements that can be made, let me know.
UPDATES
NaN issue mentioned in the comments now resolved and code above updated.
Waveform Image updated to represent output fixed by removal of NaN values as noted in point 1.
UPDATE 1
Average level (not RMS) was determined by summing the max level for each sample point and dividing by the total number of samples. Examples of this can be seen below:
Silent Wav File:
Hand Clap Wav File:
Brownian, Pink & White Noise Wav File:
Here is a variation you may want to study. It scales the Graphics object so it can use the float data directly.
Note how I translate (i.e. move) the drawing area twice so I can do the drawing more conveniently!
It also uses the DrawLines method for drawing. The benefit in addition to speed is that the lines may be semi-transparent or thicker than one pixel without getting artifacts at the joints. You can see the center line shine through.
To do this I convert the float data to a List<PointF> using a little Linq magick.
I also make sure to put all GDI+ objects I create in using clause so they will get disposed of properly.
...
using System.Windows.Forms;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
..
..
class Program
{
static void Main(string[] args)
{
float[] data = initData(10000);
Size imgSize = new Size(1000, 400);
Bitmap bmp = drawGraph(data, imgSize , Color.Green, Color.Black);
bmp.Save("D:\\wave.png", ImageFormat.Png);
}
static float[] initData(int count)
{
float[] data = new float[count];
for (int i = 0; i < count; i++ )
{
data[i] = (float) ((Math.Sin(i / 12f) * 880 + Math.Sin(i / 15f) * 440
+ Math.Sin(i / 66) * 110) / Math.Pow( (i+1), 0.33f));
}
return data;
}
static Bitmap drawGraph(float[] data, Size size, Color ForeColor, Color BackColor)
{
Bitmap bmp = new System.Drawing.Bitmap(size.Width, size.Height,
PixelFormat.Format32bppArgb);
Padding borders = new Padding(20, 20, 10, 50);
Rectangle plotArea = new Rectangle(borders.Left, borders.Top,
size.Width - borders.Left - borders.Right,
size.Height - borders.Top - borders.Bottom);
using (Graphics g = Graphics.FromImage(bmp))
using (Pen pen = new Pen(Color.FromArgb(224, ForeColor),1.75f))
{
g.SmoothingMode = SmoothingMode.AntiAlias;
g.Clear(Color.Silver);
using (SolidBrush brush = new SolidBrush(BackColor))
g.FillRectangle(brush, plotArea);
g.DrawRectangle(Pens.LightGoldenrodYellow, plotArea);
g.TranslateTransform(plotArea.Left, plotArea.Top);
g.DrawLine(Pens.White, 0, plotArea.Height / 2,
plotArea.Width, plotArea.Height / 2);
float dataHeight = Math.Max( data.Max(), - data.Min()) * 2;
float yScale = 1f * plotArea.Height / dataHeight;
float xScale = 1f * plotArea.Width / data.Length;
g.ScaleTransform(xScale, yScale);
g.TranslateTransform(0, dataHeight / 2);
var points = data.ToList().Select((y, x) => new { x, y })
.Select(p => new PointF(p.x, p.y)).ToList();
g.DrawLines(pen, points.ToArray());
g.ResetTransform();
g.DrawString(data.Length.ToString("###,###,###,##0") + " points plotted.",
new Font("Consolas", 14f), Brushes.Black,
plotArea.Left, plotArea.Bottom + 2f);
}
return bmp;
}
}
I'm creating a silverlight application where I have to dynamically create buttons. But I need to place them in a circle around the button that I click to generate the other buttons (picture here, the buttons should go on the black line surrounding the 'test project' button)
I don't know how many buttons will be generated each time but I do know the size of each button is static. I'm not quite sure how to do this. Currently my button creation is as follows
foreach (Item a in itemList)
{
Button newButton = new Button();
newButton.Height = 50;
newButton.Width = 50;
newButton.Content = a.getName();
newButton.Click += new RoutedEventHandler(addedClick);
newButton.HorizontalAlignment = HorizontalAlignment.Left;
newButton.VerticalAlignment = VerticalAlignment.Top;
newButton.Margin = new Thickness(0, 0, 0, 0);
newButton.Style = (Style)Application.Current.Resources["RB"];
buttons.Add(newButton);
}
My biggest problem is that I'm not quite sure how to get the center point of the 'test project' button.
EDIT: Okay, now that I have a set of coordinates for each button, how exactly do I go about placing them? I'm not sure how to use a canvas. I tried to set one up but it keeps acting like a stackpanel (no .setLeft/.setTop).
You mean something like the circle equation:
Double distanceFromCenter = 5;
Double angleInDegrees = 90;
Double angleAsRadians = (angleInDegrees* Math.PI) / 180.0;
Double centerX = 100;
Double centerY = 100;
Double x = centerX + Math.Cos(angleAsRadians) * distanceFromCenter;
Double y = centerY + Math.Sin(angleAsRadians) * distanceFromCenter;
that should give you a point that is distanceFromCenter units away from (centerX, center), at an angle of 90-degrees. Note this only works with radians so we have to convert to radians.
var radius = 100;
var angle = 360 / itmeList.Count * Math.PI / 180.0f;
var center = new Point(100, 100);
for (int i = 0; i < itemList.Count; i++)
{
var x = center.X + Math.Cos(angle * i) * radius;
var y = center.Y + Math.Sin(angle * i) * radius;
Button newButton = new Button();
newButton.RenderTransformOrigin = new Point(x, y);
newButton.Height = 50;
newButton.Width = 50;
newButton.Content = a.getName();
newButton.Click += new RoutedEventHandler(addedClick);
newButton.HorizontalAlignment = HorizontalAlignment.Left;
newButton.VerticalAlignment = VerticalAlignment.Top;
newButton.Margin = new Thickness(0, 0, 0, 0);
newButton.Style = (Style)Application.Current.Resources["RB"];
buttons.Add(newButton);
}
Assuming you want your buttons evenly spaced on the circle, you should first generate the list of angles you want them at. E.g.
double eachSection = 2 * Math.PI / count;
var anglesInRadians = Enumerable.Range(0, count).Select(x => x * eachSection);
Then use this formula to find the x/y coordinates of each angle, and use a Canvas or something to position the buttons in those positions
public static Point PointOnCircle(double radius, double angleInRadians, Point origin)
{
double x = radius * Math.Cos(angleInRadians) + origin.X;
double y = radius * Math.Sin(angleInRadians) + origin.Y;
return new Point(x, y);
}
How can i draw a polygon according to the input coordinates which are given in C#.
You didn't show any code because based on those coordinate, you are applying some form of scaling to the image.
Using the Paint event of a PictureBox, here is an example using those coordinates on the screen. It fills in the polygon, then draws the border, then it loops through all the points to draw the red circle:
void pictureBox1_Paint(object sender, PaintEventArgs e) {
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.Clear(Color.White);
// draw the shading background:
List<Point> shadePoints = new List<Point>();
shadePoints.Add(new Point(0, pictureBox1.ClientSize.Height));
shadePoints.Add(new Point(pictureBox1.ClientSize.Width, 0));
shadePoints.Add(new Point(pictureBox1.ClientSize.Width,
pictureBox1.ClientSize.Height));
e.Graphics.FillPolygon(Brushes.LightGray, shadePoints.ToArray());
// scale the drawing larger:
using (Matrix m = new Matrix()) {
m.Scale(4, 4);
e.Graphics.Transform = m;
List<Point> polyPoints = new List<Point>();
polyPoints.Add(new Point(10, 10));
polyPoints.Add(new Point(12, 35));
polyPoints.Add(new Point(22, 35));
polyPoints.Add(new Point(24, 22));
// use a semi-transparent background brush:
using (SolidBrush br = new SolidBrush(Color.FromArgb(100, Color.Yellow))) {
e.Graphics.FillPolygon(br, polyPoints.ToArray());
}
e.Graphics.DrawPolygon(Pens.DarkBlue, polyPoints.ToArray());
foreach (Point p in polyPoints) {
e.Graphics.FillEllipse(Brushes.Red,
new Rectangle(p.X - 2, p.Y - 2, 4, 4));
}
}
}
You may use Graphics.DrawPolygon. You can store the coordinates in an array of Point and then you can pass that to DrawPolygon method. You may wanna see:
Drawing with Graphics in WinForms using C#
private System.Drawing.Graphics g;
System.Drawing.Point[] p = new System.Drawing.Point[6];
p[0].X = 0;
p[0].Y = 0;
p[1].X = 53;
p[1].Y = 111;
p[2].X = 114;
p[2].Y = 86;
p[3].X = 34;
p[3].Y = 34;
p[4].X = 165;
p[4].Y = 7;
g = PictureBox1.CreateGraphics();
g.DrawPolygon(pen1, p);
This simple function is able to generate an array of PointF equal to the vertices of the regular polygon to be drawn, where "center" is the center of the polygon, "sides" is its number of sides, "sideLength" is the size of each side in pixels and "offset" is its slope.
public PointF[] GetRegularPolygonScreenVertex(Point center, int sides, int sideLength, float offset)
{
var points = new PointF[sides];
for (int i = 0; i < sides; i++)
{
points[i] = new PointF(
(float)(center.X + sideLength * Math.Cos((i * 360 / sides + offset) * Math.PI / 180f)),
(float)(center.Y + sideLength * Math.Sin((i * 360 / sides + offset) * Math.PI / 180f))
);
}
return points;
}
The result obtained can be used to draw a polygon, e.g. with the function:
GraphicsObject.DrawPolygon(new Pen(Brushes.Black, GetRegularPolygonScreenVertex(new Point(X, Y), 6, 30, 60f));
Which will generate a regular hexagon with a side of 30 pixels inclined by 30°.
hex