Skip to content

Commit

Permalink
添加graphics,包括point和line
Browse files Browse the repository at this point in the history
  • Loading branch information
RainbowYang committed Nov 15, 2018
1 parent 9f0c948 commit 50e586a
Show file tree
Hide file tree
Showing 21 changed files with 208 additions and 360 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ plugins {
}

group 'moe.rainbowyang'
version '0.1.3'
version '0.2.0'

repositories {
mavenCentral()
Expand Down
8 changes: 8 additions & 0 deletions src/main/kotlin/moe/rainbowyang/math/graphics/Graphics.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package moe.rainbowyang.math.graphics

/**
* 抽象图形
* @author: Rainbow Yang
* @create: 2018-11-14 18:52
**/
interface Graphics
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
package moe.rainbowyang.math.line
package moe.rainbowyang.math.graphics.line

import moe.rainbowyang.math.almostEquals
import moe.rainbowyang.math.point.Point2D
import moe.rainbowyang.math.graphics.point.Point2D
import moe.rainbowyang.math.number.Real
import moe.rainbowyang.math.number.toReal
import kotlin.math.atan

/**
* 数学意义上的线
* 提供求交点等功能
* 表达式为ax+by+c=0
*
* @author Rainbow Yang
*/
class Line(val a: Double, val b: Double, val c: Double) {
class Line(val a: Real, val b: Real, val c: Real) {

/** 斜率 */
val slope = -a / b
/** 倾斜角 */
val angle = atan(slope)
val angle = atan(slope.value).toReal()

constructor(a: Number, b: Number, c: Number) : this(a.toDouble(), b.toDouble(), c.toDouble())
constructor(a: Number, b: Number, c: Number) : this(a.toReal(), b.toReal(), c.toReal())

companion object {
/**
Expand All @@ -36,14 +37,15 @@ class Line(val a: Double, val b: Double, val c: Double) {
*/
operator fun invoke(point: Point2D, angle: Double) =
if ((angle - Math.PI / 2) % Math.PI almostEquals 0.0) {
Line(1, 0, -point.x)
Line(1, 0, -point.x.value)
} else {
val a = Math.tan(angle)
Line(a, -1, point.y * (1 - a))
Line(a, -1, point.y.value * (1 - a))
}

val X_AXIS = Line(0.0, 1.0, 0.0)
val Y_AXIS = Line(1.0, 0.0, 0.0)
operator fun invoke(point: Point2D, angle: Real) = invoke(point, angle.value)
}

/**
Expand All @@ -52,7 +54,8 @@ class Line(val a: Double, val b: Double, val c: Double) {
*/
infix fun crossTo(other: Line): Point2D {
//平行
if (a * other.b - b * other.a == 0.0) throw NoCrossException("$this has no cross with $other")
if (a * other.b - b * other.a == Real.ZERO)
throw NoCrossException("$this has no cross with $other")

return Point2D(-(c * other.b - b * other.c) / (a * other.b - b * other.a),
-(a * other.c - c * other.a) / (a * other.b - b * other.a))
Expand Down
38 changes: 38 additions & 0 deletions src/main/kotlin/moe/rainbowyang/math/graphics/point/Point.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package moe.rainbowyang.math.graphics.point

import moe.rainbowyang.math.graphics.Graphics
import moe.rainbowyang.math.number.Real
import moe.rainbowyang.math.operation.Addition

/**
* 抽象点
* 所有子类的所有操作均不应修改其本身,而是返回一个新的类
* 所有点之间都应能够进行互相转换,可以用[PointAxes]作为中介
* @author Rainbow Yang
*/
abstract class Point : Graphics, Addition<Point> {

/**
* 转换为[PointAxes]
*/
abstract val asAxes: PointAxes

/**
* 检测该点中是否没有[Double.NaN]之类无效的值
*/
open val available: Boolean get() = asAxes.available

/**
* 默认通过[PointAxes]进行计算,值为其模
*/
open val length: Real get() = asAxes.length

override operator fun plus(other: Point): Point = asAxes.plus(other.asAxes)
override operator fun unaryMinus(): Point = this * -Real.ONE

open operator fun times(times: Real): Point = asAxes * times
open operator fun div(div: Real): Point = this * div.reciprocal()

override fun equals(other: Any?): Boolean = asAxes == other
override fun hashCode(): Int = asAxes.hashCode()
}
23 changes: 23 additions & 0 deletions src/main/kotlin/moe/rainbowyang/math/graphics/point/Point2D.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package moe.rainbowyang.math.graphics.point

import moe.rainbowyang.math.number.Real
import moe.rainbowyang.math.number.atan2

/**
* 二维笛卡尔坐标系点
* @author Rainbow Yang
*/
data class Point2D(val x: Real, val y: Real) : Point() {

constructor(point: PointAxes) : this(point[0], point[1])

override val asAxes = PointAxes(x, y)

val angle = atan2(y, x)

/**
* 逆时针旋转[angle]【弧度】
*/
fun spin(angle: Real) = asPoint2DPolar.spin(angle).asPoint2D

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package moe.rainbowyang.math.graphics.point

import moe.rainbowyang.math.number.Real
import moe.rainbowyang.math.number.toReal
import moe.rainbowyang.math.operation.cos
import moe.rainbowyang.math.operation.sin

/**
* 二维极坐标点
* @author Rainbow Yang
*/
data class Point2DPolar(val radius: Real, val angle: Real) : Point() {

constructor(radius: Number, angle: Number) : this(radius.toReal(), angle.toReal())

companion object {
operator fun invoke(form: Point): Point2DPolar {
val pd = form.asPoint2D
return Point2DPolar(pd.length, pd.angle)
}
}

override val asAxes by lazy { PointAxes(radius * cos(angle), radius * sin(angle)) }

/**
* 逆时针旋转[angle]【弧度】
*/
fun spin(angle: Real) = Point2DPolar(radius, this.angle + angle)

}

30 changes: 30 additions & 0 deletions src/main/kotlin/moe/rainbowyang/math/graphics/point/Point3D.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package moe.rainbowyang.math.graphics.point

import moe.rainbowyang.math.number.Real
import moe.rainbowyang.math.number.toReal

/**
* 三维轴坐标点
* @author Rainbow Yang
*/
data class Point3D(val x: Real, val y: Real, val z: Real) : Point() {

constructor(x: Number = 0, y: Number = 0, z: Number = 0) : this(x.toReal(), y.toReal(), z.toReal())

companion object {
operator fun invoke(form: Point): Point3D {
val (x, y, z) = form.asAxes
return Point3D(x, y, z)
}
}

override val asAxes = PointAxes(x, y, z)

fun spinAtXY(angle: Real) = asAxes.spinAtAndNew(0, 1, angle)
fun spinAtXZ(angle: Real) = asAxes.spinAtAndNew(0, 2, angle)
fun spinAtYX(angle: Real) = asAxes.spinAtAndNew(1, 0, angle)
fun spinAtYZ(angle: Real) = asAxes.spinAtAndNew(1, 2, angle)
fun spinAtZX(angle: Real) = asAxes.spinAtAndNew(2, 0, angle)
fun spinAtZY(angle: Real) = asAxes.spinAtAndNew(2, 1, angle)

}
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package moe.rainbowyang.math.point
package moe.rainbowyang.math.graphics.point

import moe.rainbowyang.math.number.*
import moe.rainbowyang.math.operation.cos
import moe.rainbowyang.math.operation.sin

/**
* 三维球坐标系点
* @author Rainbow Yang
*/
class Point3DSpherical(val r: Double, val theta: Double, val phi: Double) : Point {
class Point3DSpherical(val r: Real, val theta: Real, val phi: Real) : Point() {

constructor(r: Number = 0, θ: Number = 0, φ: Number = 0) : this(r.toDouble(), θ.toDouble(), φ.toDouble())
constructor(r: Number = 0, θ: Number = 0, φ: Number = 0) : this(r.toReal(), θ.toReal(), φ.toReal())

operator fun component1() = r
operator fun component2() = theta
Expand All @@ -17,19 +21,17 @@ class Point3DSpherical(val r: Double, val theta: Double, val phi: Double) : Poin
val (x, y, z) = form.asAxes

val r = form.length
val theta = Math.acos(z / r)
val theta = Math.acos((z / r).value).toReal()
val phi = Point2D(x, y).angle

return Point3DSpherical(r, theta, phi)
}
}

fun spinAtTheta(angle: Double) = Point3DSpherical(r, theta + angle, phi)
fun spinAtPhi(angle: Double) = Point3DSpherical(r, theta, phi + angle)
fun spinAtTheta(angle: Real) = Point3DSpherical(r, theta + angle, phi)
fun spinAtPhi(angle: Real) = Point3DSpherical(r, theta, phi + angle)

override val asAxes by lazy {
PointAxes(r * Math.sin(theta) * Math.cos(phi), r * Math.sin(theta) * Math.sin(phi), r * Math.cos(theta))
}
override val asAxes = PointAxes(r * sin(theta) * cos(phi), r * sin(theta) * sin(phi), r * cos(theta))

override fun toString(): String {
return "Point3DSpherical(r=$r, theta=$theta, phi=$phi)"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
package moe.rainbowyang.math.point
package moe.rainbowyang.math.graphics.point

import moe.rainbowyang.math.checkValues
import moe.rainbowyang.math.lengthOf
import moe.rainbowyang.math.number.*
import moe.rainbowyang.math.until
import java.util.*
import kotlin.math.max


/**
* 任意纬度的坐标轴点
*
* @author Rainbow Yang
*/
class PointAxes(val values: List<Double>) : Point {
class PointAxes(val values: List<Real>) : Point() {

constructor(vararg values: Real) : this(List(values.size) { values[it] })

constructor(vararg values: Number) : this(List(values.size) { values[it].toDouble() })
/**
* 生成size维的值均为value的点
*/
constructor(value: Real, size: Int) : this(List(size) { value })

//生成size维的值均为value的点
constructor(value: Double, size: Int) : this(List(size) { value })
constructor(value: Number, size: Int) : this(List(size) { value.toReal() })

/**
* 维度数
Expand All @@ -27,33 +30,32 @@ class PointAxes(val values: List<Double>) : Point {
operator fun component2() = values[1]
operator fun component3() = values[2]
operator fun component4() = values[3]
operator fun component5() = values[4]

operator fun get(index: Int) = values.getOrElse(index) { 0.0 } //维度不够时补0
operator fun get(index: Int) = values.getOrElse(index) { Real.ZERO } //维度不够时补0

override val asAxes get() = this
override val asAxes = this

override val available get() = values.checkValues()
override val length get() = values.lengthOf()
override val available = values.checkValues()
override val length = values.lengthOf()

override fun plus(other: Point): Point {
val paOther = other.asAxes
return PointAxes(List(max(size, paOther.size)) { this[it] + paOther[it] })
}

override operator fun times(times: Double) = PointAxes(List(size) { get(it) * times })
override operator fun times(times: Real) = PointAxes(List(size) { get(it) * times })


fun plusAt(index: Int, plus: Number): PointAxes =
PointAxes(createNewListWithOldData(index).apply { this[index] += plus.toDouble() })
fun plusAt(index: Int, plus: Real): PointAxes =
PointAxes(createNewListWithOldData(index).apply { this[index] += plus })

fun setAtAndNew(index: Int, value: Number): PointAxes =
PointAxes(createNewListWithOldData(index).apply { this[index] = value.toDouble() })
PointAxes(createNewListWithOldData(index).apply { this[index] = value.toReal() })

fun timesAtAndNew(index: Int, times: Number): PointAxes =
PointAxes(createNewListWithOldData(index).apply { this[index] *= times.toDouble() })
PointAxes(createNewListWithOldData(index).apply { this[index] *= times.toReal() })

fun spinAtAndNew(firstIndex: Int, secondIndex: Int, angle: Number): PointAxes {
fun spinAtAndNew(firstIndex: Int, secondIndex: Int, angle: Real): PointAxes {
val newValues = createNewListWithOldData(firstIndex, secondIndex)
val (x, y) = Point2D(this[firstIndex], this[secondIndex]).asPoint2DPolar.spin(angle).asAxes
newValues[firstIndex] = x
Expand All @@ -67,7 +69,7 @@ class PointAxes(val values: List<Double>) : Point {

private fun createNewListWithOldData(index: Int) = MutableList(max(index + 1, size)) { get(it) }

override fun toString() = "PointForAxes(${Arrays.toString(values.toDoubleArray())})"
override fun toString() = "PointForAxes(${Arrays.toString(values.toTypedArray())})"


override fun equals(other: Any?): Boolean {
Expand All @@ -85,7 +87,7 @@ class PointAxes(val values: List<Double>) : Point {
}

override fun hashCode(): Int {
return Arrays.hashCode(values.toDoubleArray())
return Arrays.hashCode(values.toTypedArray())
}

}
Loading

0 comments on commit 50e586a

Please sign in to comment.