<commit_before>module OpenSolid.CubicSpline2d
    exposing
        ( bezier
        , hermite
        , controlPoints
        , startPoint
        , endPoint
        , startDerivative
        , endDerivative
        , point
        , derivative
        , scaleAbout
        , rotateAround
        , translateBy
        , mirrorAcross
        , relativeTo
        , placeIn
        , placeOnto
        )

{-| A `CubicSpline2d` is a cubic [Bézier curve](https://en.wikipedia.org/wiki/B%C3%A9zier_curve)
in 2D defined by four control points. This module contains functionality for

  - Evaluating points and derivatives along a spline
  - Scaling, rotating, translating or mirroring a spline
  - Converting a spline between local and global coordinates in different
    reference frames

Splines can be constructed by passing a tuple of control points to the
`CubicSpline2d` constructor, for example

    exampleSpline =
        CubicSpline2d
            ( Point2d ( 1, 1 )
            , Point2d ( 3, 4 )
            , Point2d ( 5, 1 )
            , Point2d ( 7, 4 )
            )


# Constructors

@docs bezier, hermite


# Accessors

@docs controlPoints, startPoint, endPoint, startDerivative, endDerivative


# Evaluation

@docs point, derivative


# Transformations

@docs scaleAbout, rotateAround, translateBy, mirrorAcross


# Coordinate frames

@docs relativeTo, placeIn


# Sketch planes

@docs placeOnto

-}

import OpenSolid.Geometry.Types exposing (..)
import OpenSolid.Point2d as Point2d
import OpenSolid.Vector2d as Vector2d


bezier : Point2d -> Point2d -> Point2d -> Point2d -> CubicSpline2d
bezier firstPoint secondPoint thirdPoint fourthPoint =
    CubicSpline2d ( firstPoint, secondPoint, thirdPoint, fourthPoint )


hermite : ( Point2d, Vector2d ) -> ( Point2d, Vector2d ) -> CubicSpline2d
hermite start end =
    let
        ( startPoint, startDerivative ) =
            start

        ( endPoint, endDerivative ) =
            end

        startControlPoint =
            startPoint
                |> Point2d.translateBy
                    (Vector2d.scaleBy (1 / 3) startDerivative)

        endControlPoint =
            endPoint
                |> Point2d.translateBy
                    (Vector2d.scaleBy (-1 / 3) endDerivative)
    in
        bezier startPoint startControlPoint endControlPoint endPoint


controlPoints : CubicSpline2d -> ( Point2d, Point2d, Point2d, Point2d )
controlPoints (CubicSpline2d controlPoints_) =<commit_msg>Start documenting CubicSpline2d constructors<commit_after>module OpenSolid.CubicSpline2d
    exposing
        ( bezier
        , hermite
        , controlPoints
        , startPoint
        , endPoint
        , startDerivative
        , endDerivative
        , point
        , derivative
        , scaleAbout
        , rotateAround
        , translateBy
        , mirrorAcross
        , relativeTo
        , placeIn
        , placeOnto
        )

{-| A `CubicSpline2d` is a cubic [Bézier curve](https://en.wikipedia.org/wiki/B%C3%A9zier_curve)
in 2D defined by four control points. This module contains functionality for

  - Evaluating points and derivatives along a spline
  - Scaling, rotating, translating or mirroring a spline
  - Converting a spline between local and global coordinates in different
    reference frames

Splines can be constructed by passing a tuple of control points to the
`CubicSpline2d` constructor, for example

    exampleSpline =
        CubicSpline2d
            ( Point2d ( 1, 1 )
            , Point2d ( 3, 4 )
            , Point2d ( 5, 1 )
            , Point2d ( 7, 4 )
            )


# Constructors

@docs bezier, hermite


# Accessors

@docs controlPoints, startPoint, endPoint, startDerivative, endDerivative


# Evaluation

@docs point, derivative


# Transformations

@docs scaleAbout, rotateAround, translateBy, mirrorAcross


# Coordinate frames

@docs relativeTo, placeIn


# Sketch planes

@docs placeOnto

-}

import OpenSolid.Geometry.Types exposing (..)
import OpenSolid.Point2d as Point2d
import OpenSolid.Vector2d as Vector2d


{-| Construct a spline from its four control points. This is the same as just
using the `CubicSpline2d` constructor directly;

    CubicSpline2d.bezier p1 p2 p3 p4

is equivalent to

    CubicSpline2d ( p1, p2, p3, p4 )

-}
bezier : Point2d -> Point2d -> Point2d -> Point2d -> CubicSpline2d
bezier firstPoint secondPoint thirdPoint fourthPoint =
    CubicSpline2d ( firstPoint, secondPoint, thirdPoint, fourthPoint )


{-| Construct a spline in Hermite form, from the position and derivative values
at its start and end points.
-}
hermite : ( Point2d, Vector2d ) -> ( Point2d, Vector2d ) -> CubicSpline2d
hermite start end =
    let
        ( startPoint, startDerivative ) =
            start

        ( endPoint, endDerivative ) =
            end

        startControlPoint =
            startPoint
                |> Point2d.translateBy
                    (Vector2d.scaleBy (1 / 3) startDerivative)

        endControlPoint =
            endPoint
                |> Point2d.translateBy
                    (Vector2d.scaleBy (-1 / 3) endDerivative)
    in
        bezier startPoint startControlPoint endControlPoint endPoint


controlPoints : CubicSpline2d -> ( Point2d, Point2d, Point2d, Point2d )
controlPoints (CubicSpline2d controlPoints_) =
{'fraction_non_alphanumeric': 0.06657839984868545, 'fraction_numerical': 0.02042746358993758, 'mean_word_length': 2.427090084251458, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 21, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2246312', 'n_tokens_mistral': 1697, 'n_tokens_neox': 1567, 'n_words': 447}