<commit_before># This file is part of NIT (http://www.nitlanguage.org).
#
# Copyright 2014 <NAME> <<EMAIL>>
#
# 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.

# Interfaces and classes to represent basic geometry needs.
module points_and_lines is serialize

import serialization

# Abstract 2d point, strongly linked to its implementation `Point`
interface IPoint[N: Numeric]

	# Horizontal coordinate
	fun x: N is abstract

	# Vertical coordinate
	fun y: N is abstract

	redef fun to_s do return "({x}, {y})"

	# Distance with `other`
	#
	# ~~~
	# var p0 = new Point[Float](0.0, 0.0)
	# var p1 = new Point[Float](2.0, 3.0)
	# assert p0.dist(p1).is_approx(3.6, 0.01)
	# ~~~
	#
	# TODO 3D implementation.
	fun dist(other: Point[Numeric]): N
	do
		return x.value_of(dist2(other).to_f.sqrt)
	end

	# Square of the distance with `other`
	#
	# May be used as an approximation to compare distance between two points.
	#
	# ~~~
	# var p0 = new Point[Float](0.0, 0.0)
	# var p1 = new Point[Float](2.0, 3.0)
	# assert p0.dist2(p1) == 13.0
	# ~~~
	#
	# TODO 3D implementation.
	fun dist2(other: Point[Numeric]): N
	do
		var dx = other.x.sub(x)
		var dy = other.y.sub(y)
		var s = (dx.mul(dx)).add(dy.mul(dy))
		return x.value_of(s)
	end

	# Linear interpolation between `self` and `other` at `p` out of `1.0`
	#
	# ~~~
	# var p0 = new Point[Float](0.0, 0.0)
	# var p1 = new Point[Float](2.0, 3.0)
	# assert p0.lerp(p1, 0.0) == p0
	# assert p0.lerp(p1, 1.0) == p1
	# assert p0.lerp(p1, 0.5) == new Point[Float](1.0, 1.5)
	# ~~~
	#
	# TODO 3D implementation.
	fun lerp(other: Point[Numeric], p: Float): Point[N]
	do
		var xx = x.to_f + (other.x.to_f - x.to_f).to_f * p
		var yy = y.to_f + (other.y.to_f - y.to_f).to_f * p
		return new Point[N](x.value_of(xx), y.value_of(yy))
	end

	redef fun ==(o) do return o isa IPoint[Numeric] and o.x == x and o.y == y
end

# 2D point with `x` and `z`
class Point[N: Numeric]
	super IPoint[N]

	redef var x: N = 0.0 is writable, optional
	redef var y: N = 0.0 is writable, optional
end

# Abstract 3d point, strongly linked to its implementation `Point3d`
interface IPoint3d[N: Numeric]
	super IPoint[N]

	# Depth coordinate
	fun z: N is abstract

	redef fun to_s do return "({x}, {y}, {z})"
end

# 3D point with `x`, `y` and `z`
class Point3d[N: Numeric]
	super IPoint3d[N]
	super Point[N]

	redef var z: N = 0.0 is writable, optional
end

# Abstract 2D line segment between two ordered points
interface ILine[N: Numeric]
	# The type of points that ends the segment<commit_msg>geometry: implement `Point::dist` for 3D points<commit_after># This file is part of NIT (http://www.nitlanguage.org).
#
# Copyright 2014 <NAME> <<EMAIL>>
#
# 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.

# Interfaces and classes to represent basic geometry needs.
module points_and_lines is serialize

import serialization

# Abstract 2d point, strongly linked to its implementation `Point`
interface IPoint[N: Numeric]

	# Horizontal coordinate
	fun x: N is abstract

	# Vertical coordinate
	fun y: N is abstract

	redef fun to_s do return "({x}, {y})"

	# Distance with `other`
	#
	# ~~~
	# var p0 = new Point[Float](0.0, 0.0)
	# var p1 = new Point[Float](2.0, 3.0)
	# assert p0.dist(p1).is_approx(3.6, 0.01)
	# ~~~
	#
	# If `self` or `other` are in 3D, the distance takes into account the 3 axes.
	# For a 2D point, the Z coordinate is considered to be 0.
	#
	# ~~~
	# var p2 = new Point3d[Float](0.0, 0.0, 0.0)
	# var p3 = new Point3d[Float](2.0, 3.0, 4.0)
	# var p4 = new Point[Float](2.0, 3.0)
	# assert p2.dist(p3).is_approx(5.385, 0.01)
	# assert p2.dist(p4).is_approx(3.606, 0.01)
	# ~~~
	fun dist(other: Point[Numeric]): N
	do
		return x.value_of(dist2(other).to_f.sqrt)
	end

	# Square of the distance with `other`
	#
	# May be used as an approximation to compare distance between two points.
	#
	# ~~~
	# var p0 = new Point[Float](0.0, 0.0)
	# var p1 = new Point[Float](2.0, 3.0)
	# assert p0.dist2(p1) == 13.0
	# ~~~
	#
	# If `self` or `other` are in 3D, the distance takes into account the 3 axes.
	# For a 2D point, the Z coordinate is considered to be 0.
	#
	# ~~~
	# var p2 = new Point3d[Float](0.0, 0.0, 0.0)
	# var p3 = new Point3d[Float](2.0, 3.0, 4.0)
	# var p4 = new Point[Float](2.0, 3.0)
	# assert p2.dist2(p3).is_approx(29.0, 0.01)
	# assert p2.dist2(p4).is_approx(13.0, 0.01)
	# assert p4.dist2(p2).is_approx(13.0, 0.01)
	# ~~~
	fun dist2(other: Point[Numeric]): N
	do return x.value_of(other.dist2_with_2d(self))

	private fun dist2_with_2d(other: IPoint[Numeric]): Numeric
	do return dist2_xy(other)

	private fun dist2_with_3d(other: IPoint3d[Numeric]): Numeric
	do return dist2_xy(other).add(other.z.mul(other.z))

	# Square of the distance with `other` on the X and Y axes
	private fun dist2_xy(other: IPoint[N]): N
	do
		var dx = other.x.sub(x)
		var dy = other.y.sub(y)
		var s = (dx.mul(dx)).add(dy.mul(dy))
		return x.value_of(s)
	end

	# Linear interpolation between `self` and `other` at `p` out of `1.0`
	#
	# ~~~
	# var p0 = new Point[Float](0.0, 0.0)
	# var p1 = new Point[Float](2.0, 3.0)
	# assert p0.lerp(p1, 0.0) == p0
	# assert p0.lerp(p1, 1.0) == p1
	# assert p0.lerp(p1, 0.5) == new Point[Float](1.0, 1.5)
	# ~~~
	#
	# TODO 3D implementation.
	fun lerp(other: Point[Numeric], p: Float): Point[N]
	do
		var xx = x.to_f + (other.x.to_f - x.to_f).to_f * p
		var yy = y.to_f + (other.y.to_f - y.to_f).to_f * p
		return new Point[N](x.value_of(xx), y.value_of(yy))
	end

	redef fun ==(o) do return o isa IPoint[Numeric] and o.x == x and o.y == y
end

# 2D point with `x` and `z`
class Point[N: Numeric]
	super IPoint[N]

	redef var x: N = 0.0 is writable, optional
	redef var y: N = 0.0 is writable, optional
end

# Abstract 3d point, strongly linked to its implementation `Point3d`
interface IPoint3d[N: Numeric]
	super IPoint[N]

	# Depth coordinate
	fun z: N is abstract

	redef fun to_s do return "({x}, {y}, {z})"

	redef fun dist2(other)
	do return x.value_of(other.dist2_with_3d(self))

	redef fun dist2_with_2d(other)
	do return dist2_xy(other).add(z.mul(z))

	redef fun dist2_with_3d(other)
	do
		var dz = other.z.sub(z)
		var s = dist2_xy(other).add(dz.mul(dz))
		return x.value_of(s)
	end
end

# 3D point with `x`, `y` and `z`
class Point3d[N: Numeric]
	super IPoint3d[N]
	super Point[N]

	redef var z: N = 0.0 is writable, optional
end

# Abstract 2D line segment between two ordered points
interface ILine[N: Numeric]
	# The type of points that ends the segment
{'fraction_non_alphanumeric': 0.1382892606583918, 'fraction_numerical': 0.03980032379924447, 'mean_word_length': 3.6389236545682104, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, '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': '5543440', 'n_tokens_mistral': 3079, 'n_tokens_neox': 2915, 'n_words': 946}