Module:CineMol/geometry/testcases

From Wikipedia, the free encyclopedia
Jump to navigation Jump to search
-- This is a port of CineMol to lua
-- CineMol https://github.com/moltools/CineMol was written by David Meijer, Marnix H. Medema & Justin J. J. van der Hooft and is MIT licensed
-- Please consider any edits I make to this page also dual licensed MIT & CC-BY-SA 4.0


local p = require('Module:UnitTests')
local g = require('Module:CineMol/geometry')
for k,v in pairs(g) do
	_G[k] = v
end

require( 'strict' )

function p:assertAlmostEquals(actual, expected, name)
	name = name == nil and "AlmostEquals " .. expected or name
	self:equals( name, math.abs( actual - expected ) < 0.001, true )
end

-- ============
-- Vector3D
-- ============
function p:test_vector3d_creation()
	local vector = Vector3D(1, 2, 3)
	self:equals("vector x", vector.x, 1 )
	self:equals("vector y", vector.y, 2 )
	self:equals("vector z", vector.z, 3 )
end

function p:test_random_vector3d()
        local vector = Vector3D_create_random()

        -- All values should be between 0 and -1. 
        self:equals("vector x", 0 <= vector.x and vector.x <= 1, true)
        self:equals("vector y", 0 <= vector.y and vector.y <= 1, true)
        self:equals("vector z", 0 <= vector.z and vector.z <= 1, true)
end

function p:test_vector3d_length()
        local vector = Vector3D(1, 2, 3)
        self:equals("length", math.abs(vector:length() - 3.742) <0.001, true)
end


-- END Vector3D

function p:test_GramSchmidt()
	local vector_n = Vector3D(1,2,3)
	local v, w = gram_schmidt(vector_n)
	self:equals( "n not null", type(vector_n), "table")
	self:equals( "v not null", type(v), "table")
	self:equals( "w not null", type(w), "table")
	self:equals( "w is Vector3D", w._TYPE, "Vector3D")
	self:assertAlmostEquals( vector_n:dot(w), 0 )
	self:assertAlmostEquals( v:dot(w), 0 )
end


function p:test_same_side_of_plane_same_side()
        local plane_point = Point3D(0, 0, 0)
        local plane_normal = Vector3D(0, 0, 1)
        local plane = Plane3D(plane_point, plane_normal)
        local point1 = Point3D(1, 1, 1)
        local point2 = Point3D(-1, -1, 1)
        local result = same_side_of_plane(plane, point1, point2)
        self:equals("same_side", result, true )
end

function p:test_same_side_of_plane_opposite_side()
        local plane_point = Point3D(0, 0, 0)
        local plane_normal = Vector3D(0, 0, 1)
        local plane = Plane3D(plane_point, plane_normal)
        local point1 = Point3D(1, 1, 1)
        local point2 = Point3D(-1, -1, -1)
        local result = same_side_of_plane(plane, point1, point2)
        self:equals("same_side", result, false )
end

function p:test_distance_to_line()
        local point = Point3D(1, 1, 1)
        local line = Line3D(Point3D(0, 0, 0), Point3D(2, 2, 2))
        local result = distance_to_line(line, point)
        self:assertAlmostEquals(result, 0.0, "is zero")

		point = Point3D(1, 0, 0)
		line = Line3D(Point3D(-1, -1, 0), Point3D(2, 2, 0))
		result = distance_to_line(line, point)
		self:assertAlmostEquals(result, 0.707, "not zero")
end

function p:test_three_perpendicular_lines()
        local line = Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0))
        local width = 1
        local result = get_perpendicular_lines(line, width, 3)

        -- Distances between the starts and the ends of the three new lines should
        -- all be equal to the given width.
        self:assertAlmostEquals(result[1].start:calculate_distance(result[2].start), width, "1.start 2.start")
        self:assertAlmostEquals(result[1].endp:calculate_distance(result[2].endp), width, "1.end 2.end")
        self:assertAlmostEquals(result[2].start:calculate_distance(result[3].start), width, "2.start 3.start")
        self:assertAlmostEquals(result[2].endp:calculate_distance(result[3].endp), width, "2.end 3.end")
        self:assertAlmostEquals(
            result[1].start:calculate_distance(result[3].start), width * 2, "start1 start3"
        )
        self:assertAlmostEquals(result[1].endp:calculate_distance(result[3].endp), width * 2, "end.1 end.3")

        -- Distances between the starts and the ends of the three new lines and the
        -- original line should be equal to the given width for the first and third line ...
        self:assertAlmostEquals(result[1].start:calculate_distance(line.start), width, "1.start line.start")
        self:assertAlmostEquals(result[1].endp:calculate_distance(line.endp), width, "1.end line.end")
        self:assertAlmostEquals(result[3].start:calculate_distance(line.start), width, "3.start line.start")
        self:assertAlmostEquals(result[3].endp:calculate_distance(line.endp), width, "3.end line.end")

        -- ... and zero for the second line.
        self:assertAlmostEquals(result[2].start:calculate_distance(line.start), 0, "2.start line.start")
        self:assertAlmostEquals(result[2].endp:calculate_distance(line.endp), 0, "2.end line.end")

end

function p:test_GetPointsOnLine3D()
        local line = Line3D(Point3D(0, 0, 0), Point3D(1, 1, 1)) 
        local result = get_points_on_line_3d(line, 10)

		self:equals( "number of lines returned", #result, 11)
		self:assertAlmostEquals(result[1]:calculate_distance(line.start), 0, "distance start")
		self:assertAlmostEquals(result[11]:calculate_distance(line.endp), 0, "distance end")
		for i = 1, #result do
			self:assertAlmostEquals(distance_to_line(line, result[i]), 0, "distance to line " .. i )
		end
end

function p:test_GetPointsOnCircumferenceCircle3D()
	local circle = Circle3D(Point3D(0, 0, 0), 1, Vector3D(0, 0, 1))
    local result = get_points_on_circumference_circle_3d(circle, 10)
    self:equals("number of points", #result, 10)

	for i, point in ipairs( result ) do
		self:assertAlmostEquals( point:calculate_distance(circle.center), circle.radius, "dist to radius " .. i )
	end
end


function p:test_GetPointsOnSurfaceCircle3D()
    local circle = Circle3D(Point3D(0, 0, 0), 1, Vector3D(0, 0, 1))
    local num_radii = 3
    local num_points = 10
    local result = get_points_on_surface_circle_3d(circle, num_radii, num_points)
    self:equals("number of pts", #result, num_radii * num_points)

	for i, point in ipairs(result) do
		self:equals( "point is inside circle " .. i, point:calculate_distance(circle.center) <= circle.radius, true )
		self:assertAlmostEquals(point.z, 0, "z is 0 - " .. i )
	end
end

-- TestGetPointsOnSurfaceCap

function p:test_GetPointsOnSurfaceCap()
        local circle = Circle3D(Point3D(0, 0, 0), 1, Vector3D(0, 0, 1))
        local cap_type = CylinderCapType.FLAT
        local result = get_points_on_surface_cap(
            cap_type, circle.center, circle.radius, circle.normal, Point3D(0, 0, -1), 10
        )
        for i,point in ipairs(result) do
            self:equals( "point inside circle FLAT_CAP " .. i, math.floor(point:calculate_distance(circle.center)*1e5)/1e5 <= circle.radius, true)
            self:assertAlmostEquals(point.z, 0, "FLAT CAP z=0 " .. i)
		end

        result = get_points_on_surface_cap(
            CylinderCapType.ROUND, circle.center, circle.radius, circle.normal, Point3D(0, 0, -1), 10
        )
        for i,point in ipairs(result) do
            self:equals( "point inside circle FLAT_CAP " .. i, math.floor(point:calculate_distance(circle.center)*1e5)/1e5 <= circle.radius, true)
            self:equals("ROUND CAP z=0 " .. i, point.z >= 0, true)
		end

        result = get_points_on_surface_cap(
            CylinderCapType.NO_CAP, circle.center, circle.radius, circle.normal, Point3D(0, 0, -1), 10
        )
		self:equals( 'NO_CAP numb points', #result, 0 )
		
end

function p:test_points_on_surface_cylinder_returns_points_on_surface()
        local start = Point3D(0, 0, 0)
        local endp = Point3D(0, 0, 1)
        local line = Line3D(start, endp)
        local radius = 1
        local cylinder = Cylinder(start, endp, radius, CylinderCapType.NO_CAP)
        local result = get_points_on_surface_cylinder(cylinder, 10)
        for i,point in ipairs(result) do
            self:assertAlmostEquals(distance_to_line(line, point), radius, 'point in radius ' .. i)
		end

end

function p:test_point_is_inside_sphere_inside()
        local sphere = Sphere(Point3D(0, 0, 0), 1)
        local point = Point3D(0, 0, 0.5)
        local result = point_is_inside_sphere(sphere, point)
        self:equals( "inside sphere", result, true)

        point = Point3D(0, 0, 1.5)
        result = point_is_inside_sphere(sphere, point)
        self:equals( "outside sphere", result, false)
end

function p:test_point_is_inside_cylinder()
        local cylinder = Cylinder(Point3D(0, 0, 0), Point3D(0, 0, 1), 1, CylinderCapType.NO_CAP)
        local point = Point3D(0, 0, 0.5)
        local result = point_is_inside_cylinder(cylinder, point)
        self:equals( "inside", result, true)

		point = Point3D(0, 0, 1.5)
        result = point_is_inside_cylinder(cylinder, point)
        self:equals( "outside", result, false)
end


function p:test_sphere_intersects_with_sphere()
        local sphere1 = Sphere(Point3D(0, 0, 0), 1)
        local sphere2 = Sphere(Point3D(1, 0, 0), 1)
        local result = sphere_intersects_with_sphere(sphere1, sphere2)
        self:equals( "intersects", result, true )

        sphere2 = Sphere(Point3D(3, 0, 0), 1)
        result = sphere_intersects_with_sphere(sphere1, sphere2)
        self:equals( "not intersects", result, false )
end

function p:test_sphere_intersects_with_cylinder()
        local sphere = Sphere(Point3D(0, 0, 0), 1)
        local cylinder = Cylinder(Point3D(0, 0, 0), Point3D(0, 0, 1), 1, CylinderCapType.NO_CAP)
        local result = sphere_intersects_with_cylinder(sphere, cylinder)
        self:equals( "intersects", result, true )

		cylinder = Cylinder(Point3D(0, 0, 3), Point3D(0, 0, 4), 1, CylinderCapType.NO_CAP)
        result = sphere_intersects_with_cylinder(sphere, cylinder)
        self:equals( "not intersects", result, false )
end

function p:test_cylinder_intersects_with_cylinder()

        local cylinder1 = Cylinder(Point3D(0, 0, 0), Point3D(0, 0, 1), 1, CylinderCapType.NO_CAP)
        local cylinder2 = Cylinder(Point3D(1, 0, 0), Point3D(1, 0, 1), 1, CylinderCapType.NO_CAP)
        local result = cylinder_intersects_with_cylinder(cylinder1, cylinder2)
        self:equals( "intersects", result, true )

        cylinder2 = Cylinder(Point3D(3, 0, 0), Point3D(3, 0, 1), 1, CylinderCapType.NO_CAP)
        result = cylinder_intersects_with_cylinder(cylinder1, cylinder2)
        self:equals( "not intersects", result, false )
end

function p:test_points_on_surface_sphere_returns_points_on_surface()
	local sphere = Sphere(Point3D(0,0,0), 1)
	local result = get_points_on_surface_sphere(sphere, 10, 10)
	for i,point in ipairs( result ) do
		self:assertAlmostEquals( point:calculate_distance(sphere.center), sphere.radius, "point " .. i )
	end
end

return p