Line circle intersection: Difference between revisions

Added FreeBASIC
(Added Rust solution)
(Added FreeBASIC)
 
(6 intermediate revisions by 3 users not shown)
Line 17:
 
Illustrate your method with some examples (or use the Go examples below).
 
;Stretch Task
 
Include results for a circle with center at (10, 10) and radius 5 combined with a line through points (5, 0) and (5, 20) and that same circle combined with a line segment from (-5, 10) to (5, 10).
 
 
;References
Line 24 ⟶ 29:
 
=={{header|AutoHotkey}}==
<langsyntaxhighlight AutoHotkeylang="autohotkey">data := [[[3, -5], 3, [-10, 11], [10, -9], 0]
, [[3, -5], 3, [-10, 11], [-11, 12], 1]
, [[3, -5], 3, [3, -2], [7, -2], 1]
Line 75 ⟶ 80:
sgn(x){
return x<0?-1:1
}</langsyntaxhighlight>
{{out}}
<pre>Center Rad P1 P2 Segment intersect 1 Intersect 2
Line 88 ⟶ 93:
=={{header|C}}==
{{trans|Go}}
<langsyntaxhighlight lang="c">#include <math.h>
#include <stdbool.h>
#include <stdio.h>
Line 252 ⟶ 257:
 
return 0;
}</langsyntaxhighlight>
{{out}}
<pre>The intersection points (if any) between:
Line 275 ⟶ 280:
=={{header|C++}}==
{{trans|Kotlin}}
<langsyntaxhighlight lang="cpp">#include <iostream>
#include <utility>
#include <vector>
Line 447 ⟶ 452:
 
return 0;
}</langsyntaxhighlight>
{{out}}
<pre>The intersection points (if any) between:
Line 470 ⟶ 475:
=={{header|C#}}==
{{trans|C++}}
<langsyntaxhighlight Csharplang="csharp">using System;
using System.Collections.Generic;
using System.Linq;
Line 617 ⟶ 622:
public override string ToString() => $"{{ C:{Center}, R:{Radius} }}";
}
}</langsyntaxhighlight>
{{out}}
<pre>Circle: { C:(3, -5), R:3 }
Line 642 ⟶ 647:
=={{header|D}}==
{{trans|C++}}
<langsyntaxhighlight lang="d">import std.format;
import std.math;
import std.stdio;
Line 826 ⟶ 831:
writeln(" a segment starting at ", p1, " and ending at ", p2, " is/are:");
writeln(" ", intersects(p1, p2, cp, r, true));
}</langsyntaxhighlight>
{{out}}
<pre>The intersection points (if any) between:
Line 846 ⟶ 851:
a segment starting at (7, 4) and ending at (11, 8) is/are:
[(8, 5)]</pre>
 
=={{header|FreeBASIC}}==
{{trans|C}}
<syntaxhighlight lang="vbnet">#define eps 1e-14
#define fx(a, b, c, d) -(a * d + c) / b
#define fy(a, b, c, d) -(b * d + c) / a
 
Type puntoT
Dim As Double x, y
End Type
 
Function construye_punto(x As Double, y As Double) As puntoT
Dim As puntoT p1 = (x, y)
Return p1
End Function
 
Sub imprime_punto(p As puntoT)
Dim As Double x = p.x
Dim As Double y = p.y
If x = 0 Then x = 0
If y = 0 Then y = 0
Print Using "(&, &)"; x; y;
End Sub
 
Function sq(x As Double) As Double
Return x * x
End Function
 
Function dentro(x1 As Double, y1 As Double, x2 As Double, y2 As Double, x As Double, y As Double) As Boolean
Dim d1 As Double = Sqr(sq(x2 - x1) + sq(y2 - y1)) ' distance between end-points
Dim d2 As Double = Sqr(sq(x - x1) + sq(y - y1)) ' distance from point to one end
Dim d3 As Double = Sqr(sq(x2 - x) + sq(y2 - y)) ' distance from point to other end
Dim delta As Double = d1 - d2 - d3
Return Abs(delta) < eps ' true if delta is less than a small tolerance
End Function
 
Function rxy(x1 As Double, y1 As Double, x2 As Double, y2 As Double, x As Double, y As Double, segmento As Boolean) As Integer
If Not segmento Or dentro(x1, y1, x2, y2, x, y) Then
imprime_punto(construye_punto(x, y))
Return 1
Else
Return 0
End If
End Function
 
' Prints the intersection puntos (if any) of a circle, center 'cp' with radius 'r',
' and either an infinite line containing the puntos 'p1' and 'p2'
' or a segmento drawn between those puntos.
Sub interseccion(p1 As puntoT, p2 As puntoT, cp As puntoT, r As Double, segmento As Boolean)
Dim As Double x0 = cp.x, y0 = cp.y
Dim As Double x1 = p1.x, y1 = p1.y
Dim As Double x2 = p2.x, y2 = p2.y
Dim As Double A1 = y2 - y1, B1 = x1 - x2, C1 = x2 * y1 - x1 * y2
Dim As Double a = sq(A1) + sq(B1)
Dim As Double b, c, d, x ,y
Dim As Boolean bnz = True
Dim As Integer cnt = 0
If Abs(B1) >= eps Then
' if B1 isn't zero or close to it
b = 2 * (A1 * C1 + A1 * B1 * y0 - B1 * B1 * x0)
c = sq(C1) + 2 * B1 * C1 * y0 - sq(B1) * (sq(r) - sq(x0) - sq(y0))
Else
b = 2 * (B1 * C1 + A1 * B1 * x0 - sq(A1) * y0)
c = sq(C1) + 2 * A1 * C1 * x0 - sq(A1) * (sq(r) - sq(x0) - sq(y0))
bnz = False
End If
d = sq(b) - 4 * a * c ' discriminant
Select Case d
Case Is < 0
' line & circle don't intersect
Print "[]";
Case 0
' line is tangent to circle, so just one intersect at most
If bnz Then
x = -b / (2 * a)
y = fx(A1, B1, C1, x)
cnt = rxy(x1, y1, x2, y2, x, y, segmento)
Else
y = -b / (2 * a)
x = fy(A1, B1, C1, y)
cnt = rxy(x1, y1, x2, y2, x, y, segmento)
End If
Case Else
' two interseccion at most
d = Sqr(d)
If bnz Then
x = (-b + d) / (2 * a)
y = fx(A1, B1, C1, x)
cnt = rxy(x1, y1, x2, y2, x, y, segmento)
x = (-b - d) / (2 * a)
y = fx(A1, B1, C1, x)
cnt += rxy(x1, y1, x2, y2, x, y, segmento)
Else
y = (-b + d) / (2 * a)
x = fy(A1, B1, C1, y)
cnt = rxy(x1, y1, x2, y2, x, y, segmento)
y = (-b - d) / (2 * a)
x = fy(A1, B1, C1, y)
cnt += rxy(x1, y1, x2, y2, x, y, segmento)
End If
End Select
If cnt <= 0 Then Print "[]";
End Sub
 
Dim As puntoT cp = construye_punto(3, -5)
Dim As Double r = 3.0
Print "The intersection puntos (if any) between:"
Print " A circle, center (3, -5) with radius 3, and:"
Print " a line containing the points (-10, 11) and (10, -9) is/are:"
Print Spc(6); : interseccion(construye_punto(-10, 11), construye_punto(10, -9), cp, r, False)
Print !"\n a segment starting at (-10, 11) and ending at (-11, 12) is/are"
Print Spc(6); : interseccion(construye_punto(-10, 11), construye_punto(-11, 12), cp, r, True)
Print !"\n a horizontal line containing the points (3, -2) and (7, -2) is/are:"
Print Spc(6); : interseccion(construye_punto(3, -2), construye_punto(7, -2), cp, r, False)
 
cp = construye_punto(0, 0)
r = 4.0
Print !"\n A circle, center (0, 0) with radius 4, and:"
Print " a vertical line containing the points (0, -3) and (0, 6) is/are:"
Print Spc(6); : interseccion(construye_punto(0, -3), construye_punto(0, 6), cp, r, False)
Print !"\n a vertical segmento starting at (0, -3) and ending at (0, 6) is/are:"
Print Spc(6); : interseccion(construye_punto(0, -3), construye_punto(0, 6), cp, r, True)
 
cp = construye_punto(4,2)
r = 5.0
Print !"\n A circle, center (4, 2) with radius 5, and:"
Print " a line containing the points (6, 3) and (10, 7) is/are:"
Print Spc(6); : interseccion(construye_punto(6, 3), construye_punto(10, 7), cp, r, False)
Print !"\n a segment starting at (7, 4) and ending at (11, 8) is/are:"
Print Spc(6); : interseccion(construye_punto(7, 4), construye_punto(11, 8), cp, r, True)
 
Sleep</syntaxhighlight>
{{out}}
<pre>Same as C entry.</pre>
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package main
 
import (
Line 977 ⟶ 1,121:
fmt.Println("\n a segment starting at (7, 4) and ending at (11, 8) is/are:")
fmt.Println(" ", intersects(point{7, 4}, point{11, 8}, cp, r, true))
cp = point{10, 10}
}</lang>
r = 5.0
fmt.Println("\n A circle, center (10, 10) with radius 5, and:")
fmt.Println("\n a vertical line containing the points (5, 0) and (5, 20) is/are:")
fmt.Println(" ", intersects(point{5, 0}, point{5, 20}, cp, r, false))
fmt.Println("\n a horizontal segment starting at (-5, 10) and ending at (5, 10) is/are:")
fmt.Println(" ", intersects(point{-5, 10}, point{5, 10}, cp, r, true))
}</syntaxhighlight>
 
{{out}}
Line 1,009 ⟶ 1,160:
a segment starting at (7, 4) and ending at (11, 8) is/are:
[(8, 5)]
 
A circle, center (10, 10) with radius 5, and:
 
a vertical line containing the points (5, 0) and (5, 20) is/are:
[(5, 10)]
 
a horizontal segment starting at (-5, 10) and ending at (5, 10) is/are:
[(5, 10)]
</pre>
 
=={{header|Haskell}}==
<langsyntaxhighlight lang="haskell">import Data.Tuple.Curry
 
main :: IO ()
Line 1,086 ⟶ 1,245:
sgn x
| 0 > x = -1
| otherwise = 1</langsyntaxhighlight>
{{out}}
<pre>Intersection: Circle (3.0,-5.0) 3.0 and Line (-10.0,11.0) (10.0,-9.0): [(3.0,-2.0),(6.0,-5.0)]
Line 1,110 ⟶ 1,269:
 
=={{header|Java}}==
<langsyntaxhighlight lang="java">import java.util.*;
import java.awt.geom.*;
 
Line 1,216 ⟶ 1,375:
return str.toString();
}
}</langsyntaxhighlight>
 
{{out}}
Line 1,252 ⟶ 1,411:
=={{header|Julia}}==
Uses the circles and points from the Go example.
<langsyntaxhighlight lang="julia">using Luxor
 
const centers = [Point(3, -5), Point(0, 0), Point(4, 2)]
Line 1,270 ⟶ 1,429:
println(rpad(centers[cr], 17), rads[cr], " "^3, rpad(lins[l][1], 21),
rpad(lins[l][2], 19), rpad(!extended, 8), isempty(v) ? "" :
length(v) == 2 && tup[1] == 2 ? rpad(v[1], 18) * string(v[2]) : v[1])
end
</langsyntaxhighlight>{{out}}
<pre>
Center Radius Line P1 Line P2 Segment? Intersect 1 Intersect 2
Line 1,286 ⟶ 1,445:
=={{header|Kotlin}}==
{{trans|Go}}
<langsyntaxhighlight lang="scala">import kotlin.math.absoluteValue
import kotlin.math.sqrt
 
Line 1,441 ⟶ 1,600:
println(" a segment starting at $p1 and ending at $p2 is/are:")
println(" ${intersects(p1, p2, cp, r, true)}")
}</langsyntaxhighlight>
{{out}}
<pre>The intersection points (if any) between:
Line 1,464 ⟶ 1,623:
=={{header|Lua}}==
{{trans|C++}}
<langsyntaxhighlight lang="lua">EPS = 1e-14
 
function pts(p)
Line 1,621 ⟶ 1,780:
end
 
main()</langsyntaxhighlight>
{{out}}
<pre>The intersection points (if any) between:
Line 1,643 ⟶ 1,802:
 
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<langsyntaxhighlight Mathematicalang="mathematica">LineCircleIntersections[p1_, p2_, c_, r_, type_] := RegionIntersection[Circle[c, r], type[{p1, p2}]]
LineCircleIntersections[{-1, 1}, {1, 1}, {0, 0}, 1, Line]
LineCircleIntersections[{-1, 0}, {2, 0.4}, {0, 0}, 1, Line]
LineCircleIntersections[{-1.5, 0}, {-2, 0.4}, {0, 0}, 1, Line]
LineCircleIntersections[{-1.5, 0}, {-2, 0.4}, {0, 0}, 1, InfiniteLine]</langsyntaxhighlight>
{{out}}
<pre>Point[{{0,1}}]
Line 1,656 ⟶ 1,815:
=={{header|Nim}}==
{{trans|Go}}
<langsyntaxhighlight Nimlang="nim">import math, strutils
 
const Eps = 1e-14
Line 1,760 ⟶ 1,919:
echo " ", intersects((6.0, 3.0), (10.0, 7.0), cp, r, false)
echo "\n a segment starting at (7, 4) and ending at (11, 8) is/are:"
echo " ", intersects((7.0, 4.0), (11.0, 8.0), cp, r, true)</langsyntaxhighlight>
 
{{out}}
Line 1,793 ⟶ 1,952:
 
=={{header|Perl}}==
<langsyntaxhighlight lang="perl">use strict;
use warnings;
use feature 'say';
Line 1,833 ⟶ 1,992:
say 'Solutions: ' . (@solution > 1 ? join ', ', map { '('. join(',', rnd @$_) .')' } @solution : 'None');
say '';
}</langsyntaxhighlight>
{{out}}
<pre>For input: (-10,11), (10,-9), (3,-5), 3
Line 1,859 ⟶ 2,018:
{{trans|Go}}
{{trans|zkl}}
<!--<langsyntaxhighlight Phixlang="phix">(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">epsilon</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1e-14</span> <span style="color: #000080;font-style:italic;">-- say</span>
Line 1,957 ⟶ 2,116:
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<!--</langsyntaxhighlight>-->
{{out}}
<pre>
Line 1,972 ⟶ 2,131:
(formerly Perl 6)
Extend solution space to 3D. Reference: this [https://stackoverflow.com/questions/1073336/ SO question and answers]
<syntaxhighlight lang="raku" perl6line>sub LineCircularOBJintersection(@P1, @P2, @Centre, \Radius) {
my @d = @P2 »-« @P1 ; # d
my @f = @P1 »-« @Centre ; # c
Line 2,008 ⟶ 2,167:
say "For data set: ", $_;
say "Solution(s) is/are: ", @solution.Bool ?? @solution !! "None";
}</langsyntaxhighlight>
{{out}}
<pre>For data set: [(-10 11) (10 -9) (3 -5) 3]
Line 2,031 ⟶ 2,190:
The formulae used for this REXX version were taken from the MathWorld
webpage: &nbsp; [https://mathworld.wolfram.com/Circle-LineIntersection.html circle line intersection].
<langsyntaxhighlight lang="rexx">/*REXX program calculates where (or if) a line intersects (or tengents) a cirle. */
/*───────────────────────────────────── line= x1,y1 x2,y2; circle is at 0,0, radius=r*/
parse arg x1 y1 x2 y2 cx cy r . /*obtain optional arguments from the CL*/
Line 2,073 ⟶ 2,232:
numeric form; m.=9; parse value format(x,2,1,,0) 'E0' with g "E" _ .; g=g *.5'e'_ %2
do j=0 while h>9; m.j= h; h= h%2 + 1; end /*j*/
do k=j+5 to 0 by -1; numeric digits m.k; g= (g+x/g) *.5; end /*k*/; return g</langsyntaxhighlight>
{{out|output|text=&nbsp; when using the default inputs:}}
<pre>
Line 2,083 ⟶ 2,242:
=={{header|Ruby}}==
{{trans|C++}}
<langsyntaxhighlight lang="ruby">EPS = 1e-14
 
def sq(x)
Line 2,222 ⟶ 2,381:
end
 
main()</langsyntaxhighlight>
{{out}}
<pre>The intersection points (if any) between:
Line 2,245 ⟶ 2,404:
=={{header|Rust}}==
{{trans|C++}}
<langsyntaxhighlight lang="rust">
use assert_approx_eq::assert_approx_eq;
 
Line 2,422 ⟶ 2,581:
}
}
</syntaxhighlight>
</lang>
 
{{out}}
Line 2,434 ⟶ 2,593:
=={{header|Swift}}==
{{trans|Java}}
<langsyntaxhighlight lang="swift">import Foundation
import CoreGraphics
 
Line 2,522 ⟶ 2,681:
center: center, radius: radius,
segment: true)
print(" \(toString(points: points))")</langsyntaxhighlight>
 
{{out}}
Line 2,558 ⟶ 2,717:
=={{header|Visual Basic .NET}}==
{{trans|C#}}
<langsyntaxhighlight lang="vbnet">Module Module1
 
Structure Point
Line 2,736 ⟶ 2,895:
End Sub
 
End Module</langsyntaxhighlight>
{{out}}
<pre>Circle: { C:(3, -5), R:3 }
Line 2,761 ⟶ 2,920:
{{trans|Kotlin}}
{{libheader|Wren-dynamic}}
<langsyntaxhighlight ecmascriptlang="wren">import "./dynamic" for Tuple
 
var Point = Tuple.create("Point", ["x", "y"])
Line 2,893 ⟶ 3,052:
p2 = Point.new(11, 8)
System.print(" a segment starting at %(p1) and ending at %(p2) is/are:")
System.print(" %(intersects.call(p1, p2, cp, r, true))")</lang>
 
cp = Point.new(10, 10)
r = 5
System.print(" A circle, center %(cp) with radius %(r), and:")
 
p1 = Point.new( 5, 0)
p2 = Point.new( 5, 20)
System.print(" a vertical line containing the points %(p1) and %(p2) is/are:")
System.print(" %(intersects.call(p1, p2, cp, r, false))")
 
p1 = Point.new(-5, 10)
p2 = Point.new( 5, 10)
System.print(" a horizontal segment starting at %(p1) and ending at %(p2) is/are:")
System.print(" %(intersects.call(p1, p2, cp, r, true))")</syntaxhighlight>
 
{{out}}
Line 2,915 ⟶ 3,088:
a segment starting at (7, 4) and ending at (11, 8) is/are:
[(8, 5)]
A circle, center (10, 10) with radius 5, and:
a vertical line containing the points (5, 0) and (5, 20) is/are:
[(5, 10)]
a horizontal segment starting at (-5, 10) and ending at (5, 10) is/are:
[(5, 10)]
</pre>
 
=={{header|zkl}}==
{{trans|Go}}
<langsyntaxhighlight lang="zkl">const EPS=1e-14; // a close-ness to zero
// p1,p2 are (x,y), circle is ( (x,y),r )
fcn intersectLineCircle(p1,p2, circle, segment=False) // assume line
Line 2,967 ⟶ 3,145:
if(d==0) return( T( T(ux,uy) ) );
return( T(ux,uy), T(vx,vy) )
}</langsyntaxhighlight>
<langsyntaxhighlight lang="zkl">circle:=T( T(3,-5),3 ); p1,p2 := T(-10,11), T( 10,-9);
println("Circle @ ",circle); lcpp(p1,p2,circle);
p2:=T(-11,12); lcpp(p1,p2,circle,True);
Line 2,987 ⟶ 3,165:
.fmt(segment and "Segment" or "Line ",
p1,p2,intersectLineCircle(p1,p2, circle,segment)));
}</langsyntaxhighlight>
{{out}}
<pre>
2,127

edits