Calculation of minimum distance between coordinate points - vb.net

I am having a problem in building up VBcode for getting the minimum distance between a set of coordinate points. What I am actually trying is to find the minimum distance between one set of coordinate points (A(x1,y1),Bx2,y2),C(x3,y3),D(x4,y4),E(x5,y5)) with respect to another set of coord points (i(x1,y1),j(x2,y2),k(x3,y3),l(x4,y4),m(x5,y5)).
I hope you understand what I am trying to interpret.
Can anybody help me out?
Public Function DoSearch(ByVal SearchCritera As Bracket, ByVal ListToSearchFrom As System.Collections.Generic.List(Of TRacksDefinitions.Racks.Bracket)) As System.Collections.Generic.List(Of TRacksDefinitions.Search.SearchBracket) Implements TRacksDefinitions.Search.ISearch.DoSearch
_results.Clear()
For Each b As Bracket In ListToSearchFrom
'LAST POINT DISTANCE., WT DIST, number of points, similarity of points (-1 if not used),
Dim dist() As Double = {0, 0, 0, 0, 0}
Dim dx As Double = b.RearPoints(b.RearPoints.Length - 2).X - SearchCritera.RearPoints(SearchCritera.RearPoints.Length - 2).X
Dim dy As Double = b.RearPoints(b.RearPoints.Length - 2).Y - SearchCritera.RearPoints(SearchCritera.RearPoints.Length - 2).Y
Dim dz As Double = b.RearPoints(b.RearPoints.Length - 2).Z - SearchCritera.RearPoints(SearchCritera.RearPoints.Length - 2).Z
dist(0) += Math.Sqrt(dx ^ 2 + dy ^ 2 + dz ^ 2)
dist(1) += Math.Abs(SearchCritera.Wallthickness - b.Wallthickness)
dist(2) += Math.Abs(SearchCritera.RearPoints.Count - b.RearPoints.Count)
If SearchCritera.RearPoints.Count = b.RearPoints.Count Then
Dim d1, d2 As Decimal
' Dim sum As Double = 0
For i As Integer = 0 To b.RearPoints.Count - 1
d1 = Math.Abs(SearchCritera.RearPoints(i).X - b.RearPoints(i).X)
d2 = Math.Abs(SearchCritera.RearPoints(i).Y - b.RearPoints(i).Y)
?????????????????
Next
Else
dist(3) = -1
End If
#LarsTech
The above is code which I have created until now and the next step is calculating the min distance criteria.
Search criteria: rear points is the one we get from solidworks and b.rearpoints is the one present in database we compare both of them find the one which is very similar to the one in database.

You need a distance formula:
Public Function GetDistance(ByVal startPoint As Point, ByVal endPoint As Point) As Integer
Return Math.Sqrt((Math.Abs(endPoint.X - startPoint.X) ^ 2) + _
(Math.Abs(endPoint.Y - startPoint.Y) ^ 2))
End Function
Then you just need to loop through all of your points to find which distance is the smallest:
Dim listOne As New List(Of Point)
listOne.Add(New Point(10, 10))
listOne.Add(New Point(20, 20))
listOne.Add(New Point(30, 30))
listOne.Add(New Point(40, 40))
listOne.Add(New Point(50, 50))
Dim listTwo As New List(Of Point)
listTwo.Add(New Point(50, 10))
listTwo.Add(New Point(50, 20))
listTwo.Add(New Point(50, 30))
listTwo.Add(New Point(50, 40))
'listTwo.Add(New Point(50, 50))
Dim minDistance As Nullable(Of Integer)
For Each p1 As Point In listOne
For Each p2 As Point In listTwo
Dim distance As Integer = GetDistance(p1, p2)
If minDistance Is Nothing OrElse distance < minDistance Then
minDistance = distance
End If
Next
Next
MessageBox.Show("Minimum Distance = " & minDistance.ToString)

In two dimensions, depending upon the distribution of the points, if N exceeds 9, it may make sense to partition the space into int(sqrt(N)-1)^2 identically-sized "boxes". If any box contains more than a hundred or so points, randomly pick ten or so points from the most populous box, find the smallest distance between any pair, and then repartition with a box size of either that smallest distance or a box size reduced by a factor of int(sqrt(k)-1) where k is the population of that box [if a box contains that many points, there must be two within that fraction of the box size.
In the worst case this algorithm could perform badly, since there could be a very dense concentration of points that somehow never get arbitrarily chosen for the distance test, and it could take awhile before the space gets subdivided finely enough to separate them. In practice, however, the points would likely get chosen at some point, allowing the collection to get quickly subdivided.

Related

Find 2 x values of the current y in a List(of Point)

I have a List(of PointF).
2 nested for loops run through a rectangle that is stretched around a circle (or circle-ish (but is really is a closed path)). I want to work within this circle with GetPixel(x,y). That means, I need the respective minimum and maximum x value of the respective y. How can I work that out with this List(Of PointF)?
The reason I'm requesting help here is because I get confused with these List.Find(predicates or matches)things.
For x As Integer = CInt(xmin) To CInt(xmax) Step 1
For y As Integer = CInt(ymin) To CInt(ymax) Step 1
'get the min and max value of x here
Next
Next
Edit: It's about: I wrote a program that uses gray images and Laplace to perform edge detection. A rectangle was drawn with the mouse and a search was made for edges within it. A Drawing2D.GraphicsPath was then created. This worked more or less well according to the object shown in the photo, because the rectangle had to be enlarged accordingly.
Now my idea is that I draw a freehand GraphicsPath myself (instead of a rectangle) and let it search for edges within it. That's why I have this circle (or egg) and I have to make sure that I don't get over its borders. I could already work out xmin, xmax, ymin, and ymax, but not x1 and x2 (see drawing).
So as I loop through all of the points from xmin to xmax and ymin to ymax, I want to know if the current point is inside the shape.
I have to check whether its x value is between the shape's x range for the given y and then the reverse for the y value. That's my problem. How to use the List?
I think you're better off not For-looping through the entire space. That would work but it's more effort than I think you need computationally.
Given a point, to determine whether or not it is within your shape - as defined by a list of point - you should only need to compare the defined point's x and y co-ords with the shape list.
Eg, Given a point x=100px and y=100px, you know that you have to check whether its x value is between the shape's x range for a the given y (100px) (or the reverse for the y value).
This would (probably?) only work for a simple shape that does not "turn in on itself" or has a curvature that doesn't change polarity. (Not sure what the mathematical name for that is, but there is one.) An hour-glass shape, for example, would probably present greater difficulty.
UPDATE
Here's a simple Linq approach which determines whether a specified point is within a defined shape. Note that it excludes points on the extremity of the shape but you can include these by changing ">" to ">=", etc.
For simplicity, I've used an octagon to approximate a circle. Also, the code assumes that ALL points within the bitmap are defined for the shape. That is, no interpolation is used.
Dim s As List(Of Point) = New List(Of Point) From {New Point(50, 0), New Point(25, 25), New Point(0, 50), New Point(25, 75), New Point(50, 100), New Point(75, 75), New Point(100, 50), New Point(75, 25)}
Dim p As Point = New Point(30, 75) ' Is inside the shape
Dim IsInside As Boolean = s.Exists(Function(f) f.Y = p.Y AndAlso f.X < p.X) AndAlso s.Exists(Function(f) f.Y = p.Y AndAlso f.X > p.X)
There're probably ways to combine the Linq test, but you get the idea.
Meanwhile, there are 2 answers:
The solution by #SteveCinq and the solution by #Jimi.
Dim IsInside As Boolean = s.Exists(Function(f) f.Y = p.Y AndAlso f.X < p.X) AndAlso s.Exists(Function(f) f.Y = p.Y AndAlso f.X > p.X)
GraphicsPath.IsVisible()

Visual Basic - Making a Line Chart

This is my first post on stackoverflow so sorry in advance for anything I may have messed up, but for a project I am doing a simulator for projectile motion. I am only a beginner programmer and dont have much experience with charts, but there aren't any youtube videos that I find helpful.
The chart is plotting vertical displacement against horizontal displacement, and should look like an inverted parabola but it doesn't look anything like what it should.
I am struggling to set axis intervals correctly, each time the line should start from the origin but the x axis contains negative values for displacement, something which should definitely not be occurring. Each time a different simulation is done the axis should change so that each interval in the x axis is something along the lines of a tenth of the total range of the projectile.
Anything that could point me in the right direction would be incredibly useful.
Code:
Public Sub CreateDiagram(ByVal flightRange As Double, ByVal totalTime As Double, ByVal velocity
As Double, ByVal angle As Double, ByVal elevation As Double, ByVal heightOfProjectile As Double)
Chart1.Titles.Add("Projectile Motion")
Chart1.ChartAreas.Clear()
Chart1.ChartAreas.Add("Default")
Dim xAxisInterval As Integer = CInt(totalTime / 10)
Dim yAxisInterval As Integer = CInt(heightOfProjectile / 10)
With Chart1.ChartAreas("Default")
.AxisX.Interval() = xAxisInterval
.AxisY.Interval() = yAxisInterval
End With
Chart1.Series.Add("projection")
Chart1.Series("projection").Color = Color.Black
Chart1.Series("projection").ChartType = DataVisualization.Charting.SeriesChartType.Line
For x = 0 To totalTime Step 0.1
Dim xPos As Double = findXLocation(velocity, angle, x)
Dim yPos As Double = findYLocation(velocity, angle, x, elevation)
Chart1.Series("projection").Points.AddXY(xPos, yPos)
Next
End Sub
EDIT: findXLocation and findYLocation code:
Public Function findYLocation(ByVal velocity As Double, ByVal angle As Double, ByVal time As Double, ByVal elevation As Double) As Double
Dim y As Double
y = elevation + findVerticalVelocity(velocity, angle) - ((0.5 * gConstant) * (time ^ 2))
y = Math.Round(y, 1)
If y < 0 Then
y = 0
End If
Return y
End Function
Public Function findXLocation(ByVal velocity As Double, ByVal angle As Double, ByVal time As Double) As Double
Dim x As Double
x = findHorizontalVelocity(velocity, angle) * time
x = Math.Round(x, 1)
If x < 0 Then
x = 0
End If
Return x
End Function
If you want to explicitly set the minimum value of the X Axis you can use Axis.Minimum. In your case you would use it as Chart1.ChartAreas("Default").AxisX.Minimum = SomeValue
Note that when you set the minimum in this way the axis will stop automatically rescaling.
If you want the minimum to always be zero when all x-values are positive, have a look at Axis.IsStartedFromZero
I hope i understood your question correctly because you mention intervals, but seem to be talking about the minimum value of your x axis.
As a further comment on your code unrelated to the question; it is unnecessary and inefficient to remove the ChartArea every time you want to update the graph, same goes for the Series. Doing this will result in having to re-format the chart on every update (like you are in fact doing with the series).
It suffices to call YourSeries.Points.Clear() and to then add the new points. This way you don't have to re-specify the series color and chartype on each update.
EDIT:
I also see that you round the x position to one decimal, presumably to prevent the x-axis from having long ugly numbers on it. However, a better way to do this is to specify a format for the axis:
chart1.ChartAreas.FirstOrDefault.AxisX.LabelStyle.Format = "{0:0.0}" in your case. This way your series will still store the exact value, but only one decimal will be displayed.

How to fit straight line to variable curve and determining the x-intercept

I'm trying to figure out how to code a straight line to the straight part of a curve, the curve should look something like the exponential, click the link to open the image:
Straight line to Curve and determining the x-intercept
Here is the code, I'm only using the exponential as an example
`
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim s As String
Dim xl As New Excel.Application
Dim wb As Excel.Workbook
Dim ws As Excel.Worksheet
wb = xl.Workbooks.Add 'create new workbook
ws = wb.Worksheets(1) 'select sheet 1
ws.Activate()
Dim Currents() As Double
Dim PhotodiodeValues() As Double
Dim AppliedCurrent As Double
'AppliedCurrent = SerialPort1.ReadLine
AppliedCurrent = 0
If AppliedCurrent >= 0 And AppliedCurrent < 0.1 Then
Dim j As Integer = 1
For i As Double = 0 To 5 Step 0.5
ReDim Preserve Currents(j)
ReDim Preserve PhotodiodeValues(j)
MsgBox(i)
MsgBox("LDI " & CType(i, String))
s = ("LDI " & CType(i, String))
AppliedCurrent = i
If AppliedCurrent >= i And AppliedCurrent < (i + 0.1) Then
Currents(j) = CType(i, Double)
Label1.Text = Currents(j)
PhotodiodeValues(j) = CType(Math.E ^ (i), Double)
ws.Cells(j, 1) = Currents(j)
ws.Cells(j, 2) = PhotodiodeValues(j)
Else
System.Threading.Thread.Sleep(1000)
End If
j = j + 1
Next
Else
System.Threading.Thread.Sleep(1000)
End If
sfd1.ShowDialog() 'get file name
wb.SaveAs(sfd1.FileName) 'save data to file
wb.Close()
xl = Nothing 'dispose of excel
ScatterGraph1.PlotXY(Currents, PhotodiodeValues)
'SerialPort1.Close()
End Sub
End Class`
First off, I'll explain my thought process. If I have misunderstood, please let me know and I will update my answer. The slope dy/dx of the curve y = e^x is dy/dx = e^x, a monotonically increasing function of x for all real x. There is never a point at which the function becomes linear and, while it has a horizontal asymptote (y = 0) it has no vertical asymptote.
I take it that what you want is the equation of a tangent line taken at a point where the slope first becomes greater than some cutoff value m*. After that point, the graph of y = e^x "might as well" be a straight line for your intents and purposes.
So, we must first solve the equation m* = dy/dx = e^x for the x at which m* occurs. The range of e^x is all positive real numbers and e^x is monotonically increasing, so any positive real number m* will have a unique solution x*. indeed, x* = ln(m*). Our tangent line will pass through the point (x*, e^x*) and have slope m*. Recall that m* = e^x*, so the point is (ln(m*), m*) and the slope is m*.
With a point and the slope, we can figure out the equation of a line. We have that the slope from the given point to any other point must be m*; so, (y - y*)/(x - x*) = m*. Rearranging, (y - y*) = m*(x - x*), y = mx - mx* + y*, and finally y = mx + (y - mx) = mx + (m - mln(m)). The Y-intercept is therefore (m* - mln(m)). We can get the X-intercept by setting y = 0 and solving for x: 0 = mx + (m - mln(m)), mx = mln(m*) - m*, x = ln(m*) - 1.
In summary:
the equation of the line tangent to y = e^x with slope m* is y = mx + (m - mln(m)).
the Y-intercept of this line is (m* - mln(m)).
the X-intercept of this line is ln(m*) - 1
If the curve is known at compile time, I recommend hard-coding a closed form analytical solution for the derivative and any asymptotes. If the function is not known until runtime, the derivative at a given point can be approximated numerically using a variety of methods. Intuitively, the definition of the derivative as the limit of (f(x+d) - f(x)) / d as d approaches zero can be used to find approximations of the derivative where the derivative (likely) exists. For well-behaved analytic functions, you will typically be safe except in special cases.
If the function's derivative is monotonically non-decreasing, as in this example, you can find the point (if any) at which the function's slope meets or exceeds a certain cutoff using approximation (as above) in conjunction with something akin to binary search. Start at a value such as x = 0, and increase or decrease x by some multiplicatively increasing factor until you have passed your target. Now, with bounds on the values of x between which your target can be found, check the middle of the range, and then either the left or right half recursively until a suitably good x* is found.

Polygon Inside Another Polygon

Source of algorithm idea
I took that idea and I am trying to detect if an entire polygon is inside the other polygon. Here is my code that I came up with adding an additional check for X because sometimes it will equal zero and cause a issue.
Public Shared Function ContainsOutsidePoints(ByVal ToBeChecked As Polygon, ByVal CheckAgainst As Polygon) As Boolean
For Each pt As Point In ToBeChecked.Coordinates
If CheckAgainst.Inside(pt) = False Then
Return True
End If
Next
Return False
End Function
Public Function Inside(ByVal Value As Point) As Boolean
Dim j As Integer = Lines.Count - 1
Dim pxi As Double
Dim pxj As Double
Dim pyi As Double
Dim pyj As Double
Inside = False
For i As Integer = 0 To Lines.Count - 1
pxi = Lines.Item(i).EndPointA.X
pxj = Lines.Item(j).EndPointA.X
pyi = Lines.Item(i).EndPointA.Y
pyj = Lines.Item(j).EndPointA.Y
If (pyi < Value.Y AndAlso pyj >= Value.Y OrElse _
pyj < Value.Y AndAlso pyi >= Value.Y) And _
pxi <= Value.X OrElse pxj <= Value.X AndAlso _
pxi <> pxj Then
If (pxi + (Value.Y - pyi) / (pyj - pyi) * (pxj - pxi) < Value.X) Then
Inside = Not Inside
End If
End If
j = i
Next
Return Inside
End Function
When I run it it will sometimes say polygons that I can see are not inside the other when it clearly is and sometimes it will return is inside when not all points are inside the other polygon. Is this caused by adding the additional check of the X since even less statements match the if statement requirements.
The intersection of an horizontal line with the interior of a polygon is a set of 1D intervals.
If P is inside Q, all 1D intervals of P will be wholly inside a corresponding interval of Q.
It suffices to check that this property holds for all horizontals though all vertices of both polygons.
You can do that by considering every vertex in turn, finding the intersections with the horizontals and sorting them left-to-right before checking for inclusion.
You can save operations by using the sweepline paradigm, i.e. scanning the vertices top-to-bottom and maintaining a list of the edges that straddle the current horizontal. This way you know exactly which edge will intersect; the update of the straddling list from vertex to vertex is straightforward.

Need to determine if a list of points are all part of the same circle in VB.net

VB.NET
My data is coming from an exported DXF file from various cad packages. When a circular arc (defined as a part of a true circle) is exported it is sometimes exported as a bunch of line segments rather than a circular arc.
I have a list of points and I am trying to guess if they were derived from the same circle. Basically I iterate through all the points and use a method to find the center point of a circle from three points. My intention was to compare all the calculated center points generated and make a determination if they are close to each other.
My first thought was that I could check to see if the center points are all equal but they have slight differences between them because of rounding and the underlying estimating routine that generates the point in the first place (I have no control over that).
MY second was to check the standard deviation of the x and y values of the circumference points and compare that against the standard deviation of the x,y of the centers and make some judgement from that. VB.net does not seem to have a native stdev function and I am sometimes a bit lazy.
Does anybody have a simple idea on how to determine if a list of points are all from the same circle?
Here are my functions:
To determine the center of a circle given three points:
Public Function getCenter(p1 As Point2D, p2 As Point2D, p3 As Point2D) As Point2D
Dim yDelta_a As Double = p2.Y - p1.Y
Dim xDelta_a As Double = p2.X - p1.X
Dim yDelta_b As Double = p3.Y - p2.Y
Dim xDelta_b = p3.X - p2.X
Dim center As New Point2D
Dim aSlope As Double = yDelta_a / xDelta_a
Dim bSlope As Double = yDelta_b / xDelta_b
center.X = (aSlope * bSlope * (p1.Y - p3.Y) + bSlope * (p1.X + p2.X) - aSlope * (p2.X + p3.X)) / (2 * (bSlope - aSlope))
center.Y = -1 * (center.X - (p1.X + p2.X) / 2) / aSlope + (p1.Y + p2.Y) / 2
Return center
End Function
And then to iterate the list of points and get a collection of centers. FYI...This function received a list of lines that have endpoints that are points so I do a bit of iterating to get all the correct points.
Public Function MakesCircle(lines As List(Of Line))
Dim points As New List(Of Point2D)
If lines.Count < 2 Then
Return False
Else
//Get points from lines
For i As Int16 = 0 To lines.Count - 2
points.Add(lines(i).StartPoint)
Next
points.Add(lines.Last.StartPoint)
End If
//"Prime the pump" for the center calculation loop
Dim centers As New List(Of Point2D)
Dim a As Point2D = points(0)
Dim b As Point2D = points(1)
Dim c As Point2D = points(2)
//Calc all the centers
For i As Int16 = 3 To lines.Count - 1
centers.Add(getCenter(a, b, c))
a = b
b = c
c = points(i)
Next
//This is where I need logic to determine if the points all actually belong to the same circle
Return True
End Function
You can use a GraphicsPath object to find this out. -not tested-
I figured you would be able to construct a Rectangle Structure based on the data coming in (x,y,w,h) then this make-shift algorithm would do for you.
Private Function areAllPointsInEllipsis(ellipsis As Rectangle, pts() As Point) As Boolean
Dim result As Boolean
Using gp As New System.Drawing.Drawing2D.GraphicsPath
gp.AddEllipsis(ellispsis)
result = pts.All(Function(pt) gp.IsVisible(pt))
End Using
Return result
End Function
What I did was generate all the distances from the average center point to each of the points that make up the circumference. Find the max and min distances. They you can use a threshold of a percentage of the radius - a kind of eccentricity measurement. If the difference between the max and min falls below 1% of the radius then I call it a circle.