diff options
author | iximeow <me@iximeow.net> | 2017-03-22 00:59:44 -0700 |
---|---|---|
committer | iximeow <me@iximeow.net> | 2017-03-22 00:59:44 -0700 |
commit | b1376dff1a375c1371e175817c392f9cbce79377 (patch) | |
tree | 875b261db41ea8a381cd3fdd62be48e2e516fb75 | |
parent | 2770febcc400f5a16aea55ba7f11d942f8ccc22c (diff) |
partial refactoring to Surface instead of Segment + parabolic lenses
-rw-r--r-- | build.sbt | 2 | ||||
-rw-r--r-- | src/Objects.scala | 359 | ||||
-rw-r--r-- | src/Scene.scala | 88 | ||||
-rw-r--r-- | src/main.scala | 29 |
4 files changed, 404 insertions, 74 deletions
@@ -1,3 +1,5 @@ name := "DIFFS LOL" scalaSource in Compile := baseDirectory.value / "src" + +scalaVersion := "2.11.2" diff --git a/src/Objects.scala b/src/Objects.scala index b4e6435..a74ccc2 100644 --- a/src/Objects.scala +++ b/src/Objects.scala @@ -31,10 +31,26 @@ object Objects { Line(m, b) } } + trait Surface { + // returns a t where other first intersets with this surface + def intersect(other: Segment): Double + // intersect, but returns None if intersection (t) is outside [0,1] + def intersectChecked(other: Segment): Option[Point] + // surface is some parametric function Double => Point + def at(t: Double): Point + // aka at^-1, inverse of at(t). Option, for cases that p is not on this surface. + def tFor(p: Point): Option[Double] + // reflect a ray off this surface, assuming intersection at point + // returns a truncated form of source stopped at intersection + // and a continuation after interaction + def scatter(source: Ray, intersection: Point): (Ray, Ray) + def normal(t: Double): Ray + def renderTo(buf: BufferedImage, scale: Double, xoff: Int, yoff: Int, color: Int): Unit + } /* * Segments are defined for t in [0, 1] */ - case class Segment(x: Double, y: Double, initial: Point) { + case class Segment(x: Double, y: Double, initial: Point) extends Surface { def at(t: Double): Point = Point(x * t, y * t) + initial def apply = at _ def length = Math.sqrt(x * x + y * y) @@ -117,10 +133,344 @@ object Objects { case (x: ArrayIndexOutOfBoundsException) => { /* well, we're not properly rendering a region so uh just ignore the failure i guess lol */ } } } - def normal: Segment = { + def normal(t: Double): Ray = { val normalMag = Math.sqrt(x * x + y * y) val finalNormMult = 1.5 / normalMag - Ray(-y * finalNormMult, x * finalNormMult, (at(0) + at(1)) / 2).toSegment + Ray(-y * finalNormMult, x * finalNormMult, at(t)) + } + def scatter(r: Ray, firstIntersection: Point): (Ray, Ray) = { + def isBehind(start: Ray): Boolean = { + val normal = Ray(this.normal(0.5).x, this.normal(0.5).y, Point(0, 0)) + val rebased = Ray(start.x, start.y, Point(0, 0)) + val cosAngle = normal.dot(rebased) / (normal.mag * rebased.mag) + cosAngle > 0 + } + if (isBehind(r)) { // as in, 'r is behind this' + // stop. + (r.endingAt(firstIntersection), Ray(0, 0, r.initial)) + } else { + // reflect. + val minAngle = { + val fromStart = Raymath.angleBetween( + r.initial, + firstIntersection, + this.at(0) + ) + val fromEnd = Raymath.angleBetween( + r.initial, + firstIntersection, + this.at(1) + ) + + if (Math.abs(fromStart) < Math.PI / 2) { + fromStart + } else { + fromEnd + } + + fromStart + } + + val maxAngle = Math.PI - minAngle + + val baseAngle = Math.atan2(this.y, this.x) + + val reflectedAngle = baseAngle + minAngle + + if (minAngle < 0 || minAngle > Math.PI * 2) { + (r.endingAt(firstIntersection), r.endingAt(firstIntersection)) //Ray(0, 0, firstIntersection._2)) + } else { + val (x, y) = ( + Math.cos(reflectedAngle) * 3, + Math.sin(reflectedAngle) * 3 + ) + + // Sure hope this is right... + (r.endingAt(firstIntersection), Ray(x, y, firstIntersection)) + } + } + } + } + case class ParabolicLens(center: Point, rotation: Double, radius: Double, rMinor: Double) extends Surface { + // assume we can just use parabolic mirror equations here... + // 4FD = R^2, F = focal length, D = depth, R = radius + // so we know the intended radius and focal length, time to derive D.. + val depth = radius * radius / (4 * rMinor) + val b = radius * radius / (4 * rMinor) + val bi = 0 // -depth + /* + * P2_x = u * cos(rotation) - (bi + u^2 * b) * sin(rotation) + * P2_y = u * sin(rotation) + (bi + u^2 * b) * cos(rotation) + */ + def normal(t: Double): Ray = + normalRaw(t - 0.5) + + def normalRaw(t: Double): Ray = { + val cosRot = Math.cos(rotation) + val sinRot = Math.sin(rotation) + // p2_x' = -sin(rotation) - 2u*b*cos(rotation) + // p2_y' = cos(rotation) - 2u*b*sin(rotation) + val p2_xp = -sinRot - 2*(t) * b * cosRot + val p2_yp = cosRot - 2*(t) * b * sinRot + Ray(p2_xp, p2_yp, this.atRaw((t))) + } + def scatter(source: Ray, intersection: Point): (Ray, Ray) = { + // next up... + val rayEnd = intersection + val t = tFor(intersection) + //println(t) + t.map(t => { + val norm = normal(t) + // so we rotate by the angle diff of source and normal? times refraction index? + val angle = -(Math.PI - Raymath.angleBetween( + source.initial, + intersection, + norm.at(1) + )) * refractionIndex + /* + * rotation matrix: + * cos(rot) -sin(rot) + * sin(rot) +cos(rot) + */ + val out = Ray(source.x * Math.cos(angle) - source.y * Math.sin(angle), source.x * Math.sin(angle) + source.y * Math.cos(angle), intersection) + (source.endingAt(intersection), out) + }).getOrElse((source, Ray(source.x, source.y, source.at(1)))) + //??? + } + def tFor(p: Point): Option[Double] = { + val cosRot = Math.cos(rotation) + val sinRot = Math.sin(rotation) + // P2_x u: = center.x + u * cos(rotation) - (bi + u^2 * b) * sin(rotation) + // 0 = center.x - P2_x + u * cos(rotation) - (bi + u^2 * b) * sin(rotation) + // 0 = center.x - P2_x - bi * sin(rotation) + u * cos(rotation) - u^2 * b * sin(rotation) + // P2_y u: = center.y + u * sin(rotation) + (bi + u^2 * b) * cos(rotation) + // 0 = center.y - P2_y + bi * cos(rotation) + u * sin(rotation) + u^2 * b * cos(rotation) + val x_us = if (Math.abs(sinRot) > 0.0000001) { + quadradicRoots(-b * sinRot, cosRot, center.x - p.x - bi * sinRot) + } else { + Seq(-(center.x - p.x) / cosRot / 2) // why does this appear to be off by a factor of 2? + } + val y_us = if (Math.abs(cosRot) > 0.0000001) { + quadradicRoots(b * cosRot, sinRot, center.y - p.y + bi * cosRot) + } else { + Seq(-(center.y - p.y) / sinRot / 2) + } + //println(s"x_us: $x_us and y_us: $y_us") + val matches = for { + xu <- x_us + yu <- y_us + } yield { + if (Math.abs(xu - yu) < 0.00001) { + Some(xu) + } else { + None + } + } + matches.flatten match { + case Seq() => None + case Seq(u) => Some(u + 0.5) + case Seq(a, b) => { + if (Math.abs(a - b) < 0.000001) { + Some(a + 0.5) + } else { + throw new Exception("Too many t's for point " + p + " (" + a + ", " + b + ")") + } + } + case x => throw new Exception("Too many t's for point " + p + " (" + x + ")") + } + } + def renderTo(buf: BufferedImage, scale: Double = 1, xoff: Int = 0, yoff: Int = 0, color: Int = 0x205080): Unit = { + var i = 0.0 + while (i <= 1.0) { + val point = this.at(i) + try { + buf.setRGB(Math.round((point.x * scale).toFloat) + xoff, Math.round((point.y * scale).toFloat) + yoff, color) + } catch { + case e: Exception => { } + } + i = i + 0.01 // 100 points + } + } + + def at(t: Double): Point = atRaw(t - 0.5) + def atRaw(t: Double): Point = { + val cosRot = Math.cos(rotation) + val sinRot = Math.sin(rotation) + val t2 = t * t + val bit2b = bi + t2 * b + Point(t * cosRot * radius - bit2b * sinRot * radius, t * sinRot + bit2b * cosRot) + center + } + + val refractionIndex = 1.52 // 1.52-1.75 + def intersect(other: Segment): Double = { + /* + * WRONG: + * px = other.x * t + other.initial.x + * py = other.y * t + other.initial.y + * px = other.x + * P1_x = t + * P1_y = ai + t * a + * P2_x = u * cos(rotation) + * p2_y = (bi + u^2 * b) * sin(rotation) + * ai + t * a = (bi + u^2 * b) * sin(rotation) + * 0 = bi * sin(rotation) - ai - t * a + (t / cos(rotation))^2 * b * sin(rotation) // t == u by P1_x == P2_x + * 0 = bi * sin(rotation) - ai - t * a + t ^ 2 * b * sin(rotation) / cos(rotation) ^2 + * + * t = a +- sqrt(a^2 - 4 (b * sin(rotation) / cos(rotation)^2 * (bi * sin(rotation) - ai))) / 2(b * sin(rotation) / cos(rotation) ^2) + * + * + * WRONG: + * definition of p2_{x,y} is wrong for rotation. + * px = other.x * t + other.initial.x + * py = other.y * t + other.initial.y + * P1_x = axi + t * ax + * P1_y = ayi + t * ay + * P2_x = u * cos(rotation) + * p2_y = (bi + u^2 * b) * sin(rotation) + * + * P1_y = P2_y + * ayi + t * ay = (bi + u^2 * b) * sin(rotation) + * + * P1_x = P2_x + * axi + t * ax = u * cos(rotation) + * (axi + t * ax) / cos(rotation) = u + * + * sub u for t to have one variable to solve for + * reminder: t is parameter for `other` aka P1 + * ayi + t * ay = (bi + ((axi + t * ax) / cos(rotation))^2 * b) * sin(rotation) + * ayi + t * ay = (bi + (axi + t * ax)^2 / cos(rotation)^2 * b) * sin(rotation) + * ayi / sin(rotation) + t * ay / sin(rotation) = bi + (axi + t * ax)^2 / cos(rotation)^2 * b + * ayi / (b * sin(rotation)) + t * a / (b * sin(rotation)) = bi / b + (axi + t * ax)^2 / cos(rotation)^2 + * ayi / (b * sin(rotation)) - bi / b + t * ay / (b * sin(rotation)) = (axi + t * ax)^2 / cos(rotation)^2 + * (ai - bi * sin(rotation)) / (b * sin(rotation)) + t * a / (b * sin(rotation)) = (axi + t * ax)^2 / cos(rotation)^2 + * (cos(rotation)^2 * (ayi - bi * sin(rotation))) / (b * sin(rotation)) + t * ay * cos(rotation)^2 / (b * sin(rotation)) = (axi + t * ax)^2 + * (cos(rotation)^2 * (ayi - bi * sin(rotation))) / (b * sin(rotation)) + t * ay * cos(rotation)^2 / (b * sin(rotation)) = axi^2 + 2 * ax * axi * t + (t * ax)^2 + * (cos(rotation)^2 * (ayi - bi * sin(rotation))) / (b * sin(rotation)) - axi^2 - 2 * ax * axi * t + t * a * cos(rotation)^2 / (b * sin(rotation)) - t^2 * ax^2 = 0 + * (cos(rotation)^2 * (ayi - bi * sin(rotation))) / (b * sin(rotation)) - axi^2 + + * - 2 * ax * axi * t + t * ay * cos(rotation)^2 / (b * sin(rotation)) + + * - t^2 * ax^2 + * (cos(rotation)^2 * (ayi - bi * sin(rotation))) / (b * sin(rotation)) - axi^2 + + * t * (ay * cos(rotation)^2 - 2 * ax * axi * b * sin(rotation)) / (b * sin(rotation)) + + * - t^2 * ax^2 + * + * lol quadradic + * + * rotation matrix: + * cos(rot) -sin(rot) + * sin(rot) +cos(rot) + * + * RIGHT..ish: + * doesn't account for possibility of non-centered parabola. FIX: subtract axi and ayi by center.x and center.y. + * this SHOULD be what the math shows anyway... + * px = other.x * t + other.initial.x + * py = other.y * t + other.initial.y + * P1_x = axi + t * ax + * P1_y = ayi + t * ay + * P2_x = u * cos(rotation) * r - (bi + u^2 * b) * sin(rotation) * r + * P2_y = u * sin(rotation) + (bi + u^2 * b) * cos(rotation) + * + * so, intersect if P1_y(t1) == P2_y(u1) and P1_x(t1) == P2_x(u1) + * P1_x = P2_x: + * axi + t * ax = u * cos(rotation) * r - (bi + u^2 * b) * sin(rotation) * r + * t = (u * cos(rotation) * r - (bi + u^2 * b) * sin(rotation) * r - axi) / ax + * P1_y = P2_y: + * ayi + t * ay = u * sin(rotation) + (bi + u^2 * b) * cos(rotation) + * sub t to only solve for u + * ayi + (u * cos(rotation) * r - (bi + u^2 * b) * sin(rotation) * r - axi) / ax * ay = u * sin(rotation) + (bi + u^2 * b) * cos(rotation) + * ayi * ax / ay + u * cos(rotation) * r- (bi + u^2 * b) * sin(rotation) * r - axi = u * sin(rotation) * ax / ay + (bi + u^2 * b) * cos(rotation) * ax / ay + * ayi * ax / ay - axi + u * cos(rotation) * r - (bi + u^2 * b) * sin(rotation) * r = u * sin(rotation) * ax / ay + (bi + u^2 * b) * cos(rotation) * ax / ay + * ayi * ax / ay - axi + u * cos(rotation) * r - u * sin(rotation) * ax / ay - bi * sin(rotation) * r - u^2 * b * sin(rotation) * r = bi * cos(rotation) * ax / ay + u^2 * b * cos(rotation) * ax / ay + * ayi * ax / ay - axi - bi * cos(rotation) * ax / ay - bi * sin(rotation) * r + u * (cos(rotation) * r - sin(rotation) * ax / ay) - u^2 * b * sin(rotation) * r = u^2 * b * cos(rotation) * ax / ay + * (ayi - bi * cos(rotation)) * ax / ay - axi - bi * sin(rotation) * r + u * (cos(rotation) * r - sin(rotation) * ax / ay) - u^2 * b * sin(rotation) * r - u^2 * b * cos(rotation) * ax / ay = 0 + * (ayi - bi * cos(rotation)) * ax / ay - axi - bi * sin(rotation) * r + u * (cos(rotation) * r - sin(rotation) * ax / ay) - u^2 * b * (sin(rotation) * r + cos(rotation) * ax / ay) = 0 + * (ayi - bi * cos(rotation)) * ax / ay - axi - bi * sin(rotation) * r + + * u * (cos(rotation) * r - sin(rotation) * ax / ay) + + * - u^2 * b * (sin(rotation) * r - cos(rotation) * ax / ay) = 0 + * + * but in cases like this where ax = 0... + * -axi - bi * sin(rotation) * r + + * u * cos(rotation) * r + + * - u^2 * b * sin(rotation) * r + */ + val ax = other.x + val axi = other.initial.x - center.x + val ay = other.y + val ayi = other.initial.y - center.y + val cosRot = Math.cos(rotation) + val cosRot2 = cosRot * cosRot + val sinRot = Math.sin(rotation) + + val quad_a = b * (sinRot * radius + cosRot * ax / ay) + val quad_b = cosRot * radius - sinRot * ax / ay + val quad_c = (ayi - bi * cosRot) * ax / ay - axi - bi * sinRot * radius + + // potentially valid t for intersection + val options: Seq[Double] = if (Math.abs(quad_a) > 0.000001) { + quadradicRoots(quad_a, quad_b, quad_c) + } else { + // quad_a is basically 0, so... + // quad_b * u + quad_c == 0 + Seq(-quad_c / quad_b) + } + + /* + * Returns all u such that P2_x(u) = p2_xi + * p2_xi = u * cos(rotation) * r - (bi + u^2 * b) * sin(rotation) * r + * p2_xi + bi * sin(rotation) * r - u * cos(rotation) * r + u*2 * b * sin(rotation) * r = 0 + */ + def `P2_x^-1`(p2_xi: Double): Seq[Double] = quadradicRoots(b * sinRot * radius, cosRot * radius, p2_xi + bi * sinRot * radius) + def P1_x(t: Double): Double = other.at(t).x + def `P1^-1`(pt: Point): Double = { + val byX = (pt.x - other.initial.x) / other.x + val byY = (pt.y - other.initial.y) / other.y + if (Math.abs(other.x) <= 0.00001) { + byY + } else if (Math.abs(other.y) <= 0.00001) { + byX + } else { + 0 + } + } + + /* returns Some(t) if there is an intersection there, None if there is not */ + // eg verifies that at other(t), u = P2_x^-1(other(t).x), that + val ts: Seq[Double] = options.filter(u => u >= -0.5 && u <= 0.5).flatMap(u => { + val ourPoint = this.atRaw(u) + val candidateT = `P1^-1`(ourPoint) + //println("candidate t: " + candidateT) + //println("ours: " + ourPoint + " their: " + other.at(candidateT)) + Some(candidateT).filter(t => ourPoint.distTo(other.at(t)) < 0.00001) + }) + + ts match { + case Seq() => Double.NaN + case Seq(t) => t + case Seq(t1, t2) => Math.min(t1, t2) + } + } + + def quadradicRoots(a: Double, b: Double, c: Double): Seq[Double] = { + val radical = b * b - 4 * a * c + val bdiv2a = -b / (2 * a) + if (radical < 0) { + Nil + } else if (radical == 0) { + Seq(bdiv2a) + } else { + val sqrtRad = Math.sqrt(radical) / (2 * a) + Seq(bdiv2a + sqrtRad, bdiv2a - sqrtRad) + } + } + + def intersectChecked(other: Segment): Option[Point] = { + val u = intersect(other) + //println("Intersection is at u=" + u) + if (u >= 0 && u <= 1) { + + Some(other.at(u)) + } else { + None + } } } object Segment { @@ -147,5 +497,8 @@ object Objects { def mag: Double = { Math.sqrt(x * x + y * y) } + def at(t: Double): Point = { + initial + Point(x * t, y * t) + } } } diff --git a/src/Scene.scala b/src/Scene.scala index 9b59f7b..8454f0a 100644 --- a/src/Scene.scala +++ b/src/Scene.scala @@ -6,7 +6,7 @@ import java.awt.image.BufferedImage import javax.imageio._ import java.io.File -case class Scene(walls: Seq[Segment]) { +case class Scene(walls: Seq[Surface]) { val buffer = new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB) def render(scale: Double = 1, xoff: Int = 0, yoff: Int = 0, color: Int = 0x808000, normals: Boolean = false): Unit = { @@ -14,7 +14,7 @@ case class Scene(walls: Seq[Segment]) { wall.renderTo(buffer, scale, 400, 300, color = color) } for (wall <- walls) { - wall.normal.renderTo(buffer, scale, 400, 300, color = 0xc00000) + wall.normal(0.5).toSegment.renderTo(buffer, scale, 400, 300, color = 0xc00000) } } @@ -32,58 +32,14 @@ case class Scene(walls: Seq[Segment]) { def castSingle(r: Ray): (Ray, Ray) = { val asSeg = r.toSegment - def reflect(firstIntersection: (Segment, Point)): (Ray, Ray) = { - val minAngle = { - val fromStart = Raymath.angleBetween( - r.initial, - firstIntersection._2, - firstIntersection._1.at(0) - ) - val fromEnd = Raymath.angleBetween( - r.initial, - firstIntersection._2, - firstIntersection._1.at(1) - ) - - println("Fromstart: " + Raymath.toDegrees(fromStart)) - println("Fromend: " + Raymath.toDegrees(fromEnd)) - - if (Math.abs(fromStart) < Math.PI / 2) { - fromStart - } else { - fromEnd - } - - fromStart - } - - val maxAngle = Math.PI - minAngle - - val baseAngle = Math.atan2(firstIntersection._1.y, firstIntersection._1.x) - println("base angle: " + Raymath.toDegrees(baseAngle)) - - val reflectedAngle = baseAngle + minAngle - - if (minAngle < 0 || minAngle > Math.PI * 2) { - println("lol") - (r.endingAt(firstIntersection._2), r.endingAt(firstIntersection._2)) //Ray(0, 0, firstIntersection._2)) - } else { - val (x, y) = ( - Math.cos(reflectedAngle) * 3, - Math.sin(reflectedAngle) * 3 - ) - - // Sure hope this is right... - (r.endingAt(firstIntersection._2), Ray(x, y, firstIntersection._2)) - } - } - val intersections: Seq[(Segment, Point)] = walls.flatMap(w => { + val intersections: Seq[(Surface, Point)] = walls.flatMap(w => { w.intersectChecked(asSeg) .map(x => (w, x)) }) - .filter { case (w: Segment, x: Point) => asSeg.tFor(x).map(_ > 0.0000001).getOrElse(false) } + .filter { case (w: Surface, x: Point) => asSeg.tFor(x).map(_ > 0.0000001).getOrElse(false) } - def isBehind(start: Segment, wall: Segment): Boolean = { + /* + def isBehind(start: Segment, wall: Surface): Boolean = { val normal = Ray(-wall.y, wall.x, Point(0, 0)) val rebased = Ray(start.x, start.y, Point(0, 0)) val cosAngle = normal.dot(rebased) / (normal.mag * rebased.mag) @@ -101,27 +57,39 @@ case class Scene(walls: Seq[Segment]) { val otherT = i._1.tFor(i._2) otherT.map(t => t >= 0 && t <= 1 && isBehind(asSeg, i._1)).getOrElse(false) }) + */ - def fnMin(x: (Segment, Point), y: (Segment, Point)) = if (asSeg.tFor(x._2).get < asSeg.tFor(y._2).get) x else y - val firstStop: Option[(Segment, Point)] = stoppedIntersections.reduceOption(fnMin(_, _)) - val firstReflect: Option[(Segment, Point)] = continuedIntersections.reduceOption(fnMin(_, _)) + def fnMin(x: (Surface, Point), y: (Surface, Point)) = if (asSeg.tFor(x._2).get < asSeg.tFor(y._2).get) x else y + /* + val firstStop: Option[(Surface, Point)] = stoppedIntersections.reduceOption(fnMin(_, _)) + val firstReflect: Option[(Surface, Point)] = continuedIntersections.reduceOption(fnMin(_, _)) (firstStop, firstReflect) match { case (None, None) => (r, Ray(r.x, r.y, r.toSegment.at(1))) case (Some(stop), None) => (r.endingAt(stop._2), Ray(0, 0, r.initial)) - case (None, Some(cont)) => reflect(cont)/* reflect */ + case (None, Some(cont)) => cont._1.scatter(r, cont._2) //reflect(cont)// reflect case (Some(stop), Some(cont)) => { if (fnMin(stop, cont) == stop) { (r.endingAt(stop._2), Ray(0, 0, r.initial)) // stop } else { - reflect(cont) + cont._1.scatter(r, cont._2) + //reflect(cont) // reflect } } } + */ + val firstInteraction = intersections +// .map(x => {println("maybe " + x._1); x}) + .filter(i => i._1.tFor(i._2).map(t => t >= 0 && t <= 1).getOrElse(true)) + .reduceOption(fnMin(_, _)) + firstInteraction match { + case None => (r, Ray(r.x, r.y, r.toSegment.at(1))) + case Some(cont) => cont._1.scatter(r, cont._2) + } } } @@ -149,4 +117,14 @@ object Scene { def rotate(walls: Seq[Segment], angle: Double) = walls.map(_.rotate(angle)) + + def rays(number: Int, spacing: Double, centerpoint: Point, direction: Point): Seq[Ray] = { + (0 until number).map { i => + val x = (i.toDouble - number.toDouble / 2) * spacing + val y = 0 + val dx = direction.x + val dy = direction.y + Ray(dx, dy, Point(x, y) + centerpoint) + } + } } diff --git a/src/main.scala b/src/main.scala index 8883cc7..a0ea4cd 100644 --- a/src/main.scala +++ b/src/main.scala @@ -4,10 +4,12 @@ import Objects._ object main extends App { // val mirror = Scene(Scene.generateMirror(10, 60, Raymath.toRadians(180), Point(0, 0), 0)) val offset = Point(0.0, -9) - val mirror = Scene(Scene.generateParabola(-0.9, -0.0075, 16, 0, 42, Point(0, 14), 0) :+ Segment.fromPoints( - Point(-0.5, 0.5) + offset, - Point(0.5, -0.5) + offset - )) +// val mirror = Scene(Scene.generateParabola(-0.9, -0.0075, 16, 0, 142, Point(0, 14), 0) :+ Segment.fromPoints( +// Point(-0.5, 0.5) + offset, +// Point(0.5, -0.5) + offset +// ) :+ ParabolicLens(Point(4, -9), -Math.PI / 2, 1, 0.2) :+ ParabolicLens(Point(5, -1), 0, 1, 0.4)) +// + val mirror = Scene(Seq(ParabolicLens(Point(0, 1), 0.00, 2, 0.2))) // val mirror = Scene(Seq(Segment(4, -4, Point(-2, 2)))) //val ray = mirror.cast(Ray(0, 2, Point(0.8, -1)), 4) mirror.render(scale = 20, color = 0xc0c0c0, normals = true) @@ -21,20 +23,15 @@ object main extends App { } } */ - def rays(number: Int, spacing: Double, centerpoint: Point, direction: Point): Seq[Ray] = { - (0 until number).map { i => - val x = (i.toDouble - number.toDouble / 2) * spacing - val y = 0 - val dx = direction.x -// * Math.cos((i.toDouble - number.toDouble) / (number.toDouble / 4)) - val dy = direction.y - Ray(dx, dy, Point(x, y) + centerpoint) - } - } - rays(63, 0.165, Point(-0, -10), Point(0.0, 2)) - .flatMap(x => mirror.cast(x, 30)) +/* + rays(63, 0.165, Point(-0, -10), Point(0.0, 4)) + .flatMap(x => mirror.cast(x, 63)) .map(_.renderTo(mirror.buffer, 20, 400, 300)) //println(ray) +*/ + Scene.rays(4, 0.165, Point(0, -10), Point(0.0, 40)) + .flatMap(x => mirror.cast(x, 2)) + .map(_.renderTo(mirror.buffer, 20, 400, 300)) mirror.save() } |