# Example 1 Interpolating Conformal Objects¶

In this example we will look at a few of the tools provided by the clifford package for (4,1) conformal geometric algebra (CGA) and see how we can use them in a practical setting to interpolate geometric primitives.

The first step in using the package for CGA is to generate and import the algebra:

[1]:

from clifford.g3c import *
blades

[1]:

{'e1': (1^e1),
'e2': (1^e2),
'e3': (1^e3),
'e4': (1^e4),
'e5': (1^e5),
'e12': (1^e12),
'e13': (1^e13),
'e14': (1^e14),
'e15': (1^e15),
'e23': (1^e23),
'e24': (1^e24),
'e25': (1^e25),
'e34': (1^e34),
'e35': (1^e35),
'e45': (1^e45),
'e123': (1^e123),
'e124': (1^e124),
'e125': (1^e125),
'e134': (1^e134),
'e135': (1^e135),
'e145': (1^e145),
'e234': (1^e234),
'e235': (1^e235),
'e245': (1^e245),
'e345': (1^e345),
'e1234': (1^e1234),
'e1235': (1^e1235),
'e1245': (1^e1245),
'e1345': (1^e1345),
'e2345': (1^e2345),
'e12345': (1^e12345)}


This creates an algebra with the required signature and imports the basis blades into the current workspace. We can check our metric by squaring our grade 1 multivectors.

[2]:

print('e1*e1 ', e1*e1)
print('e2*e2 ', e2*e2)
print('e3*e3 ', e3*e3)
print('e4*e4 ', e4*e4)
print('e5*e5 ', e5*e5)

e1*e1  1.0
e2*e2  1.0
e3*e3  1.0
e4*e4  1.0
e5*e5  -1.0


As expected this gives us 4 basis vectors that square to 1.0 and one that squares to -1.0, therefore confirming our metric is (4,1).

The up() function implements the mapping of vectors from standard 3D space to conformal space. We can use this to construct conformal objects to play around with.

For example a line at the origin:

[3]:

line_a = ( up(0)^up(e1+e2)^einf ).normal()
print(line_a)

(0.70711^e145) + (0.70711^e245)


The tools submodule of the clifford package contains a wide array of algorithms and tools that can be useful for manipulating objects in CGA. We will use these tools to generate rotors that rotate and translate objects:

[4]:

from clifford.tools.g3 import *
from clifford.tools.g3c import *
from numpy import pi

rotation_radians = pi/4
euc_vector_in_plane_m = e1
euc_vector_in_plane_n = e3

euc_translation = -5.2*e1 + 3*e2 - pi*e3

rotor_rotation = generate_rotation_rotor(rotation_radians, euc_vector_in_plane_m, euc_vector_in_plane_n)
rotor_translation = generate_translation_rotor(euc_translation)
print(rotor_rotation)
print(rotor_translation)

combined_rotor = (rotor_translation*rotor_rotation).normal()

line_b = (combined_rotor*line_a*~combined_rotor).normal()
print(line_b)

0.92388 - (0.38268^e13)
1.0 + (2.6^e14) + (2.6^e15) - (1.5^e24) - (1.5^e25) + (1.5708^e34) + (1.5708^e35)
-(5.17696^e124) - (5.17696^e125) - (1.0292^e134) - (1.0292^e135) + (0.5^e145) + (3.72144^e234) + (3.72144^e235) + (0.70711^e245) + (0.5^e345)


In the above snippet of code we have generated rotors for translation and rotation, then combined these, then applied the combined rotor to the original line that we made.

The clifford package also contains an easy interface to the GAOnline visualisation software. Using this we can visualise the two lines in space, to follow along open http://gaonline.azurewebsites.net/ and copy and paste the output of the next box into the input of the GAOnline viewer, replacing all of the default content. Then untick the ‘Draw axes and floor’ checkbox and press execute script.

[5]:

from clifford.tools.g3c.GAOnline import *
sc = GAScene()
sc.add_line(line_a,'rgb(255,0,0)')
sc.add_line(line_b,'rgb(0,255,0)')
print(sc)

DrawLine((0.70711^e145) + (0.70711^e245),rgb(255,0,0));
DrawLine(-(5.17696^e124) - (5.17696^e125) - (1.0292^e134) - (1.0292^e135) + (0.5^e145) + (3.72144^e234) + (3.72144^e235) + (0.70711^e245) + (0.5^e345),rgb(0,255,0));


We can also interpolate the objects using the tools in clifford and can visualise the result

[6]:

def interpolate_lines_linearly(L1,L2,n_steps=5,color_1=np.array([255,0,0]),color_2=np.array([0,255,0])):
alpha_list = np.linspace(0,1,num=n_steps)
intermediary_list = []
sc = GAScene()
for alpha in alpha_list:
intermediate_color = (alpha*color_1 + (1-alpha)*color_2)
intermediate_object = interp_objects_root(L1,L2,alpha)
intermediary_list.append(intermediate_object)
sc.add_line(intermediate_object, 'rgb'+str(tuple([int(c) for c in intermediate_color])))
return intermediary_list, sc

intermediary_list, finished_scene = interpolate_lines_linearly(line_a, line_b)
print(finished_scene)

DrawLine((0.70711^e145) + (0.70711^e245),rgb(0, 255, 0));
DrawLine(-(1.417^e124) - (1.417^e125) + (0.22008^e134) + (0.22008^e135) + (0.6741^e145) + (0.50775^e234) + (0.50775^e235) + (0.72736^e245) + (0.12858^e345),rgb(63, 191, 0));
DrawLine(-(2.92411^e124) - (2.92411^e125) + (0.13104^e134) + (0.13104^e135) + (0.62694^e145) + (1.36472^e234) + (1.36472^e235) + (0.73451^e245) + (0.25969^e345),rgb(127, 127, 0));
DrawLine(-(4.25101^e124) - (4.25101^e125) - (0.30926^e134) - (0.30926^e135) + (0.56758^e145) + (2.49276^e234) + (2.49276^e235) + (0.72736^e245) + (0.38574^e345),rgb(191, 63, 0));
DrawLine(-(5.17696^e124) - (5.17696^e125) - (1.0292^e134) - (1.0292^e135) + (0.5^e145) + (3.72144^e234) + (3.72144^e235) + (0.70711^e245) + (0.5^e345),rgb(255, 0, 0));


We can do the same for all the other geometric primitives as well

[7]:

def interpolate_objects_linearly(L1,L2,object_flag,n_steps=10,color_1=np.array([255,0,0]),color_2=np.array([0,255,0])):
alpha_list = np.linspace(0,1,num=n_steps)
intermediary_list = []
sc = GAScene()
for alpha in alpha_list:
intermediate_color = (alpha*color_1 + (1-alpha)*color_2)
intermediate_object = interp_objects_root(L1,L2,alpha)
intermediary_list.append(intermediate_object)
color_string = 'rgb'+str(tuple([int(c) for c in intermediate_color]))
if object_flag=='point_pairs':
sc.add_point_pair(intermediate_object, color_string)
if object_flag=='lines':
sc.add_line(intermediate_object, color_string)
if object_flag=='planes':
sc.add_plane(intermediate_object, color_string)
if object_flag=='circles':
sc.add_circle(intermediate_object, color_string)
if object_flag=='spheres':
sc.add_sphere(intermediate_object, color_string)
return intermediary_list, sc


Circles:

[8]:

circle_a = (up(0)^up(e1)^up(e2)).normal()
circle_b = (combined_rotor*circle_a*~combined_rotor).normal()
intermediary_list, finished_scene = interpolate_objects_linearly(circle_a, circle_b, 'circles')
print(finished_scene)

DrawCircle(-(0.70711^e124) + (0.70711^e125) + (0.70711^e145) - (0.70711^e245),rgb(0, 255, 0));
DrawCircle((0.13426^e123) + (0.25075^e124) + (0.34988^e125) - (0.48202^e134) - (0.71262^e135) - (0.07475^e145) + (0.80523^e234) + (1.13212^e235) + (0.01592^e245) + (0.20943^e345),rgb(28, 226, 0));
DrawCircle(-(0.06082^e123) + (0.42702^e124) + (0.4943^e125) - (0.79409^e134) - (0.89755^e135) - (0.15207^e145) + (1.3568^e234) + (1.56227^e235) + (0.05835^e245) + (0.37468^e345),rgb(56, 198, 0));
DrawCircle(-(0.19353^e123) + (0.58351^e124) + (0.63958^e125) - (1.07967^e134) - (1.11153^e135) - (0.21675^e145) + (1.85666^e234) + (2.00485^e235) + (0.0911^e245) + (0.5211^e345),rgb(85, 170, 0));
DrawCircle(-(0.31585^e123) + (0.749^e124) + (0.7999^e125) - (1.3856^e134) - (1.36009^e135) - (0.28379^e145) + (2.38999^e234) + (2.50006^e235) + (0.12414^e245) + (0.67588^e345),rgb(113, 141, 0));
DrawCircle(-(0.44836^e123) + (0.94356^e124) + (0.99256^e125) - (1.74971^e134) - (1.66852^e135) - (0.36205^e145) + (3.02334^e234) + (3.10311^e235) + (0.16249^e245) + (0.85874^e345),rgb(141, 113, 0));
DrawCircle(-(0.61333^e123) + (1.19809^e124) + (1.2481^e125) - (2.23415^e134) - (2.08957^e135) - (0.46456^e145) + (3.86479^e234) + (3.91692^e235) + (0.21327^e245) + (1.10089^e345),rgb(170, 85, 0));
DrawCircle(-(0.85834^e123) + (1.58453^e124) + (1.64011^e125) - (2.99269^e134) - (2.76061^e135) - (0.6222^e145) + (5.18091^e234) + (5.20328^e235) + (0.29418^e245) + (1.47879^e345),rgb(198, 56, 0));
DrawCircle(-(1.36938^e123) + (2.36461^e124) + (2.44041^e125) - (4.66392^e134) - (4.25943^e135) - (0.95663^e145) + (8.07753^e234) + (8.055^e235) + (0.48604^e245) + (2.30919^e345),rgb(226, 28, 0));
DrawCircle((2.05841^e123) - (27.74452^e124) - (26.74452^e125) - (7.20443^e134) - (7.20443^e135) + (3.5^e145) + (12.02964^e234) + (11.02964^e235) + (7.63449^e245) + (3.5^e345),rgb(255, 0, 0));


Point pairs

[9]:

point_pair_a = (up(e3)^up(e1+e2)).normal()
point_pair_b = (combined_rotor*point_pair_a*~combined_rotor).normal()
intermediary_list, finished_scene = interpolate_objects_linearly(point_pair_a, point_pair_b, 'point_pairs')
print(finished_scene)

DrawPointPair(-(0.66667^e13) - (0.66667^e15) - (0.66667^e23) - (0.66667^e25) + (0.33333^e34) + (1.0^e35) - (0.33333^e45),rgb(0, 255, 0));
DrawPointPair(-(0.19493^e12) - (0.01022^e13) - (0.51367^e14) - (0.70295^e15) - (0.22179^e23) - (0.78585^e24) - (1.10191^e25) + (0.54326^e34) + (0.74205^e35) - (0.06979^e45),rgb(28, 226, 0));
DrawPointPair(-(0.36411^e12) + (0.13206^e13) - (0.80495^e14) - (0.96131^e15) - (0.13394^e23) - (1.23688^e24) - (1.47807^e25) + (0.74471^e34) + (0.8897^e35) - (0.00203^e45),rgb(56, 198, 0));
DrawPointPair(-(0.51509^e12) + (0.23972^e13) - (1.07615^e14) - (1.22581^e15) - (0.08459^e23) - (1.65848^e24) - (1.86759^e25) + (0.94856^e34) + (1.07045^e35) + (0.04498^e45),rgb(85, 170, 0));
DrawPointPair(-(0.67284^e12) + (0.34357^e13) - (1.36569^e14) - (1.51881^e15) - (0.04726^e23) - (2.11122^e24) - (2.3047^e25) + (1.17399^e34) + (1.28354^e35) + (0.08774^e45),rgb(113, 141, 0));
DrawPointPair(-(0.85616^e12) + (0.45825^e13) - (1.70556^e14) - (1.86973^e15) - (0.01345^e23) - (2.64738^e24) - (2.83525^e25) + (1.44378^e34) + (1.54691^e35) + (0.13338^e45),rgb(141, 113, 0));
DrawPointPair(-(1.09335^e12) + (0.6008^e13) - (2.14581^e14) - (2.33024^e15) + (0.02261^e23) - (3.35189^e24) - (3.5434^e25) + (1.79752^e34) + (1.89894^e35) + (0.18957^e45),rgb(170, 85, 0));
DrawPointPair(-(1.44916^e12) + (0.80617^e13) - (2.79935^e14) - (3.02062^e15) + (0.07001^e23) - (4.42571^e24) - (4.63444^e25) + (2.3268^e34) + (2.43222^e35) + (0.27256^e45),rgb(198, 56, 0));
DrawPointPair(-(2.15719^e12) + (1.1893^e13) - (4.04791^e14) - (4.35255^e15) + (0.1631^e23) - (6.61729^e24) - (6.87784^e25) + (3.34219^e34) + (3.4628^e35) + (0.44558^e45),rgb(226, 28, 0));
DrawPointPair(-(6.7665^e12) + (2.29526^e13) - (7.83729^e14) - (8.7801^e15) + (1.62299^e23) - (23.98137^e24) - (24.64803^e25) + (6.25486^e34) + (6.25486^e35) + (2.56927^e45),rgb(255, 0, 0));


Planes

[10]:

plane_a = (up(0)^up(e1)^up(e2)^einf).normal()
plane_b = (combined_rotor*plane_a*~combined_rotor).normal()
intermediary_list, finished_scene = interpolate_objects_linearly(plane_a, plane_b, 'planes')
print(finished_scene)

DrawPlane(-(1.0^e1245),rgb(0, 255, 0));
DrawPlane((0.16662^e1234) + (0.16662^e1235) - (0.99672^e1245) + (0.08094^e2345),rgb(28, 226, 0));
DrawPlane((0.34118^e1234) + (0.34118^e1235) - (0.98617^e1245) + (0.16575^e2345),rgb(56, 198, 0));
DrawPlane((0.52021^e1234) + (0.52021^e1235) - (0.96754^e1245) + (0.25272^e2345),rgb(85, 170, 0));
DrawPlane((0.69945^e1234) + (0.69945^e1235) - (0.9405^e1245) + (0.3398^e2345),rgb(113, 141, 0));
DrawPlane((0.87432^e1234) + (0.87432^e1235) - (0.90531^e1245) + (0.42475^e2345),rgb(141, 113, 0));
DrawPlane((1.04042^e1234) + (1.04042^e1235) - (0.86286^e1245) + (0.50545^e2345),rgb(170, 85, 0));
DrawPlane((1.19413^e1234) + (1.19413^e1235) - (0.81453^e1245) + (0.58012^e2345),rgb(198, 56, 0));
DrawPlane((1.33292^e1234) + (1.33292^e1235) - (0.76202^e1245) + (0.64755^e2345),rgb(226, 28, 0));
DrawPlane((1.45551^e1234) + (1.45551^e1235) - (0.70711^e1245) + (0.70711^e2345),rgb(255, 0, 0));


Spheres

[11]:

sphere_a = (up(0)^up(e1)^up(e2)^up(e3)).normal()
sphere_b = (combined_rotor*sphere_a*~combined_rotor).normal()
intermediary_list, finished_scene = interpolate_objects_linearly(sphere_a, sphere_b, 'spheres')
print(finished_scene)

DrawSphere((0.57735^e1234) - (0.57735^e1235) - (0.57735^e1245) + (0.57735^e1345) - (0.57735^e2345),rgb(0, 255, 0));
DrawSphere((1.44969^e1234) + (0.96164^e1235) - (0.08489^e1245) + (0.40671^e1345) + (0.06507^e2345),rgb(28, 226, 0));
DrawSphere((1.93457^e1234) + (1.579^e1235) + (0.05409^e1245) + (0.41483^e1345) + (0.2726^e2345),rgb(56, 198, 0));
DrawSphere((2.45507^e1234) + (2.14474^e1235) + (0.14839^e1245) + (0.4655^e1345) + (0.43446^e2345),rgb(85, 170, 0));
DrawSphere((3.0454^e1234) + (2.75205^e1235) + (0.23592^e1245) + (0.53781^e1345) + (0.59648^e2345),rgb(113, 141, 0));
DrawSphere((3.77008^e1234) + (3.47673^e1235) + (0.33156^e1245) + (0.63559^e1345) + (0.78226^e2345),rgb(141, 113, 0));
DrawSphere((4.75498^e1234) + (4.44464^e1235) + (0.45194^e1245) + (0.77583^e1345) + (1.02409^e2345),rgb(170, 85, 0));
DrawSphere((6.32654^e1234) + (5.97097^e1235) + (0.63376^e1245) + (1.00745^e1345) + (1.39858^e2345),rgb(198, 56, 0));
DrawSphere((9.88937^e1234) + (9.40131^e1235) + (1.02902^e1245) + (1.54549^e1345) + (2.22876^e2345),rgb(226, 28, 0));
DrawSphere((26.25022^e1234) + (25.09552^e1235) + (2.8111^e1245) + (4.04145^e1345) + (6.00444^e2345),rgb(255, 0, 0));

[ ]: