From 6acb282aa5d5dcaeca8f75b955ad526679bf04fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?eXerigumo=20Clanjor=20=28=E5=93=86=E5=95=A6=E6=AF=94?= =?UTF-8?q?=E7=8C=AB=29?= Date: Sat, 27 Oct 2012 22:10:19 +0800 Subject: [PATCH] more on latex move perl_* into perl --- latex/advanced_character_physics/acp.latex | 201 +++++++++++++++++- .../perl_animation}/01-easing/easing1 | 0 .../perl_animation}/01-easing/easing2 | 0 .../perl_animation}/01-easing/easing3 | 0 .../perl_animation}/01-easing/easing4 | 0 .../perl_animation}/02-spring/line | 0 .../perl_animation}/02-spring/spring-multi1 | 0 .../perl_animation}/02-spring/spring1 | 0 .../perl_animation}/02-spring/spring2 | 0 .../perl_animation}/02-spring/spring3 | 0 .../perl_animation}/02-spring/spring4 | 0 .../perl_animation}/02-spring/spring5 | 0 .../03-adv-character-phys/acp1 | 0 .../03-adv-character-phys/acp2 | 0 .../03-adv-character-phys/acp3 | 0 .../03-adv-character-phys/acp3-cloth | 2 +- .../03-adv-character-phys/acp3-rigid | 0 .../perl_learning}/01_test.pl | 0 perl/perl_vector/cloth.pl | 50 +++++ perl/perl_vector/vector.pm | 130 +++++++++++ 20 files changed, 371 insertions(+), 12 deletions(-) rename {perl_animation => perl/perl_animation}/01-easing/easing1 (100%) rename {perl_animation => perl/perl_animation}/01-easing/easing2 (100%) rename {perl_animation => perl/perl_animation}/01-easing/easing3 (100%) rename {perl_animation => perl/perl_animation}/01-easing/easing4 (100%) rename {perl_animation => perl/perl_animation}/02-spring/line (100%) rename {perl_animation => perl/perl_animation}/02-spring/spring-multi1 (100%) rename {perl_animation => perl/perl_animation}/02-spring/spring1 (100%) rename {perl_animation => perl/perl_animation}/02-spring/spring2 (100%) rename {perl_animation => perl/perl_animation}/02-spring/spring3 (100%) rename {perl_animation => perl/perl_animation}/02-spring/spring4 (100%) rename {perl_animation => perl/perl_animation}/02-spring/spring5 (100%) rename {perl_animation => perl/perl_animation}/03-adv-character-phys/acp1 (100%) rename {perl_animation => perl/perl_animation}/03-adv-character-phys/acp2 (100%) rename {perl_animation => perl/perl_animation}/03-adv-character-phys/acp3 (100%) rename {perl_animation => perl/perl_animation}/03-adv-character-phys/acp3-cloth (99%) rename {perl_animation => perl/perl_animation}/03-adv-character-phys/acp3-rigid (100%) rename {perl_learning => perl/perl_learning}/01_test.pl (100%) create mode 100755 perl/perl_vector/cloth.pl create mode 100644 perl/perl_vector/vector.pm diff --git a/latex/advanced_character_physics/acp.latex b/latex/advanced_character_physics/acp.latex index 9eb409b..f42400a 100644 --- a/latex/advanced_character_physics/acp.latex +++ b/latex/advanced_character_physics/acp.latex @@ -14,11 +14,14 @@ %\usepackage[usenames,dvipsnames,svgnames,table]{xcolor} \usepackage{nameref} \usepackage[margin=1in]{geometry} +\usepackage{subcaption} +\usepackage{amssymb,amsmath} \usetikzlibrary[arrows] -% Will this produce better-looking document? +% Will these produce better-looking document? %\setlength{\parskip}{\baselineskip} +%\setlength{\parindent}{0em} %%% Commands @@ -42,6 +45,18 @@ \end{figure} } +\newcommand{\SUBFIGDRAW}[3]{ % label, caption, drawing commands + \begin{subfigure}[b]{0.3\textwidth} + \centering + \begin{tikzpicture} + %\draw[step=0.25cm,color=gray] (-4,-4) grid (4,4); + #3 + \end{tikzpicture} + \caption{#2} + \label{#1} + \end{subfigure} +} + \newcommand{\DRAWX}[3]{ % x, y, size \draw (#1-#3,#2-#3) -- (#1+#3, #2+#3); \draw (#1-#3,#2+#3) -- (#1+#3, #2-#3); @@ -180,7 +195,7 @@ experience on implementing friction etc. Finally, in \SEC{sec:conclusion} a brief conclusion. In the following, $\vec{v}$ indicates vectors. Vector components are -indexed by using subscript, i.e., $\vec{x}=(x_{1}, x_{2}, x_{3})$. +indexed by using subscript, i.e., $\vec{x}=(x_1, x_2, x_3)$. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -208,7 +223,7 @@ velocity, we store its current position $\vec{x}$ and its previous position $\vec{x}''$. Keeping the time step fixed, the update rule (or integration step) is then -$$\vec{x}' = 2\cdot\vec{x} - \vec{x}'' + \vec{a}\cdot\Delta{t}^{2}$$ +$$\vec{x}' = 2\cdot\vec{x} - \vec{x}'' + \vec{a}\cdot\Delta{t}^2$$ $$\vec{x}'' = \vec{x}$$ This is called Verlet integration\cite{Verlet} and is used intensely when @@ -221,7 +236,7 @@ $\vec{x}-\vec{x}''$ is an approximation of the current velocity (actually, it's the distance traveled last time step). It is not always very accurate (energy might leave the system, i.e., dissipate) but it's fast and stable. By changing the update rule to something like -$\vec{x}'=1.99\cdot\vec{x}-0.99\cdot\vec{x}''+\vec{a}\cdot\Delta{t}^{2}$, +$\vec{x}'=1.99\cdot\vec{x}-0.99\cdot\vec{x}''+\vec{a}\cdot\Delta{t}^2$, a small amount of drag can also be introduced to the system. At the end of each step, for each particle the current position $\vec{x}$ @@ -401,7 +416,7 @@ that should be satisfied at all times: \begin{equation} \label{eqn:cubecons} -0 \le x_{i} \le 1000, \forall i \in \{1,2,3\} +0 \le x_i \le 1000, \forall i \in \{1,2,3\} \end{equation} In the example, constraints were satisfied (that is, particles are kept @@ -420,14 +435,14 @@ exactly so strong and suitably damped that instantly they will attain their rest length zero. We now extend the experiment to model a stick of length 100. We do this -by setting up two individual particles (with positions $\vec{x}_{1}$ and -$\vec{x}_{2}$) and then require them to be a distance of 100 apart. +by setting up two individual particles (with positions $\vec{x}_1$ and +$\vec{x}_2$) and then require them to be a distance of 100 apart. Expressed mathematically, we get the following bilateral (equality) constraint: \begin{equation} \label{eqn:bilacons} -|{\vec{x}_{2} - \vec{x}_{1}}| = 100 +|{\vec{x}_2 - \vec{x}_1}| = 100 \end{equation} Although the particles might be correctly placed initially, after one @@ -469,7 +484,7 @@ x2 -= delta*0.5*diff; %%%%% -Note that \texttt{delta} is a vector so \texttt{delta*delta} is actually +Note that \texttt{delta} is a vector so \texttt{delta * delta} is actually a dot product. With \texttt{restlength=100} the above pseudo-code will push apart or pull together the particles such that they once more attain the correct distance of 100 between them. Again we may think of the @@ -587,7 +602,7 @@ constraint expression ought to be, namely the rest length $r$ of the corresponding stick. We can use this fact to approximate the square root function. Mathematically, what we do is approximate the square root function by its 1st order Taylor-expansion at a neighborhood of the -squared rest length $r^{2}$ (this is equivalent to one Newton-Raphson +squared rest length $r^2$ (this is equivalent to one Newton-Raphson iteration with initial guess $r$). After some rewriting, we obtain the following pseudo-code: @@ -605,7 +620,7 @@ $|\texttt{delta}|=\texttt{restlength}$), then one gets $\texttt{delta}=(0,0,0)$ and no change is going to happen. Per constraint we now use zero square roots, one division only, and the -squared value \texttt{restlength*restlength} can even be precalculated! +squared value \texttt{restlength * restlength} can even be precalculated! The usage of time consuming operations is now down to N divisions per frame (and the corresponding memory accesses) --- it can't be done much faster than that and the result even looks quite nice. Actually, in @@ -653,6 +668,170 @@ speed-up. \section{Rigid Bodies} \label{sec:rigid} +The equations governing motion of rigid bodies were discovered long +before the invention of modern computers. To be able to say anything +useful at that time, mathematicians needed the ability to manipulate +expressions symbolically. In the theory of rigid bodies, this lead to +useful notions and tools such as inertia tensors, angular momentum, +torque, quaternions for representing orientations etc. However, with the +current ability to process huge amounts of data numerically, it has +become feasible and in some cases even advantageous to break down +calculations to simpler elements when running a simulation. In the case +of 3D rigid bodies, this could mean modeling a rigid body by four +particles and six constraints (giving the correct amount of degrees of +freedom, $4\times3-6=6$). This simplifies a lot of aspects and it's +exactly what we will do in the following. + +Consider a tetrahedron and place a particle at each of the four vertices. +In addition, for each of the six edges on the tetrahedron create a +distance constraint like the stick constraint discussed in the previous +section. This is actually enough to simulate a rigid body. The +tetrahedron can be let loose inside the cube world from earlier and the +Verlet integrator will let it move correctly. The function +\texttt{SatisfyConstraints()} should take care of two things: 1) That +particles are kept inside the cube (like previously), and 2) That the +six distance constraints are satisfied. Again, this can be done using +the relaxation approach; 3 or 4 iterations should be enough with +optional square root approximation. + +Now clearly, in general rigid bodies do not behave like tetrahedrons +collision-wise (although they might do so kinetically). There is also +another problem: Presently, collision detection between the rigid body +and the world exterior is on a vertex-only basis, that is, if a vertex +is found to be outside the world it is projected inside again. This +works fine as long as the inside of the world is convex. If the world +were non-convex then the tetrahedron and the world exterior could +actually penetrate each other without any of the tetrahedron vertices +being in an illegal region (see \FIG{fig:tetpene} where the triangle +represents the 2D analogue of the tetrahedron). This problem is handled +in the following. + +\FIGDRAW{fig:tetpene}{A tetrahedron penetrating the world.}{ + \draw (-1, -1) -- (-0.3, -1) -- (0, -0.5) -- (0.3, -1) + -- (1, -1) -- (1, 1) -- (-1, 1) -- cycle; + \draw (0, 0) -- (-0.5, -0.8) -- (0.5, -0.8) -- cycle; +} + +We'll first consider a simpler version of the problem. Consider the +stick example from earlier and assume that the world exterior has a +small bump on it. The stick can now penetrate the world exterior without +any of the two stick particles leaving the world (see +\FIG{fig:colstick}). We won't go into the intricacies of constructing a +collision detection engine since this is a science in itself. Instead we +assume that there is a subsystem available which allows us to detect the +collision. Furthermore we assume that the subsystem can reveal to us the +penetration depth and identify the penetration points on each of the two +colliding objects. (One definition of penetration points and penetration +depth goes like this: The penetration distance $d_p$ is the shortest +distance that would prevent the two objects from penetrating if one were +to translate one of the objects by the distance $d_p$ in a suitable +direction. The penetration points are the points on each object that +just exactly touch the other object after the aforementioned translation +has taken place.) + +\begin{figure}[h!] +\centering +\SUBFIGDRAW{fig:colstick-a}{Colliding stick I.}{ + \draw (-1, -1) -- (-0.3, -1) -- (0, -0.5) -- (0.3, -1) + -- (1, -1) -- (1, 1) -- (-1, 1) -- cycle; + \DRAWX{0}{-0.8}{0.05} + \node at (0, -1.2) {$\vec{p}(\vec{x}_1)$}; + \DRAWX{0.15}{-0.75}{0.05} + \node at (0.35, -0.75) {$\vec{q}$}; + \draw (0, -0.8) -- (0.5, 0); + \node at (0.7, 0.2) {$\vec{x}_2$}; +} +\SUBFIGDRAW{fig:colstick-b}{Colliding stick II.}{ + \draw (-1, -1) -- (-0.3, -1) -- (0, -0.5) -- (0.3, -1) + -- (1, -1) -- (1, 1) -- (-1, 1) -- cycle; + \DRAWX{0}{-0.8}{0.05} + \node at (0, -1.2) {$\vec{p}$}; + \DRAWX{0}{-0.5}{0.05} + \node at (0, -0.25) {$\vec{q}$}; + \draw (-0.4, -0.8) -- (0.8, -0.8); + \node at (-0.4, -0.6) {$\vec{x}_1$}; + \node at (0.8, -0.6) {$\vec{x}_2$}; +} +\caption{Colliding stick.}\label{fig:colstick} +\end{figure} + +Take a look again at \FIG{fig:colstick}. Here the stick has moved through +the bump after the Verlet step. The collision engine has identified the +two points of penetration, $\vec{p}$ and $\vec{q}$. In +\FIG{fig:colstick-a}, $\vec{p}$ is actually identical to the position of +particle 1, i.e., $\vec{p}=\vec{x}_1$. In \FIG{fig:colstick-b}, +$\vec{p}$ lies between $\vec{x}_1$ and $\vec{x}_2$ at a position +$\frac{1}{4}$ of the stick length from $\vec{x}_1$. In both cases, the +point $\vec{p}$ lies on the stick and consequently it can be expressed +as a linear combination of $\vec{x}_1$ and $\vec{x}_2$, +$\vec{p}=c_1\cdot\vec{x}_1+c_2\cdot\vec{x}_2$ such that $c_1+c_2=1$. In +the first case, $c_1=1$ and $c_2=0$, in the second case, $c_1=0.75$ and +$c_2=0.25$. These values tell us how much we should move the +corresponding particles. + +To fix the invalid configuration of the stick, it should be moved upwards +somehow. Our goal is to avoid penetration by moving $\vec{p}$ to the same +position as $\vec{q}$. We do this by adjusting the positions of the two +particles $\vec{x}_1$ and $\vec{x}_2$ in the direction of the vector +between $\vec{p}$ and $\vec{q}$, $\vec{\Delta}=\vec{q}-\vec{p}$. + +In the first case, we simply project $\vec{x}_1$ out of the invalid +region like earlier (in the direction of $\vec{q}$) and that's it +($\vec{x}_2$ is not touched). In the second case, $\vec{p}$ is still +nearest to $\vec{x}_1$ and one might reason that consequently $\vec{x}_1$ +should be moved more than $\vec{x}_2$. Actually, since +$\vec{p}=0.75\cdot\vec{x}_1+0.25\cdot\vec{x}_2$, we will choose to move +$\vec{x}_1$ by an amount of 0.75 each time we move $\vec{x}_2$ by an +amount of 0.25. In other words, the new particle positions $\vec{x}_1'$ +and $\vec{x}_2'$ are given by the expressions + +$$\vec{x}_1' = \vec{x}_1 + 0.75\cdot\lambda\cdot\vec{\Delta}$$ +\begin{equation} +\label{eqn:colnewpos} +\vec{x}_2' = \vec{x}_2 + 0.25\cdot\lambda\cdot\vec{\Delta} +\end{equation} + +where $\lambda$ is some unknown value. The new position of $\vec{p}$ +after moving both particles is +$\vec{p}'=c_1\cdot\vec{x}_1'+c_2\cdot\vec{x}_2'$. + +Recall that we want $\vec{p}'=\vec{q}$, i.e., we should choose $\lambda$ +exactly such that $\vec{p}'$ ends up coinciding with $\vec{q}$. Since we +move the particles only in the direction of $\vec{\Delta}$, also +$\vec{p}$ moves in the direction of $\vec{\Delta}$ and consequently the +solution to the equation $\vec{p}'=\vec{q}$ can be found by solving + +\begin{equation} +\label{eqn:colsolve} +\vec{p}'\cdot\vec{\Delta} = \vec{q}\cdot\vec{\Delta} +\end{equation} + +for $\lambda$. Expanding the left-hand side yields: + +\[ +\begin{split} +\vec{p}'\cdot\vec{\Delta} &= + (0.75\cdot\vec{x}_1'+0.25\cdot\vec{x}_2')\cdot\vec{\Delta} \\ +&= (0.75\cdot(\vec{x}_1 + 0.75\cdot\lambda\cdot\vec{\Delta}) + + 0.25\cdot(\vec{x}_2 + 0.25\cdot\lambda\cdot\vec{\Delta})) + \cdot\vec{\Delta} \\ +&= (0.75\cdot\vec{x}_1 + 0.25\cdot\vec{x}_2)\cdot\vec{\Delta} + + \lambda\cdot(0.75^2 + 0.25^2 )\cdot\vec{\Delta}^2 \\ +&= \vec{p}\cdot\vec{\Delta} + + \lambda\cdot(0.75^2 + 0.25^2)\cdot\vec{\Delta}^2 +\end{split} +\] + +which together with the right-hand side of \EQN{eqn:colsolve} gives + +$$ +\lambda=\frac{(\vec{q} - \vec{p})\cdot\vec{\Delta}} + {(0.75^2 + 0.25^2 )\cdot\vec{\Delta}^2} +$$ + +Plugging $\lambda$ into \EQN{eqn:colnewpos} gives us the new positions +of the particles for which $\vec{p}'$ coincide with $\vec{q}$. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/perl_animation/01-easing/easing1 b/perl/perl_animation/01-easing/easing1 similarity index 100% rename from perl_animation/01-easing/easing1 rename to perl/perl_animation/01-easing/easing1 diff --git a/perl_animation/01-easing/easing2 b/perl/perl_animation/01-easing/easing2 similarity index 100% rename from perl_animation/01-easing/easing2 rename to perl/perl_animation/01-easing/easing2 diff --git a/perl_animation/01-easing/easing3 b/perl/perl_animation/01-easing/easing3 similarity index 100% rename from perl_animation/01-easing/easing3 rename to perl/perl_animation/01-easing/easing3 diff --git a/perl_animation/01-easing/easing4 b/perl/perl_animation/01-easing/easing4 similarity index 100% rename from perl_animation/01-easing/easing4 rename to perl/perl_animation/01-easing/easing4 diff --git a/perl_animation/02-spring/line b/perl/perl_animation/02-spring/line similarity index 100% rename from perl_animation/02-spring/line rename to perl/perl_animation/02-spring/line diff --git a/perl_animation/02-spring/spring-multi1 b/perl/perl_animation/02-spring/spring-multi1 similarity index 100% rename from perl_animation/02-spring/spring-multi1 rename to perl/perl_animation/02-spring/spring-multi1 diff --git a/perl_animation/02-spring/spring1 b/perl/perl_animation/02-spring/spring1 similarity index 100% rename from perl_animation/02-spring/spring1 rename to perl/perl_animation/02-spring/spring1 diff --git a/perl_animation/02-spring/spring2 b/perl/perl_animation/02-spring/spring2 similarity index 100% rename from perl_animation/02-spring/spring2 rename to perl/perl_animation/02-spring/spring2 diff --git a/perl_animation/02-spring/spring3 b/perl/perl_animation/02-spring/spring3 similarity index 100% rename from perl_animation/02-spring/spring3 rename to perl/perl_animation/02-spring/spring3 diff --git a/perl_animation/02-spring/spring4 b/perl/perl_animation/02-spring/spring4 similarity index 100% rename from perl_animation/02-spring/spring4 rename to perl/perl_animation/02-spring/spring4 diff --git a/perl_animation/02-spring/spring5 b/perl/perl_animation/02-spring/spring5 similarity index 100% rename from perl_animation/02-spring/spring5 rename to perl/perl_animation/02-spring/spring5 diff --git a/perl_animation/03-adv-character-phys/acp1 b/perl/perl_animation/03-adv-character-phys/acp1 similarity index 100% rename from perl_animation/03-adv-character-phys/acp1 rename to perl/perl_animation/03-adv-character-phys/acp1 diff --git a/perl_animation/03-adv-character-phys/acp2 b/perl/perl_animation/03-adv-character-phys/acp2 similarity index 100% rename from perl_animation/03-adv-character-phys/acp2 rename to perl/perl_animation/03-adv-character-phys/acp2 diff --git a/perl_animation/03-adv-character-phys/acp3 b/perl/perl_animation/03-adv-character-phys/acp3 similarity index 100% rename from perl_animation/03-adv-character-phys/acp3 rename to perl/perl_animation/03-adv-character-phys/acp3 diff --git a/perl_animation/03-adv-character-phys/acp3-cloth b/perl/perl_animation/03-adv-character-phys/acp3-cloth similarity index 99% rename from perl_animation/03-adv-character-phys/acp3-cloth rename to perl/perl_animation/03-adv-character-phys/acp3-cloth index d30d516..59ce95a 100755 --- a/perl_animation/03-adv-character-phys/acp3-cloth +++ b/perl/perl_animation/03-adv-character-phys/acp3-cloth @@ -130,7 +130,7 @@ sub calc { } # satisfy constraints - foreach (1..10) { + foreach (1..1) { foreach my $i (0..$#ps) { con_cube $ps[$i], 0, 400, 0, 400; } diff --git a/perl_animation/03-adv-character-phys/acp3-rigid b/perl/perl_animation/03-adv-character-phys/acp3-rigid similarity index 100% rename from perl_animation/03-adv-character-phys/acp3-rigid rename to perl/perl_animation/03-adv-character-phys/acp3-rigid diff --git a/perl_learning/01_test.pl b/perl/perl_learning/01_test.pl similarity index 100% rename from perl_learning/01_test.pl rename to perl/perl_learning/01_test.pl diff --git a/perl/perl_vector/cloth.pl b/perl/perl_vector/cloth.pl new file mode 100755 index 0000000..a5edae7 --- /dev/null +++ b/perl/perl_vector/cloth.pl @@ -0,0 +1,50 @@ +#!/usr/bin/env perl +# see http://www.gamasutra.com/resource_guide/20030121/jacobson_03.shtml + +use strict; +use warnings; +use vector; + +use SDL; +use SDL::Event; +use SDLx::App; + +my $app = SDLx::App->new( + width => 400, + height => 400, + title => 'Cloth'); + +$app->add_event_handler(\&event); +#$app->add_move_handler (\&move); +$app->add_show_handler (\&render); +&init; +$app->run(); + +sub event { + my $event = shift; + my $controller = shift; + $controller->stop if $event->type == SDL_QUIT; + if ($event->type == SDL_MOUSEMOTION) { + # $target->{x} = $event->button_x; + # $target->{y} = $event->button_y; + } +} + +sub init +{ +} + +sub drawp { +# my $p = shift; +# $app->draw_circle_filled([$p->{x}, $p->{y}], 2, [255, 0, 0, 255]); +} + +sub render { +# my ($delta, $app) = @_; +# $app->draw_rect([0, 0, $app->w, $app->h], 0); # clear screen +# foreach my $i (0..$#ps) { +# drawp $ps[$i]; +# } + $app->update(); +} + diff --git a/perl/perl_vector/vector.pm b/perl/perl_vector/vector.pm new file mode 100644 index 0000000..4348afe --- /dev/null +++ b/perl/perl_vector/vector.pm @@ -0,0 +1,130 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +package Vector; + +use Carp; +use overload + '""' => \&_stringify, + 'neg' => \&_neg, + '+' => \&_add, + '-' => \&_sub, + '*' => \&_mul, + '/' => \&_div, + '.' => \&_dot, + 'x' => \&_cross, + '!' => \&_mod, + '~' => \&_sqr, + '**' => \&_power, +; + + +sub new +{ + my $me = shift; + my $x = shift || 0; + my $y = shift || 0; + my $z = shift || 0; + bless { + x => $x, + y => $y, + z => $z, + } => $me; +} + +sub clone +{ + my $me = shift; + Vector->new($me->{x}, $me->{y}, $me->{z}); +} + + +sub _stringify +{ + my $me = shift; + "Vector->new($me->{x}, $me->{y}, $me->{z})"; +} + +sub _neg +{ + my $me = shift; + Vector->new(-$me->{x}, -$me->{y}, -$me->{z}); +} + +sub _add +{ + my ($me, $other, $swap) = @_; + croak "[+] Vector expected." if ref$other ne 'Vector'; + Vector->new($me->{x}+$other->{x}, + $me->{y}+$other->{y}, + $me->{z}+$other->{z}); +} + +sub _sub +{ + my ($me, $other, $swap) = @_; + croak "[-] Vector expected." if ref$other ne 'Vector'; + Vector->new($me->{x}-$other->{x}, + $me->{y}-$other->{y}, + $me->{z}-$other->{z}); +} + +sub _mul +{ + my ($me, $other, $swap) = @_; + croak "[*] Vector unexpected." if ref$other eq 'Vector'; + Vector->new($me->{x}*$other, $me->{y}*$other, $me->{z}*$other); +} + +sub _div +{ + my ($me, $other, $swap) = @_; + croak "[/] Vector unexpected." if ref$other eq 'Vector'; + $other or do { + carp "!! divided by zero."; + return Vector->new; + }; + $me * (1 / $other); +} + +sub _dot +{ + my ($me, $other, $swap) = @_; + ref$other ne 'Vector' and do { + return $other . "$me" if $swap; + return "$me" . $other; + }; + $me->{x}*$other->{x} + $me->{y}*$other->{y} + $me->{z}*$other->{z}; +} + +sub _cross +{ + my ($me, $other, $swap) = @_; + return "$me" x $other if ref$other ne 'Vector'; + Vector->new($me->{y}*$other->{z} - $me->{z}*$other->{y}, + $me->{z}*$other->{x} - $me->{x}*$other->{z}, + $me->{x}*$other->{y} - $me->{y}*$other->{x}); +} + +sub _mod +{ + sqrt ~shift; +} + +sub _sqr +{ + my $me = shift; + $me . $me; +} + +sub _power +{ + my ($me, $other, $swap) = @_; + (~$me) ** ($other / 2); +} + + +1; +