I have to do something like this.
When I click on a node, it expands, and this is OK (I am using Powercharts to do it).
My big problem is creating random coordinates so that when I open the subnode, it doesn't overlap with another node/subnode.
In the Powercharts I have to pass the coordinates, so the big problem is in passing it.
I have to do the random coordinates in C#.
//-------------------------------------------------------
This is what i did so far:
This is what i do, is not overlaping, but i have a problem.
how can i start do the circles from a starting point?
for example, starts in the middle (300,300) and then do circles around it. Is possible?
private void button2_Click(object sender, EventArgs e)
{
g = pictureBox1.CreateGraphics();
g.Clear(pictureBox1.BackColor);
double angle;
Circle item0 = new Circle();
item0.x=200;
item0.y=150;
item0.r=50;
listaCirculos.Add(item0);
Random randomMember = new Random();
g.DrawEllipse(pen1, 200, 150, 50, 50);
while(listaCirculos.Count!=11)
{
int[] it = GenerateNewCircle(600);
Circle item = new Circle();
item.x = it[0];
item.y = it[1];
item.r = 50;
if (circleIsAllowed(listaCirculos, item))
{
listaCirculos.Add(item);
g.DrawEllipse(pen1, Convert.ToInt32(item.x), Convert.ToInt32(item.y), 50, 50);
}
}
}
bool circleIsAllowed(List<Circle> circles, Circle newCircle)
{
foreach(Circle it in circles)
{
//double sumR = it.x + newCircle.r;
//double dx = it.x - newCircle.x;
//double dy = it.y - newCircle.y;
//double squaredDist = dx * dx + dy * dy;
double aX = Math.Pow(it.x - newCircle.x, 2);
double aY = Math.Pow(it.y - newCircle.y, 2);
double Dif = Math.Abs(aX - aY);
double ra1 = it.r / 2;
double ra2 = it.r / 2;
double raDif = Math.Pow(ra1 + ra2, 2);
if ((raDif + 1) > Dif) return false;
//if (squaredDist < sumR*sumR) return false;
}
return true; // no existing circle overlaps
}
public int[] GenerateNewCircle(int maxSize)
{
int x, y;
Random randomMember = new Random();
x = randomMember.Next(0,maxSize);
if (x - 50 < 0)
y = randomMember.Next(x + 50, maxSize);
else if (x + 50 > 600)
y = randomMember.Next(0, x - 50);
else
// in this case, x splits the range 0..n into 2 subranges.
// get a random number and skip the "gap" if necessary
y = randomMember.Next(0, maxSize - 50);
if (y > x - 50)
{
y += 20;
}
int[] abc = new int[2];
abc[0] = x;
abc[1] = y;
return abc;
}
Size sizeShape = new Size("SomeWidth" , "SomeHeight");
List<Retangle> rects = new List<Retangle>();
Random r = new Random();
while(rects.count != "someCount")
{
Point rPoint = new Point(r.Next(500) , r.Next(500))
bool isNew = true;
foreach(Rectangle r in rects)
{
if(r.contains(rPoint))
isNew = false;
}
if(isNew)
rects.Add(GetRect(rPoint , sizeShape));
}
private Rectangle GetRect(Point p , Size s)
{
return new Rectangle(p,s);
}
After than you can use from rects ,
rects has random coordinates.
Here's the link to let you know how to create Random Numbers in C#.
You have to keep in mind that you will generate random numbers, but you also have to make sure the numbers generated will not make objects overlap.
Despite this being pretty poorly worded, I believe what you are looking for is the Random class. It is instantiated as such:
Random thisRandom = new Random();
Then from there, if you want to generate a random coordinate, you need to know the maximum possible X and Y coordinates. Knowing these will allow you to generate X and Y coordinates within the given canvas as such:
int maxX = 500; //This is the maximum X value on your canvas
int maxY = 500; //This is the maximum Y value on your canvas
int newX, newY;
newX = thisRandom.Next(maxX);
newY = thisRandom.Next(maxY);
While its not the absolute best in terms of "true" randomization this should give you what you need.
Related
Hi I am trying to add sets of coordinates to a single line of a List (so x, y as a single list line). I am currently generating the x and y coordinates as I break up an image and display the chunks in a grid. I am hitting a brick wall in being able to add both x and y to the same List line. Here is the code I have so far -
float sf = 1f;
int x = 0;
int y = 0;
int width = tileImage.Width / tileNumber;
int height = tileImage.Height / tileNumber;
int placeXValue = (width / 10);
int placeYValue = (height / 10);
int placeX = placeXValue;
int placeY = placeYValue;
Rectangle tileRect = tileImage.Bounds;
tileRect.Width = width;
tileRect.Height = height;
coordinates = new List<int>();
for (int i = 0; i < tileNumber; i++)
{
for (int j = 0; j < tileNumber; j++)
{
tileRect.X = x;
tileRect.Y = y;
_spriteBatch.Draw(tileImage, new Vector2((x + placeX) * sf, (y + placeY) * sf), tileRect, Color.White, 0, new Vector2(0, 0), sf, SpriteEffects.None, 0);
placeX += placeXValue;
x += width;
coordinates.Add(x,y);
}
x = 0;
y += height;
placeX = placeXValue;
placeY += placeYValue;
}
I found out how to do what I was trying to in the question. The first thing that I did was change my - private List<int> coordinates; - to a tuple list like this - List<Tuple<int, int>> coordinates; - This then allowed me to add my x and y elements to a new list by using the - coordinates.Add(new Tuple<int, int>(x,y)); - tuple functionality. Making this change has allowed me to add my generated coordinate pairs to my list.
* Update *
Found a solution using Clipper library. Solution added as answer. New / better / easier ideas are still welcome though!
Given a path like this:
I want to create a path surrounding this path with a given distance, e.g. 1 cm. The following sketch demonstrates that - the red path surrounds the black path with a distance of 1 cm.
How can this be done in a generic way using PDFSharp? (Meaning I want to finally draw it with PDFSharp, I don't care where the calculations are done)
Here is the code for the black path:
// helper for easily getting an XPoint in centimeters
private XPoint cmPoint(double x, double y)
{
return new XPoint(
XUnit.FromCentimeter(x),
XUnit.FromCentimeter(y)
);
}
// the path to be drawn
private XGraphicsPath getMyPath()
{
XGraphicsPath path = new XGraphicsPath();
XPoint[] points = new XPoint[3];
points[0] = cmPoint(0, 0);
points[1] = cmPoint(5, 2);
points[2] = cmPoint(10,0);
path.AddCurve(points);
path.AddLine(cmPoint(10, 0), cmPoint(10, 10));
path.AddLine(cmPoint(10, 10), cmPoint(0, 10));
path.CloseFigure();
return path;
}
// generate the PDF file
private void button3_Click(object sender, RoutedEventArgs e)
{
// Create a temporary file
string filename = String.Format("{0}_tempfile.pdf", Guid.NewGuid().ToString("D").ToUpper());
XPen penBlack = new XPen(XColors.Black, 1);
XPen penRed = new XPen(XColors.Red, 1);
PdfDocument pdfDocument = new PdfDocument();
PdfPage page = pdfDocument.AddPage();
page.Size = PdfSharp.PageSize.A1;
XGraphics gfx = XGraphics.FromPdfPage(page);
//give us some space to the left and top
gfx.TranslateTransform(XUnit.FromCentimeter(3), XUnit.FromCentimeter(3));
// draw the desired path
gfx.DrawPath(penBlack, getMyPath());
// Save the pdfDocument...
pdfDocument.Save(filename);
// ...and start a viewer
Process.Start(filename);
}
Thanks for any help on this topic!
You can use Widen() function, which replaces the path with curves that enclose the area that is filled when the path is drawn by a specified pen, adding an additional outline to the path.
This function receives as parameter a XPen, so you can create this XPen using the desired offset as width and an outer path will be added at a constant distance (pen's width).
XGraphicsPath class is in fact a wrapper of System.Drawing.Drawing2D.GraphicsPath, so you can use Widen() function in XGraphicsPath, get the internal object and iterate on it using GraphicsPathIterator class to get the path added.
This method will do the job:
public XGraphicsPath GetSurroundPath(XGraphicsPath path, double width)
{
XGraphicsPath container = new XGraphicsPath();
container.StartFigure();
container.AddPath(path, false);
container.CloseFigure();
var penOffset = new XPen(XColors.Black, width);
container.StartFigure();
container.Widen(penOffset);
container.CloseFigure();
var iterator = new GraphicsPathIterator(container.Internals.GdiPath);
bool isClosed;
var outline = new XGraphicsPath();
iterator.NextSubpath(outline.Internals.GdiPath, out isClosed);
return outline;
}
You can handle level of flatness in curves using the overload Widen(XPen pen, XMatrix matrix, double flatness). Doing this call container.Widen(penOffset, XMatrix.Identity, 0.05); results in more rounded edges.
Then draw an outer path using this function:
string filename = String.Format("{0}_tempfile.pdf", Guid.NewGuid().ToString("D").ToUpper());
XPen penBlack = new XPen(XColors.Black, 1);
XPen penRed = new XPen(XColors.Red, 1);
PdfDocument pdfDocument = new PdfDocument();
PdfPage page = pdfDocument.AddPage();
page.Size = PdfSharp.PageSize.A1;
XGraphics gfx = XGraphics.FromPdfPage(page);
//give us some space to the left and top
gfx.TranslateTransform(XUnit.FromCentimeter(3), XUnit.FromCentimeter(3));
var path = getMyPath();
// draw the desired path
gfx.DrawPath(penBlack, path);
gfx.DrawPath(penRed, GetSurroundPath(path, XUnit.FromCentimeter(1).Point));
// Save the pdfDocument...
pdfDocument.Save(filename);
// ...and start a viewer
Process.Start(filename);
This is what you get:
Another way may be using reflection to retrieve internal Pen in XPen and setup CompoundArray property. This allows you draws parallel lines and spaces. Using this property you can do something like this:
But the problem is that you can only use one color, anyway this is just an idea, I have not tried in PDFsharp
Also, you should search for offset polyline curves or offsetting polygon algorithms.
This can be done using Clipper
double scale = 1024.0;
List<IntPoint> points = new List<IntPoint>();
points.Add(new IntPoint(0*scale, 0*scale));
points.Add(new IntPoint(5*scale, 2*scale));
points.Add(new IntPoint(10*scale, 0*scale));
points.Add(new IntPoint(10*scale, 10*scale));
points.Add(new IntPoint(0*scale, 10*scale));
points.Reverse();
List<List<IntPoint>> solution = new List<List<IntPoint>>();
ClipperOffset co = new ClipperOffset();
co.AddPath(points, JoinType.jtMiter, EndType.etClosedPolygon);
co.Execute(ref solution, 1 * scale);
foreach (IntPoint point in solution[0])
{
Console.WriteLine("OUTPUT: " + point.X + "/" + point.Y + " -> " + point.X/scale + "/" + point.Y/scale);
}
And the output:
OUTPUT: 11264/11264 -> 11/11
OUTPUT: -1024/11264 -> -1/11
OUTPUT: -1024/-1512 -> -1/-1,4765625
OUTPUT: 5120/945 -> 5/0,9228515625
OUTPUT: 11264/-1512 -> 11/-1,4765625
Drawn original and offset path:
This is still not perfect for various mathematical reasons, but already quite good.
This is an updated Answer requested
The XGraphicPath is sealed class which was implemented with bad practices IMO, so the only way is to use a wrapper around it. I tried to make the code as self documented as possible
public class OGraphicPath
{
private readonly ICollection<XPoint[]> _curves;
private readonly ICollection<Tuple<XPoint, XPoint>> _lines;
public OGraphicPath()
{
_lines = new List<Tuple<XPoint, XPoint>>();
_curves = new List<XPoint[]>();
}
public XGraphicsPath XGraphicsPath
{
get
{
var path = new XGraphicsPath();
foreach (var curve in _curves)
{
path.AddCurve(curve);
}
foreach (var line in _lines)
{
path.AddLine(line.Item1, line.Item2);
}
path.CloseFigure();
return path;
}
}
public void AddCurve(XPoint[] points)
{
_curves.Add(points);
}
public void AddLine(XPoint point1, XPoint point2)
{
_lines.Add(new Tuple<XPoint, XPoint>(point1, point2));
}
// Finds Highest and lowest X and Y to find the Center O(x,y)
private XPoint FindO()
{
var xs = new List<double>();
var ys = new List<double>();
foreach (var point in _curves.SelectMany(points => points))
{
xs.Add(point.X);
ys.Add(point.Y);
}
foreach (var line in _lines)
{
xs.Add(line.Item1.X);
xs.Add(line.Item2.X);
ys.Add(line.Item1.Y);
ys.Add(line.Item2.Y);
}
var OX = xs.Min() + xs.Max()/2;
var OY = ys.Min() + ys.Max()/2;
return new XPoint(OX, OY);
}
// If a point is above O, it's surrounded point is even higher, if it's below O, it's surrunded point is below O too...
private double FindPlace(double p, double o, double distance)
{
var dp = p - o;
if (dp < 0)
{
return p - distance;
}
if (dp > 0)
{
return p + distance;
}
return p;
}
public XGraphicsPath Surrond(double distance)
{
var path = new XGraphicsPath();
var O = FindO();
foreach (var curve in _curves)
{
var points = new XPoint[curve.Length];
for (var i = 0; i < curve.Length; i++)
{
var point = curve[i];
var x = FindPlace(point.X, O.X, distance);
var y = FindPlace(point.Y, O.Y, distance);
points[i] = new XPoint(x, y);
}
path.AddCurve(points);
}
foreach (var line in _lines)
{
var ax = FindPlace(line.Item1.X, O.X, distance);
var ay = FindPlace(line.Item1.Y, O.Y, distance);
var a = new XPoint(ax, ay);
var bx = FindPlace(line.Item2.X, O.X, distance);
var by = FindPlace(line.Item2.Y, O.Y, distance);
var b = new XPoint(bx, by);
path.AddLine(a, b);
}
path.CloseFigure();
return path;
}
}
And is Consumed Like this
// draw the desired path
var path = getMyPath();
gfx.DrawPath(penBlack, path.XGraphicsPath);
gfx.DrawPath(penRed, path.Surrond(XUnit.FromCentimeter(1)));
What if we made a "DrawOutline" extension to xGraphics?
public static class XGraphicsExtentions
{
public static void DrawOutline(this XGraphics gfx, XPen pen, XGraphicsPath path, int offset)
{
// finding the size of the original path so that we know how much to scale it in x and y
var points = path.Internals.GdiPath.PathPoints;
float minX, minY;
float maxX, maxY;
GetMinMaxValues(points, out minX, out minY, out maxX, out maxY);
var deltaY = XUnit.FromPoint(maxY - minY);
var deltaX = XUnit.FromPoint(maxX - minX);
var offsetInPoints = XUnit.FromCentimeter(offset);
var scaleX = XUnit.FromPoint((deltaX + offsetInPoints)/deltaX);
var scaleY = XUnit.FromPoint((deltaY + offsetInPoints)/deltaY);
var transform = -offsetInPoints/2.0;
gfx.TranslateTransform(transform, transform);
gfx.ScaleTransform(scaleX, scaleY);
gfx.DrawPath(pen, path);
// revert changes to graphics object before exiting
gfx.ScaleTransform(1/scaleX,1/scaleY);
gfx.TranslateTransform(-transform, -transform);
}
private static void GetMinMaxValues(PointF[] points, out float minX, out float minY, out float maxX, out float maxY)
{
minX = float.MaxValue;
maxX = float.MinValue;
minY = float.MaxValue;
maxY = float.MinValue;
foreach (var point in points)
{
if (point.X < minX)
minX = point.X;
if (point.X > maxX)
maxX = point.X;
if (point.Y < minY)
minY = point.Y;
if (point.Y > maxY)
maxY = point.Y;
}
}
}
Usage:
// draw the desired path
gfx.DrawPath(penBlack, getMyPath());
gfx.DrawOutline(penRed, getMyPath(), 2);
Result:
Clipper is a great choice, but depending on your needs it will not result in a perfect offset.
offset from edge is not equal to offset from corner
A better solution, which will require you to remove any beizer curves and only use line primitives, is using CGAL library for contour offsets: http://doc.cgal.org/latest/Straight_skeleton_2/index.html
Another way of doing it, which is actually pretty cool (albeit taking a lot of memory), is to convert your path to a bitmap and then apply a dilate operation, https://en.wikipedia.org/wiki/Dilation_(morphology). This will give you a correct transformation, but in the bitmap resolution.
You can the convert the bitmap to vector graphics, using a tool like https://en.wikipedia.org/wiki/Potrace
A good image toolbox is OpenCV, and http://www.emgu.com/wiki/index.php/Main_Page for .NET/C#. It includes dilation.
This will give you a somewhat limited resolution approach, but the end result will be precise to the bitmap resolution (and actually a lot higher since you are using a contour offset that, in fact, is limiting the offsetted contour details).
try this:
public Lis<Point> Draw(Point[] points /*Current polygon*/, int distance /*distance to new polygon*/) {
List<Point> lResult = new List<Point>();
foreach(Point lPoint in points) {
Point lNewPoint = new Point(lPoint.X - distance, lPoint.Y);
if(!CheckCurrentPoint(lNewPoint, points)) {
lResult.Add(lNewPoint)
continue;
}
lNewPoint = new Point(lPoint.X + distance, lPoint.Y);
if(!CheckCurrentPoint(lNewPoint, points)) {
lResult.Add(lNewPoint)
continue;
}
lNewPoint = new Point(lPoint.X, lPoint.Y - distance);
if(!CheckCurrentPoint(lNewPoint, points)) {
lResult.Add(lNewPoint)
continue;
}
lNewPoint = new Point(lPoint.X, lPoint.Y + distance);
if(!CheckCurrentPoint(lNewPoint, points)) {
lResult.Add(lNewPoint)
continue;
}
}
return lResult; // Points of new polygon
}
private static int Crs(Point a1, Point a2, Point p, ref bool ans) {
const double e = 0.00000000000001;
int lCrsResult = 0;
if (Math.Abs(a1.Y - a2.Y) < e)
if ((Math.Abs(p.Y - a1.Y) < e) && ((p.X - a1.X) * (p.X - a2.X) < 0.0))
ans = false;
if ((a1.Y - p.Y) * (a2.Y - p.Y) > 0.0)
return lCrsResult;
double lX = a2.X - (a2.Y - p.Y) / (a2.Y - a1.Y) * (a2.X - a1.X);
if (Math.Abs(lX - p.X) < e)
ans = false;
else if (lX < p.X) {
lCrsResult = 1;
if ((Math.Abs(a1.Y - p.Y) < e) && (a1.Y < a2.Y))
lCrsResult = 0;
else if ((Math.Abs(a2.Y - p.Y) < e) && (a2.Y < a1.Y))
lCrsResult = 0;
}
return lCrsResult;
}
private static bool CheckCurrentPoint(Point p /*Point of new posible polygon*/, Points[] points /*points of current polygon*/) {
if (points.Count == 0)
return false;
int lC = 0;
bool lAns = true;
for (int lIndex = 1; lIndex < points.Count; lIndex++) {
lC += Crs(points[lIndex - 1], points[lIndex], p, ref lAns);
if (!lAns)
return false;
}
lC += Crs(points[points.Count - 1], points[0], p, ref lAns);
if (!lAns)
return false;
return (lC & 1) > 0;
}
From mentioned sample in comments
I am using the Charts component in Windows Forms.
I create a straight line using
chart1.Series["Grenzwert"].Points.Add(new DataPoint(0, y));
chart1.Series["Grenzwert"].Points.Add(new DataPoint(maxwidth, y));
Also I plot a a series of points connected by a line, let's call it curve.
How do I show everything over straight line and under curve filled?
Column fills the whole area, not just above straight line.
Example:
This is late and not really short but imo it is the best way to color areas in a chart.
The Lines and also the Spline charttypes can be very precisely colored by coding the Paint event with the right data. The necessary pixel values can be obtained by the axis function ValueToPixelPosition. See here for another example!
The following code is a little longer because we need to add certain points at the start and end of both the chart and each colored area. Other than that it is very straight forward: Create GraphicsPaths by adding the pixel coordinates with AddLines and fill the GraphicsPaths in the Paint event.
For testing and for fun I have added a movable HorizontalLineAnnotation, so I can see how the areas vary when I drag it up and down..:
The Paint event is rather simple; it refers to a HorizontalLineAnnotation hl :
private void chart1_Paint(object sender, PaintEventArgs e)
{
double limit = hl.Y; // get the limit value
hl.X = 0; // reset the x value of the annotation
List<GraphicsPath> paths = getPaths(chart1.ChartAreas[0], chart1.Series[0], limit);
using (SolidBrush brush = new SolidBrush(Color.FromArgb(127, Color.Red)))
foreach (GraphicsPath gp in paths)
{ e.Graphics.FillPath(brush, gp); gp.Dispose(); }
}
The code to get the paths is obviously way too long for comfort..:
List<GraphicsPath> getPaths(ChartArea ca, Series ser, double limit)
{
List<GraphicsPath> paths = new List<GraphicsPath>();
List<PointF> points = new List<PointF>();
int first = 0;
float limitPix = (float)ca.AxisY.ValueToPixelPosition(limit);
for (int i = 0; i < ser.Points.Count; i++)
{
if ((ser.Points[i].YValues[0] > limit) && (i < ser.Points.Count - 1))
{
if (points.Count == 0) first = i; // remember group start
// insert very first point:
if (i == 0) points.Insert(0, new PointF(
(float)ca.AxisX.ValueToPixelPosition(ser.Points[0].XValue), limitPix));
points.Add( pointfFromDataPoint(ser.Points[i], ca)); // the regular points
}
else
{
if (points.Count > 0)
{
if (first > 0) points.Insert(0, median(
pointfFromDataPoint(ser.Points[first - 1], ca),
pointfFromDataPoint(ser.Points[first], ca), limitPix));
if (i == ser.Points.Count - 1)
{
if ((ser.Points[i].YValues[0] > limit))
points.Add(pointfFromDataPoint(ser.Points[i], ca));
points.Add(new PointF(
(float)ca.AxisX.ValueToPixelPosition(ser.Points[i].XValue), limitPix));
}
else
points.Add(median(pointfFromDataPoint(ser.Points[i - 1], ca),
pointfFromDataPoint(ser.Points[i], ca), limitPix));
GraphicsPath gp = new GraphicsPath();
gp.FillMode = FillMode.Winding;
gp.AddLines(points.ToArray());
gp.CloseFigure();
paths.Add(gp);
points.Clear();
}
}
}
return paths;
}
It uses two helper functions:
PointF pointfFromDataPoint(DataPoint dp, ChartArea ca)
{
return new PointF( (float)ca.AxisX.ValueToPixelPosition(dp.XValue),
(float)ca.AxisY.ValueToPixelPosition(dp.YValues[0]));
}
PointF median(PointF p1, PointF p2, float y0)
{
float x0 = p2.X - (p2.X - p1.X) * (p2.Y - y0) / (p2.Y - p1.Y);
return new PointF(x0, y0);
}
The HorizontalLineAnnotation is set up like this:
hl = new HorizontalLineAnnotation();
hl.AllowMoving = true;
hl.LineColor = Color.OrangeRed;
hl.LineWidth = 1;
hl.AnchorDataPoint = S1.Points[1];
hl.X = 0;
hl.Y = 0; // or some other starting value..
hl.Width = 100; // percent of chart..
hl.ClipToChartArea = chart1.ChartAreas[0].Name; // ..but clipped
chart1.Annotations.Add(hl);
I have an idea that use SeriesChartType.Range as follow.
private void UpdateChart(float straight_line, List<DataPoint> curve)
{
float y = straight_line; // YValue of the straight line
var list = curve.ToList(); // Clone the curve
int count = list.Count - 2;
for (int i = 0; i < count; i++) // Calculate intersection point between the straight line and a line between (x0,y0) and (x1,y1)
{
double x0 = list[i + 0].XValue;
double y0 = list[i + 0].YValues[0];
double x1 = list[i + 1].XValue;
double y1 = list[i + 1].YValues[0];
if ((y0 > y && y1 < y) || (y0 < y && y1 > y))
{
double x = (y - y0) * (x1 - x0) / (y1 - y0) + x0;
list.Add(new DataPoint(x, y));
}
}
list.Sort((a, b) => Math.Sign(a.XValue - b.XValue));
chart1.Series[0].Points.Clear();
chart1.Series[0].ChartType = SeriesChartType.Range;
chart1.Series[0].Color = Color.Red;
chart1.Series[0].BorderColor = Color.Cyan;
chart1.ChartAreas[0].AxisX.Minimum = 0;
chart1.ChartAreas[0].AxisX.Interval = 1;
for (int i = 0; i < list.Count; i++)
{
double xx = list[i].XValue;
double yy = list[i].YValues[0];
if (yy > y)
{
chart1.Series[0].Points.AddXY(xx, y, yy);
}
else
{
chart1.Series[0].Points.AddXY(xx, yy, yy);
}
}
chart1.ChartAreas[0].AxisY.StripLines.Add(new StripLine { IntervalOffset = y, Interval = 0, BorderColor = Color.Orange, BorderWidth = 2 });
}
As in the below drawing to judge whether the straight line and a line between (x0,y0) and (x1,y1) intersect, case 1 is (y0 < y && y1 > y) and case 2 is (y0 > y && y1 < y) . In case 1 and case 2, they intersect each other. In case 3 and case 4, they don't intersect each other.
You can do this as follows.
Set the column fill like you did before. Everything will be red.
Create a new column graph on the same chart.
Set its values to the same as your jagged line, but capped at the y value of the straight line you already have.
Set the fill colour for the columns to white. This will block out the red fill for any areas not between the lines.
i want to use my kinect to recognise certain objects. One of the methods that i want to use is the Houghtransformation. To do this i am using the AForge library.
But the lines that i find, are totally wrong. Important ones are missing and there are many useless lines in the picture.
To take care of this problem i thought:
First i am detecting the 100 most intense lines via hough to be sure that all the correct lines are detected as well.
I am writing all points from edge detection into a list and them I am checking for each line whether the detected line is at least on X points ( I used 15, 50 and 150) but nontheless my results are bad.
Have you got any idea, how i can find the right lines, before drawing them into the picture and analysing the geometry any further? Or maybe there is just a grave mistake in my code, that i dont see.
SobelEdgeDetector Kante = new SobelEdgeDetector();
System.Drawing.Bitmap neu2 = Kante.Apply(neu1);
neu2.Save("test.png");
for (int a = 0; a < 320; a++) //alle mögliche Kantenpunkte in eine Liste
{
for (int b = 0; b < 240; b++)
{
color = neu2.GetPixel(a, b);
if ((color.R+color.G+color.B)/3 >= 50)
{
Kantenpunkte.Add(new System.Drawing.Point(a, b));
}
}
}
Bitmap Hough = new Bitmap(320, 240);
Hough.Save("C:\\Users\\Nikolas Rieble\\Desktop\\Hough.png");
//houghtrans
HoughLineTransformation lineTransform = new HoughLineTransformation();
// apply Hough line transofrm
lineTransform.ProcessImage(neu2);
Bitmap houghLineImage = lineTransform.ToBitmap();
houghLineImage.Save("1.png");
// get most intensive lines
HoughLine[] lines = lineTransform.GetMostIntensiveLines(100);
UnmanagedImage fertig = UnmanagedImage.FromManagedImage(neu2);
foreach (HoughLine line in lines)
{
// get line's radius and theta values
int r = line.Radius;
double t = line.Theta;
// check if line is in lower part of the image
if (r < 0)
{
t += 180;
r = -r;
}
// convert degrees to radians
t = (t / 180) * Math.PI;
// get image centers (all coordinate are measured relative
// to center)
int w2 = neu2.Width / 2;
int h2 = neu2.Height / 2;
double x0 = 0, x1 = 0, y0 = 0, y1 = 0;
if (line.Theta != 0)
{
// none-vertical line
x0 = -w2; // most left point
x1 = w2; // most right point
// calculate corresponding y values
y0 = (-Math.Cos(t) * x0 + r) / Math.Sin(t);
y1 = (-Math.Cos(t) * x1 + r) / Math.Sin(t);
}
else
{
// vertical line
x0 = line.Radius;
x1 = line.Radius;
y0 = h2;
y1 = -h2;
}
// draw line on the image
int a = 0;
foreach (System.Drawing.Point p in Kantenpunkte) //count number of detected edge points that are on this line
{
double m1 = ((double)p.Y - y0)/((double)p.X - x0);
double m2 = ((y0 - y1)) / (x0 - x1);
if (m1-m2<0.0001)
{
a=a+1;
}
}
if (a > 150) //only draw lines, which cover at least A points
{
AForge.Imaging.Drawing.Line(fertig,
new IntPoint((int)x0 + w2, h2 - (int)y0),
new IntPoint((int)x1 + w2, h2 - (int)y1),
System.Drawing.Color.Red);
}
}
Everyone,
here is a link to a small python app:
http://en.wikipedia.org/wiki/File:Beta-skeleton.svg
I think I've correctly converted it. (Source at bottom of post)
But, the Math.Acos always returns NaN. Is there a difference between the python version of acos and Math.Acos?
private Random rnd = new Random();
private double scale = 5;
private double radius = 10;
private double beta1 = 1.1;
private double beta2 = 0.9;
private double theta1;
private double theta2;
private Point[] points = new Point[10];
public MainWindow()
{
InitializeComponent();
for (int i = 0; i < 100; i++ )
{
points[i] = new Point((rnd.NextDouble() * scale),
(rnd.NextDouble() * scale));
}
theta1 = Math.Asin(1/beta1);
theta2 = Math.PI - Math.Asin(beta2);
}
private double Dot(Point p, Point q, Point r)
{
var pr = new Point();
var qr = new Point();
//(p[0]-r[0])
pr.X = p.X-r.X;
//(p[1]-r[1])
pr.Y = p.Y-r.Y;
//(q[0]-r[0])
qr.X = q.X-r.X;
//(q[1]-r[1])
qr.Y = q.Y-r.Y;
return (pr.X*qr.X) + (pr.Y*qr.Y);
}
private double Sharp(Point p,Point q)
{
double theta = 0;
foreach(var pnt in points)
{
if(pnt!=p && pnt!=q)
{
var dotpq = Dot(p, q, pnt);
double t = Math.Acos(dotpq);
double u = Math.Pow((dotpq * dotpq), 0.5);
var tempVal = t/u;
theta = Math.Max(theta, tempVal);
}
}
return theta;
}
private void DrawPoint(Point p)
{
var e = new Ellipse
{
Width = radius/2,
Height = radius/2,
Stroke = Brushes.Red,
Visibility = Visibility.Visible
};
Canvas.SetTop(e, p.Y + radius);
Canvas.SetLeft(e, p.X + radius);
MyCanvas.Children.Add(e);
}
private void DrawEdge1(Point p,Point q)
{
var l = new Line
{
X1 = p.X,
Y1 = p.Y,
X2 = q.X,
Y2 = q.Y,
Stroke = Brushes.Black,
Width = 1,
Visibility = Visibility.Visible
};
MyCanvas.Children.Add(l);
}
private void DrawEdge2(Point p,Point q)
{
var l = new Line
{
X1 = p.X,
Y1 = p.Y,
X2 = q.X,
Y2 = q.Y,
Stroke = Brushes.Blue,
Width = 1,
Visibility = Visibility.Visible
};
MyCanvas.Children.Add(l);
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
foreach (var p in points)
{
foreach (var q in points)
{
var theta = Sharp(p, q);
if(theta < theta1) DrawEdge1(p, q);
else if(theta < theta2) DrawEdge2(p, q);
}
}
}
What you need to do to get the angle from the dot product is to take away the lengths before you acos.
What python has:
prq = acos(dot(p,q,r) / (dot(p,p,r)*dot(q,q,r))**0.5)
What you're doing is not dividing in the Acos, but dividing after.
so:
int r = pnt;
int ppr = Dot(p,p,r);
int qqr = Dot(q,q,r);
int pqr = Dot(p,q,r);
double u = Math.Acos(pqr / Math.Sqrt(ppr * qqr));
Of course change the variables, I was just trying to keep it similar to the python to help you understand :)
I think it's due to your translation of the Python expression (dot(p,q,r) / (dot(p,p,r) * dot(q,q,r)) **0.5). Exponentiation in Python has one of the lowest operators precedency-wise, so the square-root is being taken of the subterm dot(p,q,r) / (dot(p,p,r) * dot(q,q,r)). In your C# version, when calculating the value of the double 'u', you're only taking the square-root of the product of the last two terms, i.e. the (dotpq * dotpq).
The question really is what is the value of dotpq when the function gets called. It has to be a double value between -1 and 1 as stated in the docs.