<commit_before>/*
 * Copyright 2013 <NAME>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package scaladelray.math

/**
 * This class represents a transform that is used by [[scaladelray.geometry.Node]] to transform the geometries within
 * the scene graph node. A new Transform object is not directly created by calling a constructor, but by using methods
 * of the companion object.
 *
 * The Transformation keeps track of the transformation matrix and the inverse matrix of it. New transformations are
 * appended by calling the transformation methods of this object. The transformation is appended on the right side.
 *
 * A transformation object is immutable.
 *
 * @author <NAME>
 * @param m The transformation matrix of this transformation.
 * @param i The inverse transformation matrix of this transformation.
 */
class Transform private ( val m : Mat4x4, val i : Mat4x4 ) {

  /**
   * This method appends a translation by the given x, y, and z values to the current transformation and returns
   * a new Transformation object.
   *
   * @param x The x value for the translation.
   * @param y The y value for the translation.
   * @param z The z value for the translation.
   * @return A new Transformation object with the appended translation.
   */
  def translate( x : Double, y : Double, z : Double ) : Transform = {
    val t = Transform.translate( x, y, z )
    new Transform( m * t.m, t.i * i )
  }

  /**
   * This method appends a translation by a given direction to the current transformation and returns
   * a new Transformation object.
   *
   * @param v The direction of the translation.
   * @return A new Transformation object with the appended translation.
   */
  def translate( v : Vector3 ) : Transform = this.translate( v.x, v.y, v.z )

  def scale( x : Double, y : Double, z : Double ) : Transform = {
    val t = Transform.scale( x, y, z )
    new Transform( m * t.m, t.i * i )
  }

  def rotateX( angle : Double ) : Transform = {
    val t = Transform.rotateX( angle )
    new Transform( m * t.m, t.i * i )
  }

  def rotateY( angle : Double ) : Transform = {
    val t = Transform.rotateY( angle )
    new Transform( m * t.m, t.i * i )
  }

  def rotateZ( angle : Double ) : Transform = {
    val t = Transform.rotateZ( angle )
    new Transform( m * t.m, t.i * i )
  }


  override def equals( obj: Any ) =
    obj match {
      case t : Transform =>
        this.m == t.m && this.i == t.i
      case _ =>
        false
    }


  def *( r : Ray ) = Ray( i * r.o, i * r.d )
  def *( n : Normal3 ) = (i.transposed * n.asVector).normalized.asNormal

}


object Transform {

  def translate( x : Double, y : Double, z : Double ) = new Transform(
    Mat4x4( 1.0, 0.0, 0.0, x,
            0.0, 1.0, 0.0, y,
            0.0, 0.0, 1.0, z,
            0.0, 0.0, 0.0, 1.0 ),
    Mat4x4( 1.0, 0.0, 0.0, -x,
            0.0, 1.0, 0.0, -y,
            0.0, 0.0, 1.0, -z,
            0.0, 0.0, 0.0, 1.0 )
  )

  def translate( p : Point3 ) : Transform = Transform.translate( p.x, p.y, p.z )

  def scale( x : Double, y : Double, z : Double ) = new Transform(
    Mat4x4( x,   0.0, 0.0, 0.0,
            0.0, y,   0.0, 0.0,
            0.0, 0.0, z,   0.0,
            0.0, 0.0, 0.0, 1.0 ),

    Mat4x4( 1.0/x, 0.0,   0.0,   0.0,
            0.0,   1.0/y, 0.0,   0.0,
            0.0,   0.0,   1.0/z, 0.0,
            0.0,   0.0,   0.0,   1.0 )
  )

  def rotateX( angle : Double ) = new Transform(
    Mat4x4( 1.0, 0.0,               0.0,                0.0,
            0.0, math.cos( angle ), -math.sin( angle ), 0.0,
            0.0, math.sin( angle ), math.cos( angle ),  0.0,
            0.0, 0.0,                0.0,               1.0 ),
    Mat4x4( 1.0, 0.0,                0.0,               0.0,
            0.0, math.cos( angle ),  math.sin( angle ), 0.0,
            0.0, -math.sin( angle ), math.cos( angle ), 0.0,
            0.0, 0.0,                0.0,               1.0 )
  )

  def rotateY( angle : Double ) = new Transform(
      Mat4x4( math.cos( angle ),  0.0, math.sin( angle ), 0.0,
              0.0,                1.0, 0.0,               0.0,
              -math.sin( angle ), 0.0, math.cos( angle ), 0.0,
              0.0,                0.0, 0.0,               1.0 ),
      Mat4x4( math.cos( angle ), 0.0, -math.sin( angle ), 0.0,
              0.0,               1.0, 0.0,                0.0,
              math.sin( angle ), 0.0, math.cos( angle ),  0.0,
              0.0,               0.0, 0.0,                1.0 )
  )

  def rotateZ( angle : Double ) = new Transform(
    Mat4x4( math.cos( angle ), -math.sin( angle ), 0.0, 0.0,
            math.sin( angle ), math.cos( angle ),  0.0, 0.0,
            0.0,               0.0,                1.0, 0.0,
            0.0,               0.0,                0.0, 1.0 ),
    Mat4x4( math.cos( angle ),  math.sin( angle ), 0.0, 0.0,
            -math.sin( angle ), math.cos( angle ), 0.0, 0.0,
            0.0,                0.0,               1.0, 0.0,
            0.0,                0.0,               0.0, 1.0 )
  )

}<commit_msg>Documentation for the Transform class<commit_after>/*
 * Copyright 2013 <NAME>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package scaladelray.math

/**
 * This class represents a transform that is used by [[scaladelray.geometry.Node]] to transform the geometries within
 * the scene graph node. A new Transform object is not directly created by calling a constructor, but by using methods
 * of the companion object.
 *
 * The Transformation keeps track of the transformation matrix and the inverse matrix of it. New transformations are
 * appended by calling the transformation methods of this object. The transformation is appended on the right side.
 *
 * A transformation object is immutable.
 *
 * @author <NAME>
 * @param m The transformation matrix of this transformation.
 * @param i The inverse transformation matrix of this transformation.
 */
class Transform private ( val m : Mat4x4, val i : Mat4x4 ) {

  /**
   * This method appends a translation by the given x, y, and z values to the current transformation and returns
   * a new Transformation object.
   *
   * @param x The x value for the translation.
   * @param y The y value for the translation.
   * @param z The z value for the translation.
   * @return A new Transformation object with the appended translation.
   */
  def translate( x : Double, y : Double, z : Double ) : Transform = {
    val t = Transform.translate( x, y, z )
    new Transform( m * t.m, t.i * i )
  }

  /**
   * This method appends a translation by a given point to the current transformation and returns
   * a new Transformation object.
   *
   * @param p The point of the translation.
   * @return A new Transformation object with the appended translation.
   */
  def translate( p : Point3 ) : Transform = this.translate( p.x, p.y, p.z )

  /**
   * This method appends a scale transformation by given factors to an existing transformation and returns a new
   * transformation object.
   *
   * @param x The scale factor for the x axis.
   * @param y The scale factor for the y axis.
   * @param z The scale factor for the z axis.
   * @return The new Transformation object with the appended scale transformation.
   */
  def scale( x : Double, y : Double, z : Double ) : Transform = {
    val t = Transform.scale( x, y, z )
    new Transform( m * t.m, t.i * i )
  }

  /**
   * This method appends a rotation around the x axis to the transformation and returns a new transformation object.
   *
   * @param angle The angle of the rotation in radians.
   * @return The new Transformation object with the appended rotation around the x axis.
   */
  def rotateX( angle : Double ) : Transform = {
    val t = Transform.rotateX( angle )
    new Transform( m * t.m, t.i * i )
  }

  /**
   * This method appends a rotation around the y axis to the transformation and returns a new transformation object.
   *
   * @param angle The angle of the rotation in radians.
   * @return The new Transformation object with the appended rotation around the y axis.
   */
  def rotateY( angle : Double ) : Transform = {
    val t = Transform.rotateY( angle )
    new Transform( m * t.m, t.i * i )
  }

  /**
   * This method appends a rotation around the z axis to the transformation and returns a new transformation object.
   *
   * @param angle The angle of the rotation in radians.
   * @return The new Transformation object with the appended rotation around the z axis.
   */
  def rotateZ( angle : Double ) : Transform = {
    val t = Transform.rotateZ( angle )
    new Transform( m * t.m, t.i * i )
  }

  override def equals( obj: Any ) =
    obj match {
      case t : Transform =>
        this.m == t.m && this.i == t.i
      case _ =>
        false
    }


  /**
   * This operator transforms a ray by multiplying the origin and the direction with the inverse transformation matrix.
   *
   * @param r The ray to transform.
   * @return The transformed ray.
   */
  def *( r : Ray ) = Ray( i * r.o, i * r.d )

  /**
   * This operator transforms a normals by multiplying it wth the transposed inverse transformation matrix.
   *
   * @param n The normal to transform.
   * @return The transformed normal.
   */
  def *( n : Normal3 ) = (i.transposed * n.asVector).normalized.asNormal

}

/**
 * The companion object is the starting point to create a transformation.
 *
 * {{{
 *   val t = Transform.translate( 0, 2, 0 ).scale( 1, 2, 1 ).rotateX( 2.1 )
 * }}}
 *
 * @author <NAME>
 */
object Transform {

  /**
   * This function creates a transformation that translates an object by a given x, y, and z value.
   *
   * @param x The x value for the translation.
   * @param y The y value for the translation.
   * @param z The z value for the translation.
   * @return A translate transformation with the given x, y, and z value.
   */
  def translate( x : Double, y : Double, z : Double ) = new Transform(
    Mat4x4( 1.0, 0.0, 0.0, x,
            0.0, 1.0, 0.0, y,
            0.0, 0.0, 1.0, z,
            0.0, 0.0, 0.0, 1.0 ),
    Mat4x4( 1.0, 0.0, 0.0, -x,
            0.0, 1.0, 0.0, -y,
            0.0, 0.0, 1.0, -z,
            0.0, 0.0, 0.0, 1.0 )
  )

  /**
   * This function creates a transformation that translates an object by a given point.
   *
   * @param p The point to which the object should be translated.
   * @return A translate transformation with the given direction.
   */
  def translate( p : Point3 ) : Transform = Transform.translate( p.x, p.y, p.z )

  /**
   * This function creates a scale transformation with the given factors for the x, y, and z axis.
   *
   * @param x The scale factor for the x axis.
   * @param y The scale factor for the y axis.
   * @param z The scale factor for the z axis.
   * @return A scale transformation with the given factors.
   */
  def scale( x : Double, y : Double, z : Double ) = new Transform(
    Mat4x4( x,   0.0, 0.0, 0.0,
            0.0, y,   0.0, 0.0,
            0.0, 0.0, z,   0.0,
            0.0, 0.0, 0.0, 1.0 ),

    Mat4x4( 1.0/x, 0.0,   0.0,   0.0,
            0.0,   1.0/y, 0.0,   0.0,
            0.0,   0.0,   1.0/z, 0.0,
            0.0,   0.0,   0.0,   1.0 )
  )

  /**
   * This function creates a rotation around the x axis.
   *
   * @param angle The angle in radians.
   * @return A rotation around the x axis.
   */
  def rotateX( angle : Double ) = new Transform(
    Mat4x4( 1.0, 0.0,               0.0,                0.0,
            0.0, math.cos( angle ), -math.sin( angle ), 0.0,
            0.0, math.sin( angle ), math.cos( angle ),  0.0,
            0.0, 0.0,                0.0,               1.0 ),
    Mat4x4( 1.0, 0.0,                0.0,               0.0,
            0.0, math.cos( angle ),  math.sin( angle ), 0.0,
            0.0, -math.sin( angle ), math.cos( angle ), 0.0,
            0.0, 0.0,                0.0,               1.0 )
  )

  /**
   * This function creates a rotation around the y axis.
   *
   * @param angle The angle in radians.
   * @return A rotation around the y axis.
   */
  def rotateY( angle : Double ) = new Transform(
      Mat4x4( math.cos( angle ),  0.0, math.sin( angle ), 0.0,
              0.0,                1.0, 0.0,               0.0,
              -math.sin( angle ), 0.0, math.cos( angle ), 0.0,
              0.0,                0.0, 0.0,               1.0 ),
      Mat4x4( math.cos( angle ), 0.0, -math.sin( angle ), 0.0,
              0.0,               1.0, 0.0,                0.0,
              math.sin( angle ), 0.0, math.cos( angle ),  0.0,
              0.0,               0.0, 0.0,                1.0 )
  )

  /**
   * This function creates a rotation around the z axis.
   *
   * @param angle The angle in radians.
   * @return A rotation around the z axis.
   */
  def rotateZ( angle : Double ) = new Transform(
    Mat4x4( math.cos( angle ), -math.sin( angle ), 0.0, 0.0,
            math.sin( angle ), math.cos( angle ),  0.0, 0.0,
            0.0,               0.0,                1.0, 0.0,
            0.0,               0.0,                0.0, 1.0 ),
    Mat4x4( math.cos( angle ),  math.sin( angle ), 0.0, 0.0,
            -math.sin( angle ), math.cos( angle ), 0.0, 0.0,
            0.0,                0.0,               1.0, 0.0,
            0.0,                0.0,               0.0, 1.0 )
  )

}
{'fraction_non_alphanumeric': 0.11795158807891423, 'fraction_numerical': 0.040996222191129146, 'mean_word_length': 1.8211959739490824, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 12, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5209436', 'n_tokens_mistral': 4856, 'n_tokens_neox': 4564, 'n_words': 1757}