În lista de probleme de mai jos, are vârfurile , , .
Determinați imaginea triunghiului printr-o scalare uniformă de factor de scală relativ la punctul .
Forma generală a matricei de scalare în jurul unui punct :
Concret, . Matricea transformării este:
Imaginea după scalare este:
Rezultă , , .
Determinați imaginea triunghiului printr-o forfecare de unghi , relativ la punctul , în direcția vectorului .
Forma generală a matricei de forfecare , de unghi , în direcția versorului , este
În particular, ,
Matricea transformării este:
Imaginea după forfecare este:
Rezultă , ,
Aplicați forfecarea de la problema precedentă pătratului , cu , , și .
Determinați imaginea triunghiului prin reflexia relativ la dreapta .
Forma generală a matricei de reflexie față de o dreaptă este:
În particular, pentru dreapta , matricea transformării este:
Imaginea după transformare este:
Obținem , ,
Determinați imaginea triunghiului prin rotația cu în jurul punctului C, urmată de reflexia relativ la dreapta .
Forma generală a matricei de rotație în jurul unui punct cu unghi :
Calculăm imaginea după rotația cu în jurul punctului :
Rezultă , , .
Forma generală a matricei de reflexie față de o dreaptă este
În cazul nostru, , , , de unde matricea de transformare este:
Imaginea finală a după transformări este
Scrieți un program în Python care să determine imaginea unui poliedru printr-o reflexie față de un plan dat. Considerați atât planul dat prin ecuația generală (datele de intrare vor fi coeficienții ecuației), cât și planul dat printr-un punct și vectorul normal. În cel de-al doilea caz, scrieți mai întâi ecuația generala, plecând de la punct și vectorul normal. Programul trebuie să conțină următorii pași:
Definim o clasă pentru matricea omogenă în 3D:
from __future__ import annotations
from math import sqrt, cos, sin
class Matrix4:
def __init__(self, *args):
self.items = [0]*16
for i in range(min(16, len(args))):
self.items[i]=args[i]
def __getitem__(self, pos):
i, j = pos
return self.items[4 * i + j]
def __setitem__(self, pos, value):
i, j=pos
self.items[4 * i + j]=value
def __str__(self):
s=""
for i in range(4):
s += str("".join(list(map(lambda x:f"{x:.3f}".rjust(8), self.items[4*i:4*i+4]))))+"\n"
return s
def _scalar_mul_(self, x:float) -> Matrix4: return Matrix4([x*i for i in self.items])
def _matrix4_mul_(self, m:Matrix4) -> Matrix4:
r = Matrix4()
for i in range(4):
for j in range(4):
for k in range(4):
r[i,j]+=self[i,k]*m[k,j]
return r
def _vec4_mul(self, v:tuple[float]):
r = [0]*4
v = (v[0], v[1], v[2], 1)
for i in range(4):
for j in range(4):
r[i] += self[i,j]*v[j]
return tuple(r)
def __mul__(self, other):
if isinstance(other, float) or isinstance(other, int): return self._scalar_mul_(other)
if isinstance(other, Matrix4): return self._matrix4_mul_(other)
if isinstance(other, tuple): return self._vec4_mul(other)
raise Exception("Unsupported operation: invalid multiplication type")
def __rmul__(self, other):
if isinstance(other, float) or isinstance(other, int): return self._scalar_mul_(other)
if isinstance(other, Matrix4): return other._matrix4_mul_(self)
raise Exception("Unsupported operation: invalid multiplication type")
def apply(self, pts): return [self * p for p in pts]
Definim principalele tipuri de matrici de transformare:
def TranslationMatrix(p):
x, y, z = p
return Matrix4(1,0,0,x, 0,1,0,y, 0,0,1,z, 0,0,0,1)
def CosSinRotXMatrix(c,s): return Matrix4(1,0,0,0, 0,c,-s,0, 0,s,c,0, 0,0,0,1)
def RotationXMatrix(thetaX): return CosSinRotXMatrix(cos(thetaX), sin(thetaX))
def CosSinRotYMatrix(c,s): return Matrix4(c,0,s,0, 0,1,0,0, -s,0,c,0, 0,0,0,1)
def RotationYMatrix(thetaY): return CosSinRotYMatrix(cos(thetaY), sin(thetaY))
def CosSinRotZMatrix(c,s): return Matrix4(c,-s,0,0, s,c,0,0, 0,0,1,0, 0,0,0,1)
def RotationZMatrix(thetaZ): return CosSinRotZMatrix(cos(thetaZ), sin(thetaZ))
def ReflectYZMatrix(): return Matrix4(-1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1)
Câteva metode ajutătoare:
"""
in p: planul (a,b,c,d)
out: (point, v), point = punctul de intersectie, v = versor Ox, Oy sau Oz
"""
def intersectAxis(p):
a,b,c,d = p
if a!=0: return ((-d/a,0,0), (1,0,0))
if b!=0: return ((0,-d/b,0), (0,1,0))
if c!=0: return ((0,0,-d/c), (0,0,1))
if d!=0: raise Exception("Runtime error: plan invalid d=0, d!=0")
return ((0, 0, 0), (1, 0, 0)) # a=b=c=0, d=0 triat la input
def neg(p):
x,y,z = p
return (-x,-y,-z)
Definirea planului (a se vedea LiviuStefan_NeacsuMiclea_235_Lab2Info.py pentru citirea planului de la tastatura, in ambele variante precizate de cerinta):
plane = (2,1,3,-10)
a,b,c,d = plane
Calcularea matricilor de transformare, conform pașilor precizați:
transforms = []
inv_transforms = []
print("Calculam intersectia cu una dintre axe")
i_point, i_axis = intersectAxis(plane)
print(f"Planul intersecteaza axa data de versorul {i_axis} in punctul {i_point}")
print("Determinam matricea de translatie care face planul sa treaca prin origine:")
if d!=0:
translate_o = TranslationMatrix(neg(i_point))
print(translate_o)
transforms.append(translate_o)
inv_transforms.append(TranslationMatrix(i_point))
else:
print("Planul este deja in origine")
print("Determinam matricea de rotatie fata de o axa care face ca normala \n"
"la plan sa fie paralela cu un plan de coordonate:")
print(">> Rotatie in jurul axei Ox pentru a face normala || cu planul xOy aka perp. pe axa Oz")
if c!=0:
norm_x = sqrt(b**2+c**2)
cos_tx = b/norm_x
sin_tx = -c/norm_x
rot_x = CosSinRotXMatrix(cos_tx, sin_tx)
print(rot_x)
transforms.append(rot_x)
inv_transforms.append(CosSinRotXMatrix(cos_tx, -sin_tx))
else:
rot_x = RotationXMatrix(0)
print("Normala este deja paralela cu axa Oz")
print("Determinam matricea de rotatie fata de alta axa care face ca planul \n"
"sa coincida cu un plan de coordonate")
print(">> Rotatie in jurul axei Oz pentru a face planul || cu planul yOz")
new_a, new_b,_,_ = rot_x.apply([(a,b,c)])[0]
if new_b != 0:
norm_z = sqrt(new_a**2+new_b**2)
cos_tz = new_a/norm_z
sin_tz = -new_b/norm_z
rot_z = CosSinRotZMatrix(cos_tz, sin_tz)
print(rot_z)
transforms.append(rot_z)
inv_transforms.append(CosSinRotZMatrix(cos_tz, -sin_tz))
else:
print("Planul este deja paralel cu axa Oz")
print("Planul se transforma in planul yOz")
print("Matricea de reflexie fata de YZ:")
refl_yz = ReflectYZMatrix()
print(refl_yz)
transforms.append(refl_yz)
print("Matricile inverse transformarilor planului (in ordinea inversa mentionarii lor)")
for m in inv_transforms[::-1]:
print(str(m)+"\n")
transforms = (transforms+ inv_transforms[::-1])[::-1]
full_t = Matrix4(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1)
for t in transforms:
full_t *= t
print("Matricea transformarii compuse")
print(full_t)
print()
Testarea transformării pe un poliedru generat care are vârfurile pe sfera unitate:
def gen_sphere(p, r):
pts = []
x,y,z=p
for t in range(0, 4):
at = 6.28 * t/4
for p in range(0, 4):
ap = 3.14 * p/4
xx = x+r*cos(at)*cos(ap)
yy = y + r * cos(at) * sin(ap)
zz = z + r * sin(at)
pts.append((xx,yy,zz))
return pts
pts = gen_sphere((0, 0, 0), 1)
print("Matricea coordonatelor ale poliedrului initial")
for j in range(3):
for i in range(len(pts)):
print(f"{pts[i][j]:.2f}".rjust(5,' '), end=" ")
print("")
for i in range(len(pts)):
print(f"{1}".rjust(5, ' '), end=" ")
print("\n")
pts_t = full_t.apply(pts)
print("Matricea coordonatelor poliedrului transformat")
for j in range(3):
for i in range(len(pts_t)):
print(f"{pts_t[i][j]:.2f}".rjust(5,' '), end=" ")
print("")
for i in range(len(pts_t)):
print(f"{1}".rjust(5, ' '), end=" ")
print("\n")
Reprezentarea grafică a transformării:
import matplotlib.pyplot as plt
import numpy as np
def plot_axes(ax):
x, y, z = np.zeros((3, 1))
u, v, w = np.array([5, 0, 0])
ax.quiver(x, y, z, u, v, w, arrow_length_ratio=0.1, color='r')
u, v, w = np.array([0, 5, 0])
ax.quiver(x, y, z, u, v, w, arrow_length_ratio=0.1, color='g')
u, v, w = np.array([0, 0, 5])
ax.quiver(x, y, z, u, v, w, arrow_length_ratio=0.1, color='b')
def plot_points(ax, pts, m="o", c="r"):
for p in pts:
ax.scatter(p[0], p[1], p[2], marker=m, color=c)
def plot_surface(ax, pts):
x = np.array([p[0] for p in pts])
y = np.array([p[1] for p in pts])
z = np.array([p[2] for p in pts])
ax.scatter(x, y, z)
def plot_plane(fig, p):
a, b, c, d = p
if c != 0:
x = np.linspace(-5, 5, 10)
y = np.linspace(-5, 5, 10)
X, Y = np.meshgrid(x, y)
Z = (-d - a * X - b * Y) / c
elif b != 0:
x = np.linspace(-5, 5, 10)
z = np.linspace(-5, 5, 10)
X, Z = np.meshgrid(x, z)
Y = (-d - a * X) / b
elif a != 0:
y = np.linspace(-5, 5, 10)
z = np.linspace(-5, 5, 10)
Y, Z = np.meshgrid(y, z)
X = (-d - 0 * Y - 0 * Z) / a
else:
y = np.linspace(-5, 5, 10)
z = np.linspace(-5, 5, 10)
Y, Z = np.meshgrid(y, z)
X = (0 - 0 * Y - 0 * Z)
ax.plot_surface(X, Y, Z)
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
plot_plane(ax, plane)
plot_points(ax, pts, c="r")
plot_points(ax, pts_t, c="b")
plot_axes(ax)
ax.view_init(-10, -30)
plt.show()
Consideram curba Bézier cubică dată de punctele de control , , , .
- Determinați punctele de control ale curbei, privită ca o curbă de gradul 4.
- Reprezentați grafic pe același sistem de axe: curba, punctele de control și poligonul de control ale curbei privite ca o curbă de gradul 3, precum și punctele de control și poligonul de control ale curbei, privite ca o curbă de gradul 4.
1.Pentru curba Bézier de gradul dată de punctele de control , se poate construi curba identică de grad , dată de punctele de control , astfel:
În particular, pentru , , , , , găsim:
2.Reprezentare grafică:
Considerăm curba Bézier de gradul 3 de la problema precedentă.
- Divizați curba la valoarea a parametrului, determinând punctele de control și parametrizările pe intervalul pentru fiecare dintre cele două segmente.
- Reprezentați grafic pe același sistem de axe: cele doua segmente de curbă (cu culori diferite), punctele de control și poligonul de control pentru curba originală, precum și punctele de control și poligoanele de control pentru cele doua segmente obținute prin divizare.
1.Pentru curba Bézier dată de punctele de control și un interval , curba Bézier care descrie curba segmentată pe intervalul are punctele de control
Rescriem ecuațiile lui din teoremă particularizate pentru :
Efectuând calulele obținem:
2.Reprezentare grafică:
Definim o clasă pentru un punct în plan:
from future import __annotations__
class Point:
def __init__(self,tuplexy):
self.x=tuplexy[0]
self.y=tuplexy[1]
def __mul__(self, f:float):
return Point((self.x*f, self.y*f))
def __rmul__(self, f:float):
return Point((self.x*f, self.y*f))
def __add__(self, pt):
return Point((self.x+pt.x, self.y+pt.y))
def __str__(self):
return f"({self.x:.3f}, {self.y:.3f})"
Algoritmul lui de Boor:
def de_boor(d,t,tx):
n = 3
N = 2
r = 0
for i in range(len(t)-1):
if t[i] <= tx < t[i + 1]:
r = i
assert(n <= r)
assert (r < n + N)
dk = [Point((0,0))]*len(d)
a = [0]*len(d)
for i in range(r - n, r + 1): dk[i] = d[i]
for k in range(1,n+1):
ndk = [Point((0,0))] * len(d)
for i in range(r-n+k,r+1):
a[i] = (tx-t[i])/(t[n+1+i-k]-t[i])
ndk[i] = (1-a[i])*dk[i-1]+a[i]*dk[i]
dk = ndk
return dk[r]
Datele de intrare (pentru exemplificare):
d = list(map(Point, [(-1, 17), (1, 2), (3, 4), (5, 6), (7, -8)]))
t = [0, 0, 0, 0, 0.5, 1, 1, 1, 1]
Lista punctelor în care vrem să calculăm valoarea curbei:
txs = [0, 0.2, 0.5, 0.7, 0.9]
print("Punctele de control:")
print(", ".join(list(map(str,d))))
print("Nodurile:")
print(t)
Calculul valorilor :
print("Valorile curbei in punctele date:")
for tx in txs:
p = de_boor(d,t,tx)
print(f"r({str(tx).rjust(3)}) = {p}")
Reprezentarea grafică:
pts = [de_boor(d, t, tx * 0.01) for tx in range(int(100*min(t)), int(100*max(t)))]
xs = [p.x for p in pts]
ys = [p.y for p in pts]
plt.plot(xs, ys)
pts = [de_boor(d, t, tx) for tx in txs]
xs = [p.x for p in pts]
ys = [p.y for p in pts]
plt.scatter(xs,ys)
for i in range(len(txs)):
plt.annotate(f"t={txs[i]}", (xs[i],ys[i]))
plt.show()
Scrieți un program Python care să determine un punct de pe o suprafață Bézier triunghiulară, folosind algoritmul lui de Casteljau. Datele de intrare vor fi:
- gradul al suprafeței;
- puncte din spațiu;
- un triplet de numere reale cu suma ,
iar rezultatul trebuie să fie .
def iterate_idices(n):
for i in range(n+1):
for j in range(n+1-i):
k = n-i-j
yield (i,j,k)
def ix_add(i,e):
i0,i1,i2 = i
e0,e1,e2 = e
return (i0+e0, i1+e1, i2+e2)
e1 = (1,0,0)
e2 = (0,1,0)
e3 = (0,0,1)
def pt_scale(u, p):
x,y,z = p
return (u*x,u*y,u*z)
def pt_add(*args):
rx,ry,rz = 0,0,0
for (x,y,z) in args:
rx += x
ry += y
rz += z
return (rx,ry,rz)
def deCasteljau(n, pts, u,v,w, save_intermediates = False):
b = pts.copy()
points = {}
for r in range(1, n+1):
new_b = {}
for ix in iterate_idices(n-r):
new_b[ix]=pt_add(
pt_scale(u, b[ix_add(ix, e1)]),
pt_scale(v, b[ix_add(ix, e2)]),
pt_scale(w, b[ix_add(ix, e3)]),
)
if(save_intermediates): points = {**points, **b}
b = new_b
if(save_intermediates): points = {**points, **b}
return b[(0,0,0)], points
n = 3
# punctele de control
in_pts = [
(0, 3, 16), (1, 2, 9), (2, 1, 9), (3, 0, 16),
(0, 2, 4), (1, 1, 5), (2, 0, 4),
(0, 1, 1), (1, 0, 2),
(0, 0, 5)
]
# (u, v, w)
coords = [
(0.4, 0.2, 0.4),
(0.5, 0.5, 0.0),
(0.0, 0.8, 0.2),
(0.7, 0.0, 0.3)
]
pts = {}
k = 0
for ix in iterate_idices(n):
pts[ix] = in_pts[k]
k += 1
print(f"n = {n}")
for k in pts.keys():
print(f"b_{k[0]}{k[1]}{k[2]} = {pts[k]}")
for u0,v0,w0 in coords:
print(f"u0,v0,w0 = {u0}, {v0}, {w0}")
result, _ = deCasteljau(n, pts, u0, v0, w0)
print(f"r{u0,v0,w0} = {tuple(map(lambda x:round(x,3), result))}")
wireframe = {} # se calculeaza niste puncte pe suprafata pentru plot
acc = 20
for i in range(acc + 1):
for j in range(acc - i + 1):
p, _ = deCasteljau(n, pts, i / acc, j / acc, (acc - i - j) / acc)
wireframe[(i, j)] = p
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
xs = [_[0] for _ in wireframe.values()]
ys = [_[1] for _ in wireframe.values()]
zs = [_[2] for _ in wireframe.values()]
surf = ax.plot_trisurf(xs, ys, zs, linewidth=0, zorder=10)
surf.set_facecolor((0,0,1,0.3))
fig.colorbar(surf)
for ix in pts:
x,y,z = pts[ix]
ax.scatter(x,y,z,color='b')
ax.text(x,y,z,f"b{ix[0]}{ix[1]}{ix[2]}",size=10, zorder=1,color='k')
for u0, v0, w0 in coords:
result, _ = deCasteljau(n, pts, u0, v0, w0)
x, y, z = result
ax.scatter(x, y, z, color='r')
ax.text(x, y, z, f"r({u0},{v0},{w0})", size=10, zorder=1, color='k')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
ax.view_init(-15,45)
plt.show()