Circle & line-segment intersection
This example is based on code found in Stack Overflow and it includes a function for finding intersection points between a line segment and a circle.
Processing / Java
Imports
import java.util.List;
PVector p0 = new PVector(100.0, 100.0);
PVector p1 = new PVector(400.0, 400.0);
float circleRadius = 90.0;
void settings() {
size(640, 480);
}
void draw() {
background(255);
fill(#FFAA00, 100);
stroke(0, 100);
strokeWeight(2);
PVector circleCenter = new PVector(mouseX, mouseY);
line(p0.x, p0.y, p1.x, p1.y);
circle(circleCenter.x, circleCenter.y, circleRadius * 2);
List<PVector> intersections = intersections(p0, p1, circleCenter, circleRadius);
for(PVector i : intersections) {
circle(i.x, i.y, 10);
}
}
List<PVector> intersections(PVector start, PVector end, PVector circleCenter, float radius) {
PVector d = PVector.sub(end, start);
PVector f = PVector.sub(start, circleCenter);
List<PVector> result = new ArrayList<PVector>();
float a = d.dot(d);
float b = 2 * f.dot( d );
float c = f.dot(f) - radius * radius;
float discriminant = b * b - 4 * a * c;
if ( discriminant < 0 ) {
return result;
}
discriminant = sqrt(discriminant);
float t1 = (-b - discriminant) / (2 * a);
float t2 = (-b + discriminant) / (2 * a);
if (t1 >= 0 && t1 <= 1) {
result.add(PVector.lerp(start, end, t1));
}
if (t2 >= 0 && t2 <= 1) {
result.add(PVector.lerp(start, end, t2));
}
return result;
}
OPENRNDR / Kotlin
Imports
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.math.Vector2
import org.openrndr.shape.Circle
import org.openrndr.shape.LineSegment
import kotlin.math.sqrt
fun main() = application {
program {
val line = LineSegment(100.0, 100.0, 400.0, 400.0)
var cir = Circle(Vector2.ZERO, 90.0)
extend {
drawer.clear(ColorRGBa.WHITE)
drawer.fill = ColorRGBa.fromHex("FFAA00").opacify(0.4)
drawer.stroke = ColorRGBa.BLACK.opacify(0.4)
drawer.strokeWeight = 2.0
cir = cir.movedTo(mouse.position)
drawer.lineSegment(line)
drawer.circle(cir)
drawer.circles(line.intersections(cir), 10.0)
}
}
}
private fun LineSegment.intersections(cir: Circle): List<Vector2> {
val d = end - start
val f = start - cir.center
val result = mutableListOf<Vector2>()
val a = d.dot(d)
val b = 2 * f.dot(d)
val c = f.dot(f) - cir.radius * cir.radius
var discriminant = b * b - 4 * a * c
if (discriminant < 0) {
return result
}
discriminant = sqrt(discriminant)
val t1 = (-b - discriminant) / (2 * a)
val t2 = (-b + discriminant) / (2 * a)
if (t1 in 0.0..1.0) {
result.add(mix(start, end, t1))
}
if (t2 in 0.0..1.0) {
result.add(mix(start, end, t2))
}
return result
}
Concept | Processing | OPENRNDR |
---|---|---|
geometry and shape classes |
PVector , PShape
|
Vector2 , Vector3 , Vector4 , Circle , Rectangle , and more, LineSegment , Shape , ShapeContour and more
|
add methods to existing classes | possible using inheritance | Kotlin lets you extend a class with new functionality without having to inherit from the class or use any design patterns. In this program we added the method .intersections() to LineSegment . |
draw a line between two points | line(p0.x, p0.y, p1.x, p1.y); |
drawer.lineSegment(line) //or drawer.lineSegment(p0, p1)
|
mouse position vector | new PVector(mouseX, mouseY); |
mouse.position |
draw segment-circle intersections | List<PVector> intersections = intersections(p0, p1, circleCenter, circleRadius); for(PVector i : intersections) { circle(i.x, i.y, 10); } |
drawer.circles( line.intersections(cir), 10.0) |
subtract two vectors | PVector d = PVector.sub(end, start); |
val d = end - start |
check if variable in given range | if (t1 >= 0 && t1 <= 1) |
if (t1 in 0.0..1.0) |
linear interpolation between two vectors | PVector.lerp(start, end, pos) |
mix(start, end, pos) |
I like that in OPENRNDR vector data types (representing points in 2D, 3D or 4D) can be used to define shapes, draw them, set colors, call noise functions, etc. For example you can do line(p1, p2)
instead of line(p1.x, p1.y, p2.x, p2.y)
. Those same vectors can easily be combined using +
, -
, *
, /
to write very readable expressions, for example line(p1+p2, p1-p2)
, where p1
and p2
are 2D points.
Note: if you are wondering where do start
and end
come from in the OPENRNDR example, note that the context of the .intersections()
function is the LineSegment
class, which luckily has properties called start
and end
.
Using IntelliJ Idea
In the past, if I needed a function, I would first write the function and only then use it. Now I do it the other way around: I first write the function call including the desired arguments. Idea will highlight it as an error and, by pressing Alt+Enter, it will suggest to create that function.
This not only works for a a typical function call like add(person1, person2)
but also for generating operator overloading functions, like person1 + person2
or even person1.add(person2)
. In all these cases the IDE suggests adding something that will make the code compile.
That is how I generated the LineSegment.intersections()
function: I typed line.intersections(cir)
and Idea created the empty function which I then populated.
Share your questions and comments below |
Find other OPENRNDR & Processing posts