I am find out the Image Coutours by Halcon,then I will determine turning Points
in Contours (x,y).
The following figures
Contour Image
I reference the calculate turning points / pivot points in trajectory (path)
Use Ramer-Douglas-Peucker(RDP) algorithm and the Result
RDP Result Image
I Want to get the Result follwing figures
I Want Result Image
public class Douglas
{
public List<Point> DouglasThinningMachine(List<Point> spList,double threshold=10)
{
if (spList == null)
{
throw new ArgumentNullException(nameof(spList));
}
int max = spList.Count;
int location = 0;
Stack<int> A = new Stack<int>();
Stack<int> B = new Stack<int>();
A.Push(0);
B.Push(max - 1);
do
{
var d = FindMostDistance(spList, A.Peek(), B.Peek(), ref location);
if (d > threshold)
{
B.Push(location);
}
else
{
A.Push(location);
B.Pop();
}
} while (B.Count > 0);
List<int> listOfIndex = A.ToList();
listOfIndex.Sort();
List<Point> result = new List<Point>();
foreach (int index in listOfIndex)
{
result.Add(spList[index]);
}
return result;
}
private double FindMostDistance(List<Point> seriesPoints, int start, int end, ref int location)
{
if (end - start <= 1)
{
location = end;
return 0;
}
double result = 0;
Point startPoint = seriesPoints[start];
Point endPoint = seriesPoints[end];
for (int i = start + 1; i < end; i++)
{
var d = GetDistanceToLine(startPoint, endPoint, seriesPoints[i]);
if (d > result)
{
result = d;
location = i;
}
}
return result;
}
public double GetDistanceToLine(double p1x, double p1y, double p2x, double p2y, double refpx, double refpy)
=> Math.Abs(((p2y - p1y) * (refpx - p1x)) - ((refpy - p1y) * (p2x - p1x))) / Math.Pow(((p2y - p1y) * (p2y - p1y)) + ((p2x - p1x) * (p2x - p1x)), 0.5);
public double GetDistanceToLine(Point point1, Point point2, Point refPoint)
{
return GetDistanceToLine(point1.X, point1.Y, point2.X, point2.Y, refPoint.X, refPoint.Y);
}
}
Main Code:
List<Point> PP = new List<Point>();
for (int i = 0; i < XX.Count; i++)
{
PP.Add(new Point() { X = Convert.ToInt32(XX[i]), Y = Convert.ToInt32(yy[i]) });
}
Douglas dg = new Douglas();
var ggg = dg.DouglasThinningMachine(PP,10);
for (int i = 0; i < XX.Count; i++)
{
chart1.Series[0].Points.AddXY(XX[i], yy[i]);
}
foreach( var g in ggg)
{
chart1.Series[1].Points.AddXY(g.X,g.Y);
}
for (int i = 0; i < XX.Count; i++)
{
chart1.Series[2].Points.AddXY(XX[i], result[i]);
}
Contour Data Link
// Read *.csv file in Halcon:
open_file (Path, 'input', FileHandle)
fread_line (FileHandle, OutLine, IsEOF)
tuple_split (OutLine, ',', Substrings)
tuple_str_first_n (Substrings[|Substrings|-1], strlen(Substrings[|Substrings|-1])-2, Substring)
Substrings[|Substrings|-1] := Substring
tuple_number (Substrings, Result)
close_file (FileHandle)
// Generate contours and split them
gen_contour_polygon_xld (Contour, -Y, X)
gen_polygons_xld (Contour, Polygons, 'ramer', 5)
split_contours_xld (Polygons, Contours, 'polygon', 3, 5)
You can adjust the parameters in gen_polygons_xld and split_contours_xld to get the connections you'd like.
Related
This is a physics problem
So I have a group of rectangles I am trying to movie towards a point. I wanted to prevent them from getting into each other so I developed a custom physics engine that detect rectangle collision.
my problem here is that I can’t seem to get the wanted behaviour at all.
Here is what I have :
my current state
Here is what I Need:
The state I need
And Here is my current code:
private void RunScript(int iterations, List<Rectangle3d> spaces, Polyline boundary, List<int> lineStartIndices, List<int> lineEndIndices, List<int> viewIndex, List<int> orientationIndex, List<Point3d> cardinals, double moveDistance, double collisionDistance, double approximationMultiplier, double orientationMultiplier, List<double> spaceProximityMultipliers, List<double> spaceOrientationMultipliers, bool iterationMode, bool start, bool reset, ref object Vectors, ref object A, ref object B, ref object C)
{
List<Line> collisionDisplay = new List<Line>();
List<Line> collisionDisplay2 = new List<Line>();
if(iterationMode)
{
tempSpaces = spaces;
//--------------------------------------------------------------------
//iterate is start button is set to true
//--------------------------------------------------------------------
for(int i = 0; i < iterations;i++)
// Parallel.For(0, iterations, i =>
{
var collision = new RectangleCollider(moveDistance, collisionDistance,
approximationMultiplier, orientationMultiplier, boundary, tempSpaces);
collision.MoveRectangles();
collision.ApplyMove();
tempSpaces = collision.ResultingSpacesArr.ToList();
}
}
else
{
//--------------------------------------------------------------------
//reset loop on switch press
//--------------------------------------------------------------------
if(reset || counter == 0)
{
tempSpaces = spaces;
velocity = moveDistance;
counter = 0;
}
//--------------------------------------------------------------------
//iterate is start button is set to true
//--------------------------------------------------------------------
if(start)
{
GrasshopperDocument.ScheduleSolution(10, ScheduleSolutionCallback);
//loop logic if start is true
var collision = new RectangleCollider(velocity, collisionDistance,
approximationMultiplier, orientationMultiplier, boundary, tempSpaces);
collision.MoveRectangles();
collision.CollideRectangles();
collision.ApplyMove();
tempSpaces = collision.ResultingSpacesArr.ToList();
velocity = collision.MoveDistance;
counter++;
//output
Vectors = collision.MovementVectors;
}
}
//--------------------------------------------------------------------
//output
//--------------------------------------------------------------------
//gh conversion
var ghRects = new List<GH_Rectangle>();
for(int i = 0; i < tempSpaces.Count; i++)
ghRects.Add(new GH_Rectangle(tempSpaces[i]));
var ghCollisionDisplay = new List<GH_Line>();
for(int i = 0; i < collisionDisplay.Count; i++)
ghCollisionDisplay.Add(new GH_Line(collisionDisplay[i]));
var ghCollisionDisplay2 = new List<GH_Line>();
for(int i = 0; i < collisionDisplay2.Count; i++)
ghCollisionDisplay2.Add(new GH_Line(collisionDisplay2[i]));
A = ghRects;
B = ghCollisionDisplay;
C = ghCollisionDisplay2;
//display no of iterations on console
Print("Iterations: " + (counter).ToString());
Print("velocity: " + (velocity).ToString());
}
// <Custom additional code>
//params
List<Rectangle3d> tempSpaces = new List<Rectangle3d>();
double velocity;
int counter;
//iteration logic
public void ScheduleSolutionCallback(GH_Document doc)
{
this.Component.ExpireSolution(false);
}
//--------------------------------------------------------------------
//Collision class
//--------------------------------------------------------------------
public class RectangleCollider
{
public double MoveDistance;
public double CollisionDistance;
public double ApproximationMultiplier;
public double OrientationMultiplier;
public Polyline Boundary;
public Point3d Center;
public List<Rectangle3d> Spaces;
public Rectangle3d[] ResultingSpacesArr;
public Vector3d[] MovementVectors;
public bool IsColliding = false;
public RectangleCollider(double moveDistance, double collisionDistance,
double approximationMultiplier, double orientationMultiplier,
Polyline boundary, List<Rectangle3d> spaces)
{
MoveDistance = moveDistance;
CollisionDistance = collisionDistance;
ApproximationMultiplier = approximationMultiplier;
OrientationMultiplier = orientationMultiplier;
Boundary = boundary;
Spaces = spaces;
Center = boundary.CenterPoint();
MovementVectors = new Vector3d[spaces.Count];
}
//Move Points
public void MoveRectangles()
{
for(int i = 0; i < Spaces.Count; i++)
{
if(Spaces[i].Center.DistanceTo(Center) > 1 && !IsColliding)
{
Vector3d translationVector = Center - Spaces[i].Center;
if(Math.Abs(Center.X - Spaces[i].Center.X) > Math.Abs(Center.Y - Spaces[i].Center.Y))
{
var xVector = new Vector3d(translationVector.X, 0, 0);
xVector.Unitize();
MovementVectors[i] += xVector * 0.5;
}
else
{
var yVector = new Vector3d(0, translationVector.Y, 0);
yVector.Unitize();
MovementVectors[i] += yVector * 0.5;
}
}
}
}
//collide rectangles
public void CollideRectangles()
{
Parallel.For(0, Spaces.Count, i =>
{
for(int j = 0; j < Spaces.Count; j++)
{
if(i != j)
{
var rect1MinX = Spaces[i].Corner(0).X;
var rect1MaxX = Spaces[i].Corner(2).X;
var rect1MinY = Spaces[i].Corner(0).Y;
var rect1MaxY = Spaces[i].Corner(2).Y;
var rect1Center = Spaces[i].Center;
var rect2MinX = Spaces[j].Corner(0).X;
var rect2MaxX = Spaces[j].Corner(2).X;
var rect2MinY = Spaces[j].Corner(0).Y;
var rect2MaxY = Spaces[j].Corner(2).Y;
var rect2Center = Spaces[j].Center;
if((rect1MinX < rect2MaxX && rect1MaxX > rect2MinX) &&
(rect1MinY < rect2MaxY && rect1MaxY > rect2MinY))
{
//stop if they collide
IsColliding = true;
//if they collide in x
if ( rect1MinX < rect2MaxX && rect1MaxX > rect2MinX )
{
MovementVectors[j].X += -MovementVectors[j].X;
}
//if they collide in y
if ( rect1MinY < rect2MaxY && rect1MaxY > rect2MinY )
{
MovementVectors[j].Y += -MovementVectors[j].Y;
}
}
else {
IsColliding = false;
}
}
}
}
);
}
//apply move
public void ApplyMove()
{
var spacesArr = Spaces.ToArray();
for(int i = 0; i < Spaces.Count; i++)
{
var move = Transform.Translation(MovementVectors[i]);
spacesArr[i].Transform(move);
}
ResultingSpacesArr = spacesArr;
}
}
// </Custom additional code>
}
please tell me anything you know. As have been stuck in this for months and researched it so much on many engines but didn’t find the right answer(or didn’t have enough understanding)
thank you in advance.
I have to calculate the spectrum values of an audio.
I used aForge's FFT in Sources/Math/FourierTransform.cs and I used an example of sampling with 16 samples as used in this video to check the results with excel (I tested the results in a spreadsheet like in the video).
FFT:
public enum Direction
{
Forward = 1,
Backward = -1
};
private const int minLength = 2;
private const int maxLength = 16384;
private const int minBits = 1;
private const int maxBits = 14;
private static int[][] reversedBits = new int[maxBits][];
private static Complex[,][] complexRotation = new Complex[maxBits, 2][];
static void Main(string[] args)
{
var Data = new Complex[16];
Data[0] = new Complex(0, 0);
Data[1] = new Complex((float)0.998027, 0);
Data[2] = new Complex((float)0.125333, 0);
Data[3] = new Complex((float)-0.98229, 0);
Data[4] = new Complex((float)-0.24869, 0);
Data[5] = new Complex((float)0.951057, 0);
Data[6] = new Complex((float)0.368125, 0);
Data[7] = new Complex((float)-0.90483, 0);
Data[8] = new Complex((float)-0.48175, 0);
Data[9] = new Complex((float)0.844328, 0);
Data[10] = new Complex((float)0.587785, 0);
Data[11] = new Complex((float)-0.77051, 0);
Data[12] = new Complex((float)-0.68455, 0);
Data[13] = new Complex((float)0.684547, 0);
Data[14] = new Complex((float)0.770513, 0);
Data[15] = new Complex((float)-0.58779, 0);
FFT(Data, Direction.Forward);
for (int a = 0; a <= Data.Length - 1; a++)
{
Console.WriteLine(Data[a].Re.ToString());
}
Console.ReadLine();
}
public static void FFT(Complex[] data, Direction direction)
{
int n = data.Length;
int m = Tools.Log2(n);
// reorder data first
ReorderData(data);
// compute FFT
int tn = 1, tm;
for (int k = 1; k <= m; k++)
{
Complex[] rotation = GetComplexRotation(k, direction);
tm = tn;
tn <<= 1;
for (int i = 0; i < tm; i++)
{
Complex t = rotation[i];
for (int even = i; even < n; even += tn)
{
int odd = even + tm;
Complex ce = data[even];
Complex co = data[odd];
double tr = co.Re * t.Re - co.Im * t.Im;
double ti = co.Re * t.Im + co.Im * t.Re;
data[even].Re += tr;
data[even].Im += ti;
data[odd].Re = ce.Re - tr;
data[odd].Im = ce.Im - ti;
}
}
}
if (direction == Direction.Forward)
{
for (int i = 0; i < n; i++)
{
data[i].Re /= (double)n;
data[i].Im /= (double)n;
}
}
}
private static int[] GetReversedBits(int numberOfBits)
{
if ((numberOfBits < minBits) || (numberOfBits > maxBits))
throw new ArgumentOutOfRangeException();
// check if the array is already calculated
if (reversedBits[numberOfBits - 1] == null)
{
int n = Tools.Pow2(numberOfBits);
int[] rBits = new int[n];
// calculate the array
for (int i = 0; i < n; i++)
{
int oldBits = i;
int newBits = 0;
for (int j = 0; j < numberOfBits; j++)
{
newBits = (newBits << 1) | (oldBits & 1);
oldBits = (oldBits >> 1);
}
rBits[i] = newBits;
}
reversedBits[numberOfBits - 1] = rBits;
}
return reversedBits[numberOfBits - 1];
}
private static Complex[] GetComplexRotation(int numberOfBits, Direction direction)
{
int directionIndex = (direction == Direction.Forward) ? 0 : 1;
// check if the array is already calculated
if (complexRotation[numberOfBits - 1, directionIndex] == null)
{
int n = 1 << (numberOfBits - 1);
double uR = 1.0;
double uI = 0.0;
double angle = System.Math.PI / n * (int)direction;
double wR = System.Math.Cos(angle);
double wI = System.Math.Sin(angle);
double t;
Complex[] rotation = new Complex[n];
for (int i = 0; i < n; i++)
{
rotation[i] = new Complex(uR, uI);
t = uR * wI + uI * wR;
uR = uR * wR - uI * wI;
uI = t;
}
complexRotation[numberOfBits - 1, directionIndex] = rotation;
}
return complexRotation[numberOfBits - 1, directionIndex];
}
// Reorder data for FFT using
private static void ReorderData(Complex[] data)
{
int len = data.Length;
// check data length
if ((len < minLength) || (len > maxLength) || (!Tools.IsPowerOf2(len)))
throw new ArgumentException("Incorrect data length.");
int[] rBits = GetReversedBits(Tools.Log2(len));
for (int i = 0; i < len; i++)
{
int s = rBits[i];
if (s > i)
{
Complex t = data[i];
data[i] = data[s];
data[s] = t;
}
}
}
These are the results after the transformation:
Output FFT results: Excel FFT results:
0,0418315622955561 0,669305
0,0533257974328085 0,716163407
0,137615673627316 0,908647001
0,114642731070279 1,673453043
0,234673940537634 7,474988602
0,0811255020953362 0,880988382
0,138088891589122 0,406276784
0,0623766891658306 0,248854492
0,0272978749126196 0,204227
0,0124250144575261 0,248854492
0,053787064184711 0,406276784
0,00783331226557493 0,880988382
0,0884368745610118 7,474988602
0,0155431246384978 1,673453043
0,0301093757152557 0,908647001
0 0,716163407
The results are not at all similar. Where is it wrong?
Is the implementation of complex (Data) wrong or is the FFT method wrong or other?
Thanks in advance!
First, the resulting FFT is a complex function in general. You're only displaying the real parts in your code but the thing you're comparing to is displaying the magnitudes, so of course they're going to be different: you're comparing apples to oranges.
When you use magnitudes and compare apples to apples, you should get this:
for (int a = 0; a <= Data.Length - 1; a++)
{
Console.WriteLine(Data[a].Magnitude.ToString());
}
...
0.0418315622955561
0.0447602132472683
0.0567904388057513
0.104590813761862
0.46718679147454
0.0550617784710375
0.025392294285886
0.0155534081359397
0.0127641875296831
0.0155534081359397
0.025392294285886
0.0550617784710375
0.46718679147454
0.104590813761862
0.0567904388057513
0.0447602132472683
That looks a little better -- it has the same symmetry property as the Excel output and there appear to be peaks in the same locations.
It almost looks like the scale is off. If I divide each element by the corresponding element from the Excel output, I get:
16
16
16
16
16
16
16
16
16
16
16
16
16
16
16
16
So your results are pretty much correct, just off by a scaling factor.
You're dividing everything by n in the last step of your FFT:
if (direction == Direction.Forward)
{
for (int i = 0; i < n; i++)
{
data[i].Re /= (double)n;
data[i].Im /= (double)n;
}
}
This is conventionally done for the inverse transform, not the forward transform.
In summary, changing the output from Data[a].Re to Data[a].Magnitude and changing the condition at the end of FFT from if (direction == Direction.Forward) to if (direction == Direction.Backward), I get this output:
0.669304996728897
0.716163411956293
0.908647020892022
1.67345302018979
7.47498866359264
0.880988455536601
0.406276708574176
0.248854530175035
0.20422700047493
0.248854530175035
0.406276708574176
0.880988455536601
7.47498866359264
1.67345302018979
0.908647020892022
0.716163411956293
which matches the Excel output.
I have two Line Segments, represented by a 3D point at their beginning/end points.
Line:
class Line
{
public string Name { get; set; }
public Point3D Start { get; set; } = new Point3D();
public Point3D End { get; set; } = new Point3D();
}
The 3D points are just 3 doubles for coordinates X,Y and Z.
3DPoint:
class Point3D
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
}
The Question:
Can I find the distance between two 'Lines' and the endpoints of that distance 'Line'. [1
What I have:
Currently, I can successfully get the distance between the two lines with this code (Adapted From Here Using the Segment To Segment Section):
public double lineNearLine(Line l1, Line l2)
{
Vector3D uS = new Vector3D { X = l1.Start.X, Y = l1.Start.Y, Z = l1.Start.Z };
Vector3D uE = new Vector3D { X = l1.End.X, Y = l1.End.Y, Z = l1.End.Z };
Vector3D vS = new Vector3D { X = l2.Start.X, Y = l2.Start.Y, Z = l2.Start.Z };
Vector3D vE = new Vector3D { X = l2.End.X, Y = l2.End.Y, Z = l2.End.Z };
Vector3D w1 = new Vector3D { X = l1.Start.X, Y = l1.Start.Y, Z = l1.Start.Z };
Vector3D w2 = new Vector3D { X = l2.Start.X, Y = l2.Start.Y, Z = l2.Start.Z };
Vector3D u = uE - uS;
Vector3D v = vE - vS;
Vector3D w = w1 - w2;
double a = Vector3D.DotProduct(u, u);
double b = Vector3D.DotProduct(u, v);
double c = Vector3D.DotProduct(v, v);
double d = Vector3D.DotProduct(u, w);
double e = Vector3D.DotProduct(v, w);
double D = a * c - b * b;
double sc, sN, sD = D;
double tc, tN, tD = D;
if (D < 0.01)
{
sN = 0;
sD = 1;
tN = e;
tD = c;
}
else
{
sN = (b * e - c * d);
tN = (a * e - b * d);
if (sN < 0)
{
sN = 0;
tN = e;
tD = c;
}
else if (sN > sD)
{
sN = sD;
tN = e + b;
tD = c;
}
}
if (tN < 0)
{
tN = 0;
if (-d < 0)
{
sN = 0;
}
else if (-d > a)
{
sN = sD;
}
else
{
sN = -d;
sD = a;
}
}
else if (tN > tD)
{
tN = tD;
if ((-d + b) < 0)
{
sN = 0;
}
else if ((-d + b) > a)
{
sN = sD;
}
else
{
sN = (-d + b);
sD = a;
}
}
if (Math.Abs(sN) < 0.01)
{
sc = 0;
}
else
{
sc = sN / sD;
}
if (Math.Abs(tN) < 0.01)
{
tc = 0;
}
else
{
tc = tN / tD;
}
Vector3D dP = w + (sc * u) - (tc * v);
double distance1 = Math.Sqrt(Vector3D.DotProduct(dP, dP));
return distance1;
}
What I Need:
Is there any way to determine the endpoints of the displacement vector 'dP' from the code above? If not, can anyone suggest a better method for finding minimum distance and the endpoints of that distance?
Thank you for Reading, and Thanks in advance for any suggestions!
An Enormous Thank You to #Isaac van Bakel for the theory behind this Solution
Here is my code complete: Shortest distance between two lines represented by the line that connects them at that shortest distance.
Classes:
Sharp3D.Math : I use this reference for Vector3D, but really any 3D vector class will work. On top of that, the vectors aren't even required if you do the subtraction element by element.
Point3D : My Personal Point3D class. Feel free to use as much or little as you want.
class Point3D
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
public Vector3D getVector()
{
return new Vector3D { X = this.X, Y = this.Y, Z = this.Z };
}
}
Line : My Personal Line class. Feel free to use as much or little as you want.
class Line
{
public string Name { get; set; }
public Point3D Start { get; set; } = new Point3D();
public Point3D End { get; set; } = new Point3D();
public double Length
{
get
{
return Math.Sqrt(Math.Pow((End.X - Start.X), 2) + Math.Pow((End.Y - Start.Y), 2));
}
}
}
Functions:
ClampPointToLine : Clamping function I wrote to clamp a point to a line.
public Point3D ClampPointToLine(Point3D pointToClamp, Line lineToClampTo)
{
Point3D clampedPoint = new Point3D();
double minX, minY, minZ, maxX, maxY, maxZ;
if(lineToClampTo.Start.X <= lineToClampTo.End.X)
{
minX = lineToClampTo.Start.X;
maxX = lineToClampTo.End.X;
}
else
{
minX = lineToClampTo.End.X;
maxX = lineToClampTo.Start.X;
}
if (lineToClampTo.Start.Y <= lineToClampTo.End.Y)
{
minY = lineToClampTo.Start.Y;
maxY = lineToClampTo.End.Y;
}
else
{
minY = lineToClampTo.End.Y;
maxY = lineToClampTo.Start.Y;
}
if (lineToClampTo.Start.Z <= lineToClampTo.End.Z)
{
minZ = lineToClampTo.Start.Z;
maxZ = lineToClampTo.End.Z;
}
else
{
minZ = lineToClampTo.End.Z;
maxZ = lineToClampTo.Start.Z;
}
clampedPoint.X = (pointToClamp.X < minX) ? minX : (pointToClamp.X > maxX) ? maxX : pointToClamp.X;
clampedPoint.Y = (pointToClamp.Y < minY) ? minY : (pointToClamp.Y > maxY) ? maxY : pointToClamp.Y;
clampedPoint.Z = (pointToClamp.Z < minZ) ? minZ : (pointToClamp.Z > maxZ) ? maxZ : pointToClamp.Z;
return clampedPoint;
}
distanceBetweenLines : The function that returns the line that represents the shortest distance between two lines. Returns null if unsolvable.
public Line distBetweenLines(Line l1, Line l2)
{
Vector3D p1, p2, p3, p4, d1, d2;
p1 = l1.Start.getVector();
p2 = l1.End.getVector();
p3 = l2.Start.getVector();
p4 = l2.End.getVector();
d1 = p2 - p1;
d2 = p4 - p3;
double eq1nCoeff = (d1.X * d2.X) + (d1.Y * d2.Y) + (d1.Z * d2.Z);
double eq1mCoeff = (-(Math.Pow(d1.X, 2)) - (Math.Pow(d1.Y, 2)) - (Math.Pow(d1.Z, 2)));
double eq1Const = ((d1.X * p3.X) - (d1.X * p1.X) + (d1.Y * p3.Y) - (d1.Y * p1.Y) + (d1.Z * p3.Z) - (d1.Z * p1.Z));
double eq2nCoeff = ((Math.Pow(d2.X, 2)) + (Math.Pow(d2.Y, 2)) + (Math.Pow(d2.Z, 2)));
double eq2mCoeff = -(d1.X * d2.X) - (d1.Y * d2.Y) - (d1.Z * d2.Z);
double eq2Const = ((d2.X * p3.X) - (d2.X * p1.X) + (d2.Y * p3.Y) - (d2.Y * p2.Y) + (d2.Z * p3.Z) - (d2.Z * p1.Z));
double[,] M = new double[,] { { eq1nCoeff, eq1mCoeff, -eq1Const }, { eq2nCoeff, eq2mCoeff, -eq2Const } };
int rowCount = M.GetUpperBound(0) + 1;
// pivoting
for (int col = 0; col + 1 < rowCount; col++) if (M[col, col] == 0)
// check for zero coefficients
{
// find non-zero coefficient
int swapRow = col + 1;
for (; swapRow < rowCount; swapRow++) if (M[swapRow, col] != 0) break;
if (M[swapRow, col] != 0) // found a non-zero coefficient?
{
// yes, then swap it with the above
double[] tmp = new double[rowCount + 1];
for (int i = 0; i < rowCount + 1; i++)
{ tmp[i] = M[swapRow, i]; M[swapRow, i] = M[col, i]; M[col, i] = tmp[i]; }
}
else return null; // no, then the matrix has no unique solution
}
// elimination
for (int sourceRow = 0; sourceRow + 1 < rowCount; sourceRow++)
{
for (int destRow = sourceRow + 1; destRow < rowCount; destRow++)
{
double df = M[sourceRow, sourceRow];
double sf = M[destRow, sourceRow];
for (int i = 0; i < rowCount + 1; i++)
M[destRow, i] = M[destRow, i] * df - M[sourceRow, i] * sf;
}
}
// back-insertion
for (int row = rowCount - 1; row >= 0; row--)
{
double f = M[row, row];
if (f == 0) return null;
for (int i = 0; i < rowCount + 1; i++) M[row, i] /= f;
for (int destRow = 0; destRow < row; destRow++)
{ M[destRow, rowCount] -= M[destRow, row] * M[row, rowCount]; M[destRow, row] = 0; }
}
double n = M[0, 2];
double m = M[1, 2];
Point3D i1 = new Point3D { X = p1.X + (m * d1.X), Y = p1.Y + (m * d1.Y), Z = p1.Z + (m * d1.Z) };
Point3D i2 = new Point3D { X = p3.X + (n * d2.X), Y = p3.Y + (n * d2.Y), Z = p3.Z + (n * d2.Z) };
Point3D i1Clamped = ClampPointToLine(i1, l1);
Point3D i2Clamped = ClampPointToLine(i2, l2);
return new Line { Start = i1Clamped, End = i2Clamped };
}
Implementation:
Line shortestDistanceLine = distBetweenLines(l1, l2);
Results:
So far this has been accurate in my testing. Returns null if passed two identical lines. I appreciate any feedback!
The shortest distance between two skew lines (lines which don't intersect) is the distance of the line which is perpendicular to both of them.
If we have a line l1 with known points p1 and p2, and a line l2 with known points p3 and p4:
The direction vector of l1 is p2-p1, or d1.
The direction vector of l2 is p4-p3, or d2.
We therefore know that the vector we are looking for, v, is perpendicular to both of these direction vectors:
d1.v = 0 & d2.v = 0
Or, if you prefer:
d1x*vx + d1y*vy + d1z*vz = 0
And the same for d2.
Let's take the point on the lines l1, l2 where v is actually perpendicular to the direction. We'll call these two points i1 and i2 respectively.
Since i1 lies on l1, we can say that i1 = p1 + m*d1, where m is some number.
Similarly, i2 = p3 + n*d2, where n is another number.
Since v is the vector between i1 and i2 (by definition) we get that v = i2 - i1.
This gives the substitutions for the x,y,z vectors of v:
vx = i2x - i1x = (p3x + n*d2x) - (p1x + m*d1x)
and so on.
Which you can now substitute back into your dot product equation:
d1x * ( (p3x + n*d2x) - (p1x + m*d1x) ) + ... = 0
This has reduced our number of equations to 2 (the two dot product equations) with two unknowns (m and n), so you can now solve them!
Once you have m and n, you can find the coordinates by going back to the original calculation of i1 and i2.
If you only wanted the shortest distance for points on the segment between p1-p2 and p3-p4, you can clamp i1 and i2 between these ranges of coordinates, since the shortest distance will always be as close to the perpendicular as possible.
The code above return a wrong value so I take the idea from Python code (Shortest distance between two line segments) and I converted for C#. It necessary to use Numpy lib for C#:
public static Tuple<NDarray, NDarray, NDarray> closestDistanceBetweenLines(
NDarray a0,
NDarray a1,
NDarray b0,
NDarray b1,
bool clampAll = false,
bool clampA0 = false,
bool clampA1 = false,
bool clampB0 = false,
bool clampB1 = false)
{
// If clampAll=True, set all clamps to True
if (clampAll)
{
clampA0 = true;
clampA1 = true;
clampB0 = true;
clampB1 = true;
}
// Calculate denomitator
NDarray A = a1 - a0;
NDarray B = b1 - b0;
NDarray magA = np.linalg.norm(A);
NDarray magB = np.linalg.norm(B);
NDarray _A = A / magA;
NDarray _B = B / magB;
NDarray cross = np.cross(_A, _B);
double denom = Math.Pow((float)np.linalg.norm(cross), 2);
// If lines are parallel (denom=0) test if lines overlap.
// If they don't overlap then there is a closest point solution.
// If they do overlap, there are infinite closest positions, but there is a closest distance
if (denom == 0)
{
NDarray d0 = np.dot(_A, b0 - a0);
// Overlap only possible with clamping
if (clampA0 || clampA1 || clampB0 || clampB1)
{
NDarray d1 = np.dot(_A, b1 - a0);
// Is segment B before A?
if ((float)d0 <= 0F || (float)d0 >= (float)d1)
{
if (clampA0 && clampB1)
{
if ( (float)np.absolute(d0) < (float)np.absolute(d1) )
{
return Tuple.Create(a0, b0, np.linalg.norm(a0 - b0));
}
return Tuple.Create(a0, b1, np.linalg.norm(a0 - b1));
}
}
else if ((float)d0 >= (float)magA || (float)d0 <= (float)d1)
{
// Is segment B after A?
if (clampA1 && clampB0)
{
if ((float)np.absolute(d0) < (float)np.absolute(d1))
{
return Tuple.Create(a1, b0, np.linalg.norm(a1 - b0));
}
return Tuple.Create(a1, b1, np.linalg.norm(a1 - b1));
}
}
}
// Segments overlap, return distance between parallel segments;
NDarray vuoto1 = np.array(new[] { 0 });
return Tuple.Create(vuoto1, vuoto1, np.linalg.norm(d0 * _A + a0 - b0));
}
// Lines criss-cross: Calculate the projected closest points
NDarray t = b0 - a0;
var ArrFordetA = np.array(new float[,] { { (float)t[0], (float)t[1], (float)t[2] },
{ (float)_B[0], (float)_B[1], (float)_B[2] },
{ (float)cross[0], (float)cross[1], (float)cross[2] } });
NDarray detA = np.linalg.det(ArrFordetA);
var ArrFordetB = np.array(new float[,] { { (float)t[0], (float)t[1], (float)t[2] },
{ (float)_A[0], (float)_A[1], (float)_A[2] },
{ (float)cross[0], (float)cross[1], (float)cross[2] } });
NDarray detB = np.linalg.det(ArrFordetB);
var t0 = detA / denom;
var t1 = detB / denom;
var pA = a0 + _A * t0; // Projected closest point on segment A
var pB = b0 + _B * t1; // Projected closest point on segment B
// Clamp projections
if (clampA0 || clampA1 || clampB0 || clampB1)
{
if (clampA0 && (float)t0 < 0)
{
pA = a0;
}
else if (clampA1 && (float)t0 > (float)magA)
{
pA = a1;
}
if (clampB0 && (float)t1 < 0)
{
pB = b0;
}
else if (clampB1 && (float)t1 > (float)magB)
{
pB = b1;
}
// Clamp projection A
if (clampA0 && (float)t0 < 0 || clampA1 && (float)t0 > (float)magA)
{
NDarray dot = np.dot(_B, pA - b0);
if ( clampB0 && (float)dot < 0)
{
dot = (NDarray)0;
}
else if (clampB1 && (float)dot > (float)magB)
{
dot = magB;
}
pB = b0 + _B * dot;
}
// Clamp projection B
if ( clampB0 && (float)t1 < 0 || clampB1 && (float)t1 > (float)magB)
{
NDarray dot = np.dot(_A, pB - a0);
if (clampA0 && (float)dot < 0)
{
dot = (NDarray)0;
}
else if (clampA1 && (float)dot > (float)magA)
{
dot = magA;
}
pA = a0 + _A * dot;
}
}
return Tuple.Create(pA, pB, np.linalg.norm(pA - pB));
}
to call this function use:
private void button1_Click(object sender, EventArgs e)
{
NDarray a1 = np.array(new[] { 13.43, 21.77, 46.81 });
NDarray a0 = np.array(new[] { 27.83, 31.74, -26.60 });
NDarray b0 = np.array(new[] { 77.54, 7.53, 6.22 });
NDarray b1 = np.array(new[] { 26.99, 12.39, 11.18 });
Debug.WriteLine("----------------- True: -----------------");
Debug.WriteLine(closestDistanceBetweenLines(a0, a1, b0, b1, true));
Debug.WriteLine("---------------------------------------------");
Debug.WriteLine("");
Debug.WriteLine("----------------- False: -----------------");
Debug.WriteLine(closestDistanceBetweenLines(a0, a1, b0, b1, false));
Debug.WriteLine("---------------------------------------------");
Tuple<NDarray, NDarray, NDarray> RisultatoTrue = closestDistanceBetweenLines(a0, a1, b0, b1, true);
var Pa = np.array(RisultatoTrue.Item1);
Debug.WriteLine("Start point X:" + Pa[0].ToString());
Debug.WriteLine("Start point Y:" + Pa[1].ToString());
Debug.WriteLine("Start point Z:" + Pa[2].ToString());
var Pb = np.array(RisultatoTrue.Item2);
Debug.WriteLine("End point X:" + Pb[0].ToString());
Debug.WriteLine("End point Y:" + Pb[1].ToString());
Debug.WriteLine("End point Z:" + Pb[2].ToString());
var dist = np.array(RisultatoTrue.Item3);
Debug.WriteLine("Distance:" + dist.ToString());
}
I am having issues with the output of the the result of a math calculation. I have a basic average of an array of double and I assign the result to a Label object, using the ToString() method. When I emulate the average, the label shows the correct value of 15.96 for example, but the same average of the same array, on my Galaxy S3 shows 159.6.
Is there anyone who know what's up and what can I do to make the S3 show the correct value?
Thank you all!
EDIT: passing the result to a label and adding the label to the grid:
double result = Math.Round(NP122.DoAverage(parameters), 2);
CustomLabel label = new CustomLabel();
label.ColNo = grid.ColumnDefinitions.IndexOf(c);
label.FontSize = 25;
label.TextColor = Color.Green;
if (result.ToString() == "NaN")
label.Text = "0";
else
label.Text = result.ToString();
label.IsVisible = true;
for (int i = 0; i < numberOfRows.Length + 2; i++) {
if(i == numberOfRows.Length +1)
Grid.SetRow(label, i);
}
Grid.SetColumn(label, grid.ColumnDefinitions.IndexOf(c));
listaRez.Add(label);
foreach (CustomLabel a in listaRez)
{
if (a.ColNo == grid.ColumnDefinitions.IndexOf(c))
{
grid.Children.Add(a);
}
}
EDIT 2: Custom function for NP122.DoAverage:
public static class NP122
{
public static double Vx, sx, Xm, kn, Xkinf, Xksup;
public static double sum;
public static double sumaProvizorie;
public static double[] valoriKn = new double[25];
public static double ValoareCaracteristicaSuperioara(double[] l)
{
Vx = 0;
sx = 0;
Xm = 0;
kn = 0;
Xkinf = 0;
Xksup = 0;
sum = 0;
sumaProvizorie = 0;
valoriKn[0] = 0;
//more here
valoriKn[24] = 0.35;
if (l.Length < 2 )
{
Xksup = 0;
Xkinf = 0;
}
else
{
Xm = (l.Sum()) / (l.Length);
for (int j = 0; j < l.Length; j++)
{
sumaProvizorie = Math.Round(Math.Pow((l[j] - Xm), 2), 2);
sum += sumaProvizorie;
}
kn = valoriKn[l.Length - 1];
double elements = (1.00 / (l.Length - 1));
double putere = sum;
sx = Math.Round(Math.Sqrt(elements * putere), 4);
Vx = sx / Xm;
Xksup = Xm * (1 + kn * Vx);
Xkinf = Xm * (1 - kn * Vx);
}
return Xksup;
I need to sort a list of points by distance.
So for e.g.
input : [[1,2],[5,10],[2,4]...]
output : [[1,2],[2,4],[5,10]...]
(assuming that geometrically [1,2] and [2,4] are nearest & [2,4] & [5,10] are nearest.
I need them to sort it so they are ordered by distance i.e. on the geometrical graph, point a is nearest to point b , point b is nearest to c and so on.
Any idea?
Edit: Code example
public class Point
{
public double X {get;set;}
public double Y {get;set;}
}
List<Point> points = new List<Point>();
let say my points list is getting populated in random order (not by geometrical distance).
So points would look something like...
point ~ [[1,2],[5,10],[2,4]...]
Now my charting control just take the first & second point and draw a line between them. Which means it does not care which geometrical order is it in.
If I simply supply the "points" list as above its going to draw lines between each points and from charting point of view it would not look correct as they would be "zig-zag".
To make sure the charting control draws a straight line (& and not zig-zag) I have to pass the points in the right order which would look something like ...
destination points ~ [[1,2],[2,4],[5,10]...]
So my question is how to achieve this.
Note: Changing chart control is not an option here.
Thanks
The code first takes the nearest point to (0, 0) at the '0' index then start sorting the points by distance from the last spotted point..
C#:
List<Point> SortByDistance(List<Point> lst)
{
List<Point> output = new List<Point>();
output.Add(lst[NearestPoint(new Point(0, 0), lst)]);
lst.Remove(output[0]);
int x = 0;
for (int i = 0; i < lst.Count + x; i++)
{
output.Add(lst[NearestPoint(output[output.Count - 1], lst)]);
lst.Remove(output[output.Count - 1]);
x++;
}
return output;
}
int NearestPoint(Point srcPt, List<Point> lookIn)
{
KeyValuePair<double, int> smallestDistance = new KeyValuePair<double, int>();
for (int i = 0; i < lookIn.Count; i++)
{
double distance = Math.Sqrt(Math.Pow(srcPt.X - lookIn[i].X, 2) + Math.Pow(srcPt.Y - lookIn[i].Y, 2));
if (i == 0)
{
smallestDistance = new KeyValuePair<double, int>(distance, i);
}
else
{
if (distance < smallestDistance.Key)
{
smallestDistance = new KeyValuePair<double, int>(distance, i);
}
}
}
return smallestDistance.Value;
}
VB.Net:
Function SortByDistance(ByVal lst As List(Of Point)) As List(Of Point)
Dim out As New List(Of Point)
out.Add(lst(NearestPoint(New Point(0, 0), lst)))
lst.Remove(out(0))
Dim x As Integer = 0
For i As Integer = 0 To lst.Count - 1 + x
out.Add(lst(NearestPoint(out(out.Count - 1), lst)))
lst.Remove(out(out.Count - 1))
x += 1
Next
Return out
End Function
Function NearestPoint(ByVal srcPt As Point, ByVal lookIn As List(Of Point)) As Integer
Dim smallestDistance As KeyValuePair(Of Double, Integer)
For i As Integer = 0 To lookIn.Count - 1
Dim distance As Double = Math.Sqrt(Math.Pow(srcPt.X - lookIn(i).X, 2) + Math.Pow(srcPt.Y - lookIn(i).Y, 2))
If i = 0 Then
smallestDistance = New KeyValuePair(Of Double, Integer)(distance, i)
Else
If distance < smallestDistance.Key Then
smallestDistance = New KeyValuePair(Of Double, Integer)(distance, i)
End If
End If
Next
Return smallestDistance.Value
End Function
I think you want this, Dijkstra's algorithm. There is a c# project here.
What follows is unmodified code from that link
class Dijkstra
{
private int rank = 0;
private int[,] L;
private int[] C;
public int[] D;
private int trank = 0;
public Dijkstra(int paramRank,int [,]paramArray)
{
L = new int[paramRank, paramRank];
C = new int[paramRank];
D = new int[paramRank];
rank = paramRank;
for (int i = 0; i < rank; i++)
{
for (int j = 0; j < rank; j++) {
L[i, j] = paramArray[i, j];
}
}
for (int i = 0; i < rank; i++)
{
C[i] = i;
}
C[0] = -1;
for (int i = 1; i < rank; i++)
D[i] = L[0, i];
}
public void DijkstraSolving()
{
int minValue = Int32.MaxValue;
int minNode = 0;
for (int i = 0; i < rank; i++)
{
if (C[i] == -1)
continue;
if (D[i] > 0 && D[i] < minValue)
{
minValue = D[i];
minNode = i;
}
}
C[minNode] = -1;
for (int i = 0; i < rank; i++)
{
if (L[minNode, i] < 0)
continue;
if (D[i] < 0) {
D[i] = minValue + L[minNode, i];
continue;
}
if ((D[minNode] + L[minNode, i]) < D[i])
D[i] = minValue+ L[minNode, i];
}
}
public void Run()
{
for (trank = 1; trank >rank; trank++)
{
DijkstraSolving();
Console.WriteLine("iteration" + trank);
for (int i = 0; i < rank; i++)
Console.Write(D[i] + " ");
Console.WriteLine("");
for (int i = 0; i < rank; i++)
Console.Write(C[i] + " ");
Console.WriteLine("");
}
}
}
In a graph, a set of points (x1,y1), (x2,y2), (x3,y3)...(xn,yn) should be ordered on the value of any one co ordinate because it is not the nearest point that should come next in order, but the one with nearest x or y (whichever axis is taken as reference) co-ordinate value. So, the array to pass for charting should be:
var orderedPoints=points.OrderBy(p=>p.X);
In the above image, the length of the line L1 is greater than L2. But the point P2 and not P3 should be come after P1 since P2.X<P3.X