Haven’t looked at your code, but i guess it creates the formula of the line based on the 2 points you pass to the algorithm.
And of course this line (almost) always has 2 intersections with the circle.
I guess if you only want the intersection that lies between these 2 points, take the solution(x,y) where solution(x) is between P1(x) and P2(x) and solution(y) is between P1(y) and P2(y).
Its been a while since you posed the question but I recently started looking for the answer too. Andy McW and I went over the plugin to try and figure out a spreadable method and we got a very workable if not perfect solution.
The patch explains why but it ain’t bad.
Here’s the code if you wanna peak:
#region usings
using System;
using System.ComponentModel.Composition;
using VVVV.PluginInterfaces.V1;
using VVVV.PluginInterfaces.V2;
using VVVV.Utils.VColor;
using VVVV.Utils.VMath;
using VVVV.Core.Logging;
- endregion usings
namespace VVVV.Nodes
{
#region PluginInfo
[PluginInfo(Name = "IntersectCircles", Category = "2d", Help = "Basic template with one value in/out", Tags = "")](PluginInfo(Name = "IntersectCircles", Category = "2d", Help = "Basic template with one value in/out", Tags = ""))
#endregion PluginInfo
public class C2dIntersectCirclesNode : IPluginEvaluate
{
#region fields & pins
[Input("Centers")](Input("Centers"))
ISpread<Vector2D> FCenters;
[Input("Radii", DefaultValue = 1.0)](Input("Radii", DefaultValue = 1.0))
ISpread<double> FRadii;
[Output("Intersections")](Output("Intersections"))
ISpread<Vector2D> FIntersections;
[Output("Number of Solutions")](Output("Number of Solutions"))
ISpread<int> FSolutionCount;
[Import()](Import())
ILogger FLogger;
#endregion fields & pins
//called when data for any output pin is requested
public void Evaluate(int SpreadMax)
{
FIntersections.SliceCount = SpreadMax;
FSolutionCount.SliceCount = SpreadMax;
for(int i = 0; i < FIntersections.SliceCount; i++)
{
FIntersections.RemoveAt(i);
}
for (int i = 0; i < SpreadMax; i++)
{
for (int j = i + 1; j < SpreadMax; j++)
{
Vector2D s1;
Vector2D s2;
FSolutionCount[i](i) = CircleIntersection(FCenters[i](i), FRadii[i](i), FCenters[j](j), FRadii[j](j), out s1, out s2);
FIntersections.Add(s1);
FIntersections.Add(s2);
}
}
}
private int CircleIntersection (Vector2D c1, double c1r, Vector2D c2, double c2r, out Vector2D p1, out Vector2D p2)
{
p1 = new Vector2D();
p2 = new Vector2D();
//Calculate distance between centres of circle
double d = !(c1 - c2);
double m = c1r + c2r;
double n = c1r - c2r;
if (n < 0)
n = n * -1;
//No solns
if ( d > m )
return 0;
//Circle are contained within each other
if ( d < n )
return 0;
//Circles are the same
if ( d == 0 && c1r == c2r )
return 0;
//Solve for a
double a = ( c1r * c1r - c2r * c2r + d * d ) / (2 * d);
//Solve for h
double h = Math.Sqrt( c1r * c1r - a * a );
//Calculate point p, where the line through the circle intersection points crosses the line between the circle centers.
Vector2D p;
p.x = c1.x + ( a / d ) * ( c2.x -c1.x );
p.y = c1.y + ( a / d ) * ( c2.y -c1.y );
//1 soln , circles are touching
if ( d == c1r + c2r )
{
p1 = p;
return 1;
}
//2solns
p1.x = p.x + ( h / d ) * ( c2.y - c1.y );
p1.y = p.y - ( h / d ) * ( c2.x - c1.x );
p2.x = p.x - ( h / d ) * ( c2.y - c1.y );
p2.y = p.y + ( h / d ) * ( c2.x - c1.x );
return 2;
}
}
}
The idea came from Elias’s ConnectAll))](https://vvvv.org/contribution/connectall">ConnectAll))) dynamic plug-in he did for his tutorial. In it he showed how multiple vectors can be made to analyse each other (the “for j = i+1” bit).
Most of the credit goes to Andy McWilliams and your good self, though, co-opted the ideas into a something usable and lovely.
for(int i = 0; i < FIntersections.SliceCount; i++)
{
FIntersections.RemoveAt(i);
}
with this
FIntersections.Clear();
it’s easier to read and has a better run time, as removing them one by one will trigger a shift of all remaining slices each time you remove one slice.
‘VVVV.PluginInterfaces.V2.ISpread<VVVV.Utils.VMath.Vector2D>’ does not contain a definition for ‘Clear’ and no extension method ‘Clear’ accepting a first argument of type ‘VVVV.PluginInterfaces.V2.ISpread<VVVV.Utils.VMath.Vector2D>’ could be found (are you missing a using directive or an assembly reference?)
Hey guys,
i´m trying to make the multiple finite lines version,
but i don´t know how to feed the plugin with a spread of points instead of 4 points with individual inputs.
Any tip?
thanks.
- region usings
using System;
using System.ComponentModel.Composition;
using VVVV.PluginInterfaces.V1;
using VVVV.PluginInterfaces.V2;
using VVVV.Utils.VColor;
using VVVV.Utils.VMath;
using VVVV.Core.Logging;
- endregion usings
namespace VVVV.Nodes
{
#region PluginInfo
[PluginInfo(Name = "MultipleLinesIntersect", Category = "Value", Help = "2 lines intersect", Tags = "")](PluginInfo(Name = "MultipleLinesIntersect", Category = "Value", Help = "2 lines intersect", Tags = ""))
//Source:
//http://paulbourke.net/geometry/lineline2d/
//Credits:
//Lasal 2011
#endregion PluginInfo
public class Value2LinesIntersectNode : IPluginEvaluate
{
#region fields & pins
// Could it be possible to use a spread of points?
[Input("P1")](Input("P1"))
ISpread<Vector2D> P1;
[Input("P2")](Input("P2"))
ISpread<Vector2D> P2;
[Input("P3")](Input("P3"))
ISpread<Vector2D> P3;
[Input("P4")](Input("P4"))
ISpread<Vector2D> P4;
[Output("Intersection")](Output("Intersection"))
ISpread<Vector2D> FIntersection;
[Output("Number of Solutions")](Output("Number of Solutions"))
ISpread<int> FSolutionCount;
[Import()](Import())
ILogger FLogger;
#endregion fields & pins
//called when data for any output pin is requested
public void Evaluate(int SpreadMax)
{
FIntersection.SliceCount = SpreadMax;
FSolutionCount.SliceCount = SpreadMax;
for(int i = 0; i < FIntersection.SliceCount; i++)
{
FIntersection.RemoveAt(i);
}
for (int i = 0; i < SpreadMax; i++)
{
for (int j = i + 1; j < SpreadMax; j++)
{
Vector2D s1;
Vector2D s2;
//How to use 10 variables? P1[j](j), P2[j](j), P3[j](j), P4[j](j)
FSolutionCount[i](i) = LinesIntersection( P1[i](i), P2[i](i), P3[i](i), P4[i](i), out s1, out s2);
FIntersection.Add(s1);
FIntersection.Add(s2);
}
}
}
private int LinesIntersection ( Vector2D P1 , Vector2D P2, Vector2D P3 , Vector2D P4, out Vector2D so1, out Vector2D so2)
{
so1 = new Vector2D();
so2 = new Vector2D();
// Denominator for ua and ub are the same, so store this calculation
double d =
(P4.y - P3.y) * (P2.x - P1.x)
-
(P4.x - P3.x) * (P2.y - P1.y);
//n_a and n_b are calculated as seperate values for readability
double n_a =
(P4.x - P3.x) * (P1.y - P3.y)
-
(P4.y - P3.y) * (P1.x - P3.x);
double n_b =
(P2.x - P1.x) * (P1.y - P2.y)
-
(P2.y - P1.y) * (P1.x - P2.x);
// Calculate the intermediate fractional point that the lines potentially intersect.
double ua = n_a / d;
double ub = n_b / d;
double SX = P1.x + (ua * (P2.x - P1.x));
double SY = P1.y + (ua * (P2.y - P1.y));
if (d == 0) // Parallel lines.
{
return 0;
}
if (SX < P1.x & SX < P2.x |
SY < P1.y & SY < P2.y |
SX > P1.x & SX > P2.x |
SY > P1.y & SY > P2.y )
// No finite lines intersecting, delete this for infinite lines Intersection.
{
return 0;
}
// than 0 the lines would need to be longer to intersect.
if (ua >= 0d && ua <= 1d && ub >= 0d && ub <= 1d)
{
so1.x = SX;
so1.y = SY;
return 1;
}
{
return 0;
}
}
}}