"""Example: Lines in a Projective Plane.

Draw N random lines in the projective plane and visualize them as great
circles on the sphere, as well as straight lines in an affine plane.
"""

#############################################
# Setup
#############################################

# [setup-1]
# Import necessary libraries
import bpy
import numpy as np

import ddg
from ddg.blender.scene import clear

# [setup-1]

# [setup-2]
# Clear the existing objects in the Blender scene
clear()
# [setup-2]


#############################################
# Blender Collections
#############################################

# [blender-collections]
# Create Blender collections for organizing objects
rendering_coll = ddg.blender.collection.collection("light and camera")
gc_coll = ddg.blender.collection.collection("great_circles")
plane_coll = ddg.blender.collection.collection("plane_intersections")
# [blender-collections]


#############################################
# Geometric Calculations
#############################################

# [geometric-calculations-1]
# Generate N random normals and calculate corresponding planes
N = 4
seed = 59232
normals = [ddg.math.random.random_point_on_sphere(2, i * seed) for i in range(N)]
planes = [
    ddg.geometry.hyperplane_from_normal(normal, point=(0, 0, 0)) for normal in normals
]
# [geometric-calculations-1]

# [geometric-calculations-2]
# Create a unit sphere (S2) and a projective plane
s2 = ddg.geometry.Quadric(np.diag([1, 1, 1, -1]))
bobj_s2 = ddg.blender.convert(s2, "s2")

projective_plane = ddg.geometry.hyperplane_from_normal((-1, 0, 0), point=(1.5, 0, 0))
# [geometric-calculations-2]


#############################################
# Geometric Intersections
#############################################

# [geometric-intersections-1]
# Calculate intersections of the random planes with S2 and the projective plane
for i, plane in enumerate(planes):
    circ_on_sphere = ddg.geometry.meet(plane, s2)
    meet_plane = ddg.geometry.meet(plane, projective_plane)

    # Orthonormalize the intersection plane
    meet_plane = ddg.geometry.Subspace.orthonormalize(meet_plane)

    if circ_on_sphere.dimension != -1:
        # Create Blender objects for circles on the sphere
        bobj_circ_on_sphere = ddg.blender.convert(
            circ_on_sphere,
            f"spheric circle {i}",
            collection=gc_coll,
        )
        bobj_circ_on_sphere.data.bevel_depth = 0.005

    if meet_plane.dimension != -1:
        # Create Blender objects for plane intersections
        bobj_meet_plane = ddg.blender.convert(
            meet_plane,
            f"plane intersection {i}",
            collection=plane_coll,
        )
        bobj_meet_plane.data.bevel_depth = 0.005
# [geometric-intersections-1]
# [geometric-intersections-2]
bobjprojective = ddg.blender.convert(projective_plane, "Projective plane")
# [geometric-intersections-2]


#############################################
# Add Camera and Light
#############################################

# [add-camera-and-light]
# Add a point light and a camera to the scene
light = ddg.blender.light.light(type_="POINT", collection=rendering_coll)
light.data.energy = 500
light.data.shadow_soft_size = 0
camera = ddg.blender.camera.camera(location=(-6, 0, 0), collection=rendering_coll)

# Position the camera to look at the projective plane
ddg.blender.camera.look_at_point(camera, (1.5, 0, 0))
bpy.context.scene.camera = camera
# [add-camera-and-light]


#############################################
# Add Material
#############################################

# [add-materials-1]
# Add a material to the projective plane
project_mat = ddg.blender.material.material(color=(0.8, 0.56, 0.535))
ddg.blender.material.set_material(bobjprojective, project_mat)
# [add-materials-1]

# [add-materials-2]
# Create a material for the sphere (S2) with transparency
s2material = bpy.data.materials.new("s2 material")
s2material.use_nodes = True
s2material.node_tree.nodes.remove(s2material.node_tree.nodes.get("Principled BSDF"))
transparent = s2material.node_tree.nodes.new("ShaderNodeBsdfTransparent")
transparent.inputs["Color"].default_value = (0.5, 0.5, 0.5, 1.0)
s2material.node_tree.links.new(
    transparent.outputs["BSDF"],
    s2material.node_tree.nodes["Material Output"].inputs["Surface"],
)
ddg.blender.material.set_material(bobj_s2, s2material)
# [add-materials-2]


#
# Render settings
#

bpy.context.scene.render.engine = "CYCLES"

# rather low number of samples, but good enough for snapshot tests
bpy.context.scene.cycles.samples = 16
