All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.ru.casperix.math.geometry.CurveFactory.kt Maven / Gradle / Ivy

package ru.casperix.math.geometry

import ru.casperix.math.geometry.float32.Geometry2Float
import ru.casperix.math.curve.float32.Arc2f
import ru.casperix.math.curve.float32.ParametricCurve2f
import ru.casperix.math.curve.float32.LineCurve2f
import ru.casperix.math.intersection.float32.Intersection2Float
import ru.casperix.math.vector.float32.Vector2f
import kotlin.math.sqrt

object CurveFactory {

//    fun buildLineAndArc2(
//        start: Vector2f,
//        startAndTangent: Vector2f,
//        finishAndTangent: Vector2f,
//        finish: Vector2f,
//        minLineLength: Float = 0.001f,
//        maxArcRange: Float = 1000f
//    ): Curve2f {
//        val O = Intersection2Float.getLineWithLine(Line2f(start, startAndTangent), Line2f(finish, finishAndTangent))
//            ?: return LineCurve2f(Line2f(start, finish))
//
//        val rayOS = start - O
//        val rayOF = finish - O
//
//        val lengthOS = rayOS.length()
//        val lengthOF = rayOF.length()
//
//        if (lengthOS > maxArcRange || lengthOF > maxArcRange) {
//            return LineCurve2f(Line2f(start, finish))
//        }
//
//        if (lengthOS > lengthOF) {
//            return buildLineAndArc2(
//                finish,
//                finishAndTangent,
//                startAndTangent,
//                start,
//                minLineLength,
//                maxArcRange
//            ).invert()
//        }
//
//        val pad1 = Geometry2Float.getPointAroundDirection(start, finish, startAndTangent, 0f)
//        val pad2 = Geometry2Float.getPointAroundDirection(start, finish, finishAndTangent, 0f)
//        val pad3 = Geometry2Float.getPointAroundDirection(start, finish, O, 0f)
//        if (pad1 != pad2 || pad1 != pad3) {
//            return LineCurve2f(Line2f(start, finish))
//        }
//
//        val rayOA = rayOF.normalize() * lengthOS
//        val A = O + rayOA
//
//        val dirCS = rayOS.rotateCW()
//        val dirCA = rayOA.rotateCCW()
//        val center = Intersection2Float.getLineWithLine(Line2f.byDelta(start, dirCS), Line2f.byDelta(A, dirCA))
//            ?: return LineCurve2f(Line2f(start, finish))
//
//        val range = center.distTo(start)
//
//        val middleAngle = RadianFloat.byDirection(O - center)
//        var deltaAngle = RadianFloat.betweenAngle(middleAngle, RadianFloat.byDirection(start - center))
//
//
//        val pad = Geometry2Float.getPointAroundDirection(start, startAndTangent, finish, 0f)
//        if (pad != PointAroundDirection.LEFT) {
//            deltaAngle = -deltaAngle
//        }
//
//        val arc = Arc2f(center, middleAngle - deltaAngle, deltaAngle * 2f, range)
//        val line = LineCurve2f(A, finish)
//        if (line.length() < minLineLength) {
//            return arc
//        }
//        return arc + line
//
//    }

    fun buildLineAndArc(
        start: Vector2f,
        startAndTangent: Vector2f,
        finishAndTangent: Vector2f,
        finish: Vector2f,
        minLineLength: Float = 0.001f,
    ): ParametricCurve2f {
        val O = Intersection2Float.getLineWithLine(
            Line2f(start, startAndTangent),
            Line2f(finish, finishAndTangent)
        )?.toVector2f()
            ?: return LineCurve2f(Line2f(start, finish))

        val toStart = start - O
        val toFinish = finish - O

        val range1 = toStart.lengthSquared()
        val range2 = toFinish.lengthSquared()
        val k = sqrt(range1 / range2)

        if (k > 0.999f && k < 1.001f) {
            return Arc2f.byTangent(start, startAndTangent - start, finish)
        }

        val padSAT = Geometry2Float.getPointAroundRay(start, finish, startAndTangent, 0f)
        val padFAT = Geometry2Float.getPointAroundRay(start, finish, finishAndTangent, 0f)
        if (padSAT != padFAT) {
            return LineCurve2f(Line2f(start, finish))
        }

        val padO = Geometry2Float.getPointAroundRay(start, finish, O, 0f)
        if (padO != padSAT) {
            return if (range1 > range2) {
                val T = toFinish * k
                buildLineAndArcDirect(start, startAndTangent, O + T, finish, true, minLineLength)
            } else {
                val T = toStart / k
                buildLineAndArcDirect(finish, finishAndTangent, O + T, start, false, minLineLength)
            }

        } else {
            return if (range1 < range2) {
                val T = toFinish * k
                buildLineAndArcDirect(start, startAndTangent, O + T, finish, true, minLineLength)
            } else {
                val T = toStart / k
                buildLineAndArcDirect(finish, finishAndTangent, O + T, start, false, minLineLength)
            }
        }
    }

    private fun buildLineAndArcDirect(
        arcStart: Vector2f,
        arcStartAndTangent: Vector2f,
        arcFinish: Vector2f,
        lineFinish: Vector2f,
        startFromArc: Boolean,
        minLineLength: Float,
    ): ParametricCurve2f {
        val line = LineCurve2f(arcFinish, lineFinish)
        val excludeLine = line.length() < minLineLength

        val actualArcFinish = if (excludeLine) {
            lineFinish
        } else {
            arcFinish
        }

        val arc = Arc2f.byTangent(arcStart, arcStartAndTangent - arcStart, actualArcFinish)
            ?: return LineCurve2f(arcStart, lineFinish)

        return if (excludeLine) {
            if (startFromArc) {
                arc
            } else {
                arc.invert()
            }
        } else {
            if (startFromArc) {
                arc + line
            } else {
                line.invert() + arc.invert()
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy