Demo 8: Parameterfremstillinger#

Demo af Steeven H. Spangsdorf.

from sympy import *
from dtumathtools import *

init_printing()

Når man skal udvikle parameterfremstillinger - også blot kaldet parametriseringer - af geometriske områder, får man ofte geometrien givet som en punktmængde. Derfra er det så op til os selv at finde en god fremgangsmåde til at komme i gang med parametriseringen. Glem ikke, at en parameterfremstilling blot er en anvendelse af vektorfunktioner - i denne sammenhæng kalder vi vektorfunktionens variable for parametre.

Denne demo viser eksempler på, hvordan forskellige typer geometriske områder kan parametriseres.

Rette linjer#

Vi får givet linjestykket \(L\) i \(\Bbb R^2\) ved punktmængden:

\[\begin{equation*} L = \Bigl\{(x,y) \in \mathbb{R}^2\ |\ 2\leq x \leq 4 \, \wedge \, y = 2x - 4\Bigr\}. \end{equation*}\]

Dette udgør en ret linje fra \((2,0)\) til \((4,4)\) (vær velkommen til at kontrollere). Lad os parametrisere denne linje.

En linje er fuldstændigt defineret af et punkt derpå plus en retningsvektor (en vektor langs linjen) gange en parameter. En retningsvektor findes nemt som \((4,4)-(2,0)=(2,4)\), og vores parameterfremstilling (også kaldet en parameterkurve) \(\boldsymbol r_L\) bliver:

\[\begin{equation*} \boldsymbol r_L(u)=\begin{bmatrix} x \\ y \end{bmatrix} = \begin{bmatrix} 2 \\ 0 \end{bmatrix} + u \begin{bmatrix} 2 \\ 4 \end{bmatrix}. \end{equation*}\]

Vi må ikke glemme at fastsætte parameterens interval. Her vælges \(u \in [0,1]\). Som \(u\) gennemløber sit interval, bevæger vi os langs linjen fra \((2,0)\) til \((4,4)\) og fejer undervejs igennem punkter, der udgør den rette linje \(L\).

I Sympy defineres en sådan parameterfremstilling som en simpel vector (eller some en Python-funktion, hvis det ønskes) uden, at Sympy får noget at vide om parameterintervallet. Men hvis du vil plotte den, så skal intervallet tages med:

u,v = symbols("u v")
r_L = Matrix([2,0]) + Matrix([2,4]) * u
r_L
\[\begin{split}\displaystyle \left[\begin{matrix}2 u + 2\\4 u\end{matrix}\right]\end{split}\]
dtuplot.plot_parametric(*r_L, (u,0,1), xlim=(0,5), ylim=(0,5))
../_images/1ddf7cfb0dd90108dcaa7057d1ae6d1d2d028aaef73ca9eaa7ab131903af2ed2.png
<spb.backends.matplotlib.matplotlib.MatplotlibBackend at 0x7f39849ca2d0>

Bemærk brugen af en asterisk * i *r_L i plot-kommandoen. Denne asterisk fjerne vektorstrukturen, så kun vektorens elementer indsættes som en tupel.

Plane områder afgrænset af rette linjer#

Vi skal nu parametrisere et område \(S\) i planen, der er afgrænset af linjerne:

\[\begin{equation*} \begin{aligned} y &= 1-x\\ y &= 2x+1\\ x &= 2 \end{aligned} \end{equation*}\]

hvilket skrevet som en punktmængde er

\[\begin{equation*} S=\Bigl\{(x,y) \in \mathbb{R}^2\ \mid 0 \leq x \leq 2 \, \wedge \, 1 - x\leq y \leq 2x+1\Bigr\}. \end{equation*}\]

Dette plottes med plot_implicit, der som argumenter tager først og fremmest alle tre ligninger, Eq(x,2),Eq(y,2*x+1),Eq(y,1-x), og dernæst de regler, (x <= 2) & (y <= 2*x+1) & (y >= 1-x), der afgør, hvad der skal skraveres/farves:

x,y = symbols("x y")
omraade = dtuplot.plot_implicit(Eq(x,2),Eq(y,2*x+1),Eq(y,1-x),(x <= 2) & (y <= 2*x+1) & (y >= 1-x),(x,-0.1,5),(y,-1.1,5.1),aspect="equal",size=(8,8))
/builds/pgcs/pg1/venv/lib/python3.11/site-packages/spb/series.py:2255: UserWarning: The provided expression contains Boolean functions. In order to plot the expression, the algorithm automatically switched to an adaptive sampling.
../_images/c8e0fd0490f0484af9edcae725cc311bdb27449f71ed336c750ff2d3e08a045f.png

For at parametrisere \(S\) er det nyttigt at forestille sig \(S\) som bestående af alle lodrette linjer, der kan tegnes fra den nedre linje \(y=-x + 1\) til den øvre linje \(y=2x + 1\), pakket tæt sammen.

Ethvert punkt på den nedre linje \(y=-x + 1\) kan udtrykkes ved \(A = (u,1-u)\) og punkter på den øvre linje \(y=2x + 1\) ved \(B = (u,2u+1)\). Vi skal bruge \(u\in[0,2]\) for ikke at forlade linjerne. En vektor fra den nedre til den øvre linje for ethvert \(u\) er:

\[\begin{equation*} B-A = \begin{bmatrix} u - u \\ 2u+1 - (1-u) \end{bmatrix} = \begin{bmatrix} 0 \\ 3u \end{bmatrix}. \end{equation*}\]

Fx har vi for \(u=1\) (svarende til \(x=1\)) start- og endepunkt \(A=(1,1-1)=(1,0)\) og \(B=(1,2\cdot 1+1)=(1,3)\), og vektoren imellem dem er \(\begin{bmatrix} 0 \\ 3 \end{bmatrix}\). Plot af denne eksempelvektor:

AB = dtuplot.quiver(Matrix([1,0]),Matrix([0,3]),show=False,rendering_kw = {"color" : "black"})

omraade.extend(AB)
omraade.show()
../_images/078e07558875f92f2de26f7be82550c1cbe6eff96a1d254897fb2f902a1ad6ef.png

Hensigten er at starte fra et punkt \(A\) på den nedre linje og derfra bevæge sig med vektoren, altså:

\[\begin{equation*} \begin{bmatrix} u \\ 1-u \end{bmatrix} + \begin{bmatrix} 0 \\ 3u \end{bmatrix}, \, u \in [0,2]. \end{equation*}\]

Som \(u\) gennemløber sit interval, vil dette tegne hele den øvre linje. Lad os nu introducere en ny parameter \(v\in[0,1]\), der nedskalerer bevægelsen langs vektoren. Når den ganges på vektoren, vil \(v=1\) svare til vektorens fulde længde, \(v=0\) vil fjerne vektoren den, så vi bliver på den nedre linje, og værdierne derimellem lader os nå alle punkter langs vektoren og dermed samlet set alle punkter i det indre af \(S\):

\[\begin{equation*} \boldsymbol r_S(u,v) = \begin{bmatrix} u \\ 1-u +3vu\end{bmatrix}, \quad u \in [0,2], \, v \in [0,1]. \end{equation*}\]

Dette er vores endelige parametrisering af det plane område \(S\).

Du vil nu gerne plotte din parametrisering. Desværre er det ikke muligt at plotte planer i 2D-rum. En måde at omgå denne begrænsning på, er at plotte planet i et 3D-rum med fx plot3d_parametric_surface, hvilket kræver tilføjelse af et dummy-koordinat 0 til parametriseringen, for så at dreje camera til at se ned på geometrien ovenfra:

dtuplot.plot3d_parametric_surface(u,1-u+3*u*v,0,(u,0,2),(v,0,1),camera={"elev":90, "azim":-90})
/builds/pgcs/pg1/venv/lib/python3.11/site-packages/spb/backends/matplotlib/matplotlib.py:591: UserWarning: Attempting to set identical low and high zlims makes transformation singular; automatically expanding.
../_images/8641d995b8ea83d96739de9d18139aa3f5bb95e1f4de3c775a5049b9d9d94315.png
<spb.backends.matplotlib.matplotlib.MatplotlibBackend at 0x7f3916708d90>

Circulære områder#

Lad os her parametrisere en enhedscirkelskive, der har centrum i \((2,1)\), som vi kalder for \(C\).

Som før laver vi en vektor fra origo til et vilkårligt punkt på skivens rand, hvilket er enhedscirklen. Per definition af cosinus of sinus kan såden en vektor opbygges som \(\begin{bmatrix} \cos(u) \\ \sin(u) \end{bmatrix}\) for \(u\in[0,2\pi]\). Som \(u\) gennemløber dette interval, tegner vektoren den fulde enhedscirkel (en anden radius opnås ved, at vektoren ganges med en skalar). Herefter skubber vi cirklen ud til det ønskede centrum ved simpelthen at tilføje centrummet:

\[\begin{equation*} \begin{bmatrix} 2 \\ 1 \end{bmatrix} + \begin{bmatrix} \cos(u) \\ \sin(u) \end{bmatrix},\quad \text{for } \, u \in [0,2\pi]. \end{equation*}\]

Her et plot af én af de omtalte vektorer:

cirkel = dtuplot.plot_implicit(Eq((x-2) ** 2 + (y-1) ** 2,1),((x-2) ** 2 + (y-1) ** 2 <=1),(x,0,3),(y,0,3), aspect = 'equal',show=False)
AB = dtuplot.quiver(Matrix([2,1]),Matrix([cos(pi /4),sin(pi / 4)]),rendering_kw={"color":"black"}, show=False)
(cirkel + AB).show()
../_images/b856c6ab3758d4e90fc24c88fb6663792038e55f80909680d16d01000cc705b5.png

Vi har nu tegnet cirkelskivens periferi. Lad os indføre en parameter \(v\), der nedskalerer vektoren med en værdi mellem \(0\) og \(1\), således at vi når alle punkter langs alle vektorerne, dvs. alle punkter inden for periferien. Vores færdige parameterfremstilling bliver:

\[\begin{equation*} \boldsymbol r_C(u) = \begin{bmatrix} 2 + v \cos(u) \\ 1 + v \sin(u) \end{bmatrix} = \begin{bmatrix} x \\ y \end{bmatrix},\quad \text{for } u \in [0,2\pi],\, v \in [0,1]. \end{equation*}\]

Et plot:

u,v = symbols('u v')
rC = Matrix([2,1]) + v * Matrix([cos(u),sin(u)])
rC
\[\begin{split}\displaystyle \left[\begin{matrix}v \cos{\left(u \right)} + 2\\v \sin{\left(u \right)} + 1\end{matrix}\right]\end{split}\]
dtuplot.plot_parametric_region(*rC, (u,0,2*pi), (v,0,1), aspect="equal")
../_images/85d681e0006bb1bb7fc40ef4fbe2e7f2fec49275f8d68c1e3e77628612c4a6f6.png
<spb.backends.matplotlib.matplotlib.MatplotlibBackend at 0x7f39164bebd0>

Kugler og omdrejninger#

En massiv kugle i \(\Bbb R^3\) med radius \(r\) og centrum \((c_1,c_2,c_3)\) kan beskrives ved punktmængden

\[\begin{equation*} \left\{\boldsymbol{x} \in \mathbb{R}^3 \:|\: (x-c_1)^2+(y-c_2)^2+(z-c_3)^2\leq r^2 \right\}. \end{equation*}\]

Særtilfældet med enhedskuglen centreret i origo kan beskrives på simplere vis:

\[\begin{equation*} \Omega = \left\{\boldsymbol{x} \in \mathbb{R}^3 \:|\: ||\boldsymbol{x}|| \leq 1 \right\}. \end{equation*}\]

Lad os parametrisere denne enhedskugle \(\Omega\).

Hvis man drejer en cirkel i \((x,z)\)-planet 180 grader om \(z\)-aksen, så fejer man igennem punkter, der udgør en kugleskal. Fyldes den op, har vi opnået \(\Omega\), så lad os følge denne fremgangsmåde. Cirklen i \((x,z)\)-planet, der udgør “grundtegningen” for omdrejningen, kaldes en profilkurve, og den parametriseres ved:

\[\begin{equation*} \boldsymbol{r}_{profil} = \begin{bmatrix} \cos(u)\\ 0\\ \sin(u) \end{bmatrix}, \quad u\in[0,2\pi]. \end{equation*}\]
r_profil = Matrix([cos(u), 0, sin(u)])

dtuplot.plot_parametric(r_profil[0], r_profil[2], (u,0,2*pi), use_cm=False,aspect="equal", xlabel = 'x', ylabel = 'z')
../_images/b0327b7f0e774fdc16ac2849e9ebae654c9b9479551942de3137b0cb404ebcbd.png
<spb.backends.matplotlib.matplotlib.MatplotlibBackend at 0x7f39166ad950>

En drejning kan gennemføres ved brug af en rotationsmatrix, her designet til en rotation på 180 grader (\(\pi\) radianer) om \(z\)-aksen (bemærk, dog, at rotationsmatricer ikke er en del af pensum):

\[\begin{equation*} R_z = \left[\begin{matrix}\cos{\left(v \right)} & - \sin{\left(v \right)} & 0\\\sin{\left(v \right)} & \cos{\left(v \right)} & 0\\0 & 0 & 1\end{matrix}\right], \quad v\in[0,\pi]. \end{equation*}\]
Rz = Matrix([[cos(v), -sin(v), 0], [sin(v), cos(v), 0], [0, 0, 1]])
Rz
\[\begin{split}\displaystyle \left[\begin{matrix}\cos{\left(v \right)} & - \sin{\left(v \right)} & 0\\\sin{\left(v \right)} & \cos{\left(v \right)} & 0\\0 & 0 & 1\end{matrix}\right]\end{split}\]

Rotationen gennemføres ved multiplikation af matricen på profilkurven:

r_skal = simplify(Rz * r_profil)
r_skal
\[\begin{split}\displaystyle \left[\begin{matrix}\cos{\left(u \right)} \cos{\left(v \right)}\\\sin{\left(v \right)} \cos{\left(u \right)}\\\sin{\left(u \right)}\end{matrix}\right]\end{split}\]

Dette er den ydre kugleskal. Den massive kugle \(\Omega\) opnås ved at gange dette vektorudtryk med en parameter \(w \in [0,1]\), så vi dermed fejer igennem alle kugleskaller fra radius \(0\) til \(1\). Den endelige parameterfremstilling af \(\Omega\) er dermed:

\[\begin{equation*} \boldsymbol{r}_{\Omega} = \left[\begin{matrix}w\cos{\left(u \right)} \cos{\left(v \right)} \\ w\cos{\left(u \right)}\sin{\left(v \right)}\\ w\sin{\left(u \right)}\end{matrix}\right], \quad u\in[0,2\pi], v\in[0,\pi], w\in[0,1]. \end{equation*}\]
w = symbols('w')
r_omega = r_skal * w
r_omega
\[\begin{split}\displaystyle \left[\begin{matrix}w \cos{\left(u \right)} \cos{\left(v \right)}\\w \sin{\left(v \right)} \cos{\left(u \right)}\\w \sin{\left(u \right)}\end{matrix}\right]\end{split}\]

Man kan ikke tegne massive tre-dimensionelle legemer i Python. Men vi kan give en indikation af, hvordan legemet ville se ud ved at tegne dets ydervæg, alternativt ved at tegne et par semitransparente kugleskaller fra kuglens indre, begge noget der opnås ved at fastsætte til parameteren \(w\) til passende værdier:

helkugle = dtuplot.plot3d_parametric_surface(*r_omega.subs(w,1), (u, 0, 2*pi), (v, 0, pi), aspect = 'equal', label = 'w=1', rendering_kw = {'alpha': 0.4,}, show = false)
halvkugle = dtuplot.plot3d_parametric_surface(*r_omega.subs(w,0.5), (u, 0, 2*pi), (v, 0, pi),label ='w = 0.5', rendering_kw = {'alpha': 0.5}, show = False)
kvartkugle = dtuplot.plot3d_parametric_surface(*r_omega.subs(w,0.25), (u, 0, 2*pi), (v, 0, pi),label ='w = 0.25', show = False)
(helkugle + halvkugle + kvartkugle).show()
../_images/07cb9da862d06875d76d55ae876f0aed79b34a28ecfa4703cf75ad7387bf81bd.png

Til dette plot har vi benyttet den generelle plot3d_parametric_surface-kommando fra dtuplot-pakken. Til sfærisk geometri kan man dog også bruge kommandoen plot3d_spherical som et alternativ. Herunder plottes blot et udsnit af en kugleskal med en radius på \(2\):

radius = 2

dtuplot.plot3d_spherical(
    radius,
    (u, pi / 6, pi / 2),(v, 0, pi),
    aspect="equal",
    camera={"elev": 25, "azim": 55}
)
../_images/1b08abaf7fa6e9e82c379ac91ace1c93b1c161e0498fae46b3c489031238eb0c.png
<spb.backends.matplotlib.matplotlib.MatplotlibBackend at 0x7f3915f23d90>

Lukket overflade i adskillige dele#

I \(\Bbb R^3\) er en 1-enhed høj container med form som en cirkulær paraboloide givet. Vi får også givet et circulært låg dertil med en radius på 1 enhed. Lad os sætte låget på og placere den nu lukkede container i et koordinatsystem med \(z\)-aksen midt igennem og med spidsen nedad. Paraboloidevæggen og låget udgør samlet en lukket overflade, som vi kan parametrisere ved at parametrisere de to dele hver for sig.

Paraboloidedelen af geometrien er blot en paraboloide, der når op til \(z=1\). Som en punktmængde kan den beskrives ved:

\[F_{væg}=\{(x,y,z)\in \Bbb R^3\,|\,z=x^2+y^2\land z\leq1\}.\]

Vi bemærker, at alle vandrette tværsnit er cirkler. En tilgang til en parametrisering af paraboloidevæggen er derfor at starte med en cirkelskive, som vi så et eksempel på tidligere:

\[\begin{split}\begin{bmatrix}u\cos(v)\\ u\sin(v)\end{bmatrix}\,,\,v\in[-\pi,\pi],\end{split}\]

(vi venter med at fastsætte radius \(u\)), og så at løfte denne cirkelskive ved at tilføje det givne \(z\)-udtryk som en tredjekoordinat:

\[\begin{split}\boldsymbol r_{F_{væg}}=\begin{bmatrix}u\cos(v)\\ u\sin(v)\\ (u\cos(v))^2+ (u\sin(v))^2 \end{bmatrix}=\begin{bmatrix}u\cos(v)\\ u\sin(v)\\ u^2 \end{bmatrix}\,,\, v\in[-\pi,\pi].\end{split}\]

Bemærk, hvordan \(x\) og \(y\) i dette tredjekoordinatsudtryk erstattes af de eksisterende udtryk for hhv. første- og andenkoordinaten. For at opfylde kravet \(z\leq1\), vælges \(u\in[0,1]\), og dette færdiggør parametriseringen.

u, v = symbols("u v", real=True)
r_vaeg = Matrix([u * cos(v), u * sin(v), u**2])
r_vaeg
\[\begin{split}\displaystyle \left[\begin{matrix}u \cos{\left(v \right)}\\u \sin{\left(v \right)}\\u^{2}\end{matrix}\right]\end{split}\]

Et plot:

p_vaeg = dtuplot.plot3d_parametric_surface(*r_vaeg,(u, 0, 1),(v, -pi, pi),
    use_cm=False,
    camera={"elev": 25, "azim": -55}
)
../_images/a81f0729d329633d7cf685e86dd77d96895b5ee065f851d7e570fac7302f1421.png

Nu til låget, \(F_{låg}\), som er en simpel cirkelskive. Dens radius stemmer med paraboloidevæggens største radius ved sin åbning, så vi fastholder \(u\in[0,1]\), og den skal blot placeres på toppen af paraboloiden, hvor \(u=1\), hvilket dermed giver den en tredjekoordinat. En parametrisering bliver dermed:

\[\begin{split}\boldsymbol r_{F_{låg}}=\begin{bmatrix}u\cos(v)\\ u\sin(v)\\ 1 \end{bmatrix}\,,\, u\in[0,1],v\in[-\pi,\pi].\end{split}\]
r_laag = Matrix([u * cos(v), u * sin(v), 1])
r_laag
\[\begin{split}\displaystyle \left[\begin{matrix}u \cos{\left(v \right)}\\u \sin{\left(v \right)}\\1\end{matrix}\right]\end{split}\]

Et samlet plot af begge dele af containeren:

p_laag = dtuplot.plot3d_parametric_surface(*r_laag,(u, 0, 1),(v, -pi, pi),
    use_cm=False,
    camera={"elev": 25, "azim": -55},
    show=False
)

(p_vaeg + p_laag).show()
../_images/cab48af0f51acf33e51f74fb3d51c2e7d022c6175744cd0f7ad07d91a59268ce.png

Et massivt legeme#

Et massivt, tre-dimensionelt område \(\Omega\subset \Bbb R^3\) - også kaldet et legeme - er givet ved punktmængden:

\[\begin{equation*} \Omega=\bigl\{(x,y,z) \in \mathbb{R}^3 : x\in[0,3], \, y\in[0,2], \,z\in[0,y^2] \bigr\}. \end{equation*}\]

Vi parametriserer først området i \((x,y)\)-planet ved:

u, v, w = symbols("u v w")
Matrix([u, v])
\[\begin{split}\displaystyle \left[\begin{matrix}u\\v\end{matrix}\right]\end{split}\]

for \(u\in[0,3],v\in[0,2]\). Bemærk, hvor nemt det er at parametrisere en rektangel. Dernæst løftes den til formen på “taget” af vores legeme ved at den gives en tredjekoordinat \(z=y^2\):

Matrix([u, v, v**2])
\[\begin{split}\displaystyle \left[\begin{matrix}u\\v\\v^{2}\end{matrix}\right]\end{split}\]

hvor \(y\) erstattes med andenkoordinaten, altså \(v\). Til slut fylder vi figuren ud med alle punkter under “taget” og ned til “gulvet” ved en ny parameter \(w\):

r = Matrix([u, v, w*v**2])
r
\[\begin{split}\displaystyle \left[\begin{matrix}u\\v\\v^{2} w\end{matrix}\right]\end{split}\]

Parameterintervallerne er \(u\in[0,3],v\in[0,2],w\in[0,1]\), og dette afslutter vores parameterfremstilling af \(\Omega\).

Lad os illustrere den. Det er ikke let at plotte legemer med Python, men vi kan vælge at plotte hvert overfladestykke ved at fiksere nogle parameterværdier passende én ad gangen - det kan ofte være en relativt svær manøvre at finde de rette værdier, så vær varsom og tjek dit plot løbende undervejs:

a = symbols("a")
p = dtuplot.plot3d_parametric_surface(
    x,
    y,
    y**2,
    (x, 0, 3),
    (y, 0, 2),
    {"color": "royalblue"},
    use_cm=False,
    aspect="equal",
    show=False,
)
p.extend(
    dtuplot.plot3d_parametric_surface(
        0,
        y,
        a * y**2,
        (a, 0, 1),
        (y, 0, 2),
        {"color": "royalblue", "alpha": 0.5},
        use_cm=False,
        aspect="equal",
        show=False,
    )
)
p.extend(
    dtuplot.plot3d_parametric_surface(
        3,
        y,
        a * y**2,
        (a, 0, 1),
        (y, 0, 2),
        {"color": "royalblue", "alpha": 0.5},
        use_cm=False,
        aspect="equal",
        show=False,
    )
)
p.extend(
    dtuplot.plot3d_parametric_surface(
        x,
        2,
        a * 4,
        (x, 0, 3),
        (a, 0, 1),
        {"color": "royalblue", "alpha": 0.5},
        use_cm=False,
        aspect="equal",
        show=False,
    )
)
p.extend(
    dtuplot.plot3d_parametric_surface(
        x,
        y,
        0,
        (x, 0, 3),
        (y, 0, 2),
        {"color": "royalblue", "alpha": 0.5},
        use_cm=False,
        aspect="equal",
        show=False,
    )
)


p.show()
../_images/461bcc7d4a25029511e49dbb950fa2cad18a17fa025961ef9b6aa96c380a9337.png