<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Math on My Blog</title><link>https://EMEEEEMMMM.github.io/tags/math/</link><description>Recent content in Math on My Blog</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Thu, 18 Jun 2026 14:05:02 +0800</lastBuildDate><atom:link href="https://EMEEEEMMMM.github.io/tags/math/index.xml" rel="self" type="application/rss+xml"/><item><title>Structure Of The Engine</title><link>https://EMEEEEMMMM.github.io/posts/structureoftheengine/</link><pubDate>Thu, 18 Jun 2026 14:05:02 +0800</pubDate><guid>https://EMEEEEMMMM.github.io/posts/structureoftheengine/</guid><description>&lt;img src="https://EMEEEEMMMM.github.io/" alt="Featured image of post Structure Of The Engine" /&gt;&lt;p&gt;This article i want to share about the two version in my &lt;a class="link" href="https://github.com/EMEEEEMMMM/AtlasPhys" target="_blank" rel="noopener"
 &gt;repository&lt;/a&gt;, the first one is prototype written in python.&lt;/p&gt;
&lt;h2 id="1-overview"&gt;1. Overview
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Integration&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Broad Phase&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Narrow Phase&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Contact Generation&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Constraint Solving&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Positional Correction&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Others&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="2-integration"&gt;2. Integration:
&lt;/h2&gt;&lt;p&gt;A typical semi-implicit Euler method to update the objects&amp;rsquo; velocity and position. The position is updated right after the velocity. I manually set the $\tau$ to zero so that the $\omega$ won&amp;rsquo;t change by itself.
&lt;/p&gt;
$$
\begin{align}
&amp;a = g \\
&amp;{v_{t + \Delta t}} = {v_t} + a\Delta t \\
&amp;{x_{t + \Delta t}} = {x_t} + {v_{t + \Delta t}}\Delta t \\
&amp;\tau = I\alpha \\
&amp;{\omega _{t + \Delta t}} = {\omega _t} + I_{world}^{ - 1}\tau \Delta t \\
&amp;{\theta _{t + \Delta t}} = {\theta _t} + {\omega _{t + \Delta t}}\Delta t \\
&amp;I_{world}^{ - 1} = RI_{body}^{ - 1}{R^T} 
\end{align}$$&lt;h2 id="3-broad-phase"&gt;3. Broad Phase:
&lt;/h2&gt;&lt;p&gt;My implementation of AABB is different from the standards, the time complexity is stil $O(n^2)$ technically, its role is to filter the objects are probably not going to collide. And since there are only two shapes allowed in the scene (Cubes and Spheres), AABB will work perfectly as I expected. I generate the object&amp;rsquo;s X/Y/Z_MAX/MIN when the object was created (G_Object.py line 128&amp;amp;133).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;MaxXYZ&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;NDArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uint8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;XYZVertices&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;MinXYZ&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;NDArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uint8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argmin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;XYZVertices&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Since the XYZ values here are all in the local space, so when detection i added the object&amp;rsquo;s position.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;check_aabb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X_MAX&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X_MIN&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Y_MAX&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Y_MIN&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Z_MAX&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Z_MIN&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X_MAX&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X_MIN&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Y_MAX&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Y_MIN&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Z_MAX&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Z_MIN&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="4-narrow-phase"&gt;4. Narrow Phase:
&lt;/h2&gt;&lt;p&gt;Consists of two parts: GJK and EPA. All of the code about these two can be found in GJK.py. GJK and EPA happens only when Cube and Cube are going to collide reported by the AABB method to avoid performance issues of running GJK and EPA on spheres.&lt;/p&gt;
&lt;h3 id="41-gjk"&gt;4.1 GJK:
&lt;/h3&gt;&lt;h4 id="minkowski-sums--differences"&gt;Minkowski Sums / Differences
&lt;/h4&gt;&lt;h5 id="sum"&gt;Sum:
&lt;/h5&gt;$${\rm{A}} \oplus B = \left\{ {a + b|a \in A,b \in B} \right\}$$&lt;h5 id="difference"&gt;Difference:
&lt;/h5&gt;$${\rm{A}} \ominus B = \left\{ {a + \left( { - {\rm{b}}} \right)|a \in A,b \in B} \right\}$$&lt;h5 id="properties"&gt;Properties:
&lt;/h5&gt;&lt;ol&gt;
&lt;li&gt;A and B convex -&amp;gt; ${\rm{A}} \ominus B$ convex&lt;/li&gt;
&lt;li&gt;A and B intersect -&amp;gt; $\left( {0,0} \right) \in A \ominus&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="support-function2-dimension"&gt;Support function(2 dimension):
&lt;/h4&gt;&lt;p&gt;C(Minkowski Sum):
&lt;/p&gt;
$$C = A \oplus B $$&lt;p&gt;
The furthest point on A in the direction of ${\vec d}$:
&lt;/p&gt;
$$ {s_A}\left( {\vec d} \right) \to \left( {{x_A},{y_A}} \right) $$&lt;p&gt;
The furthest point on B in the direction of ${\vec d}$:
&lt;/p&gt;
$${s_B}\left( {\vec d} \right) \to \left( {{x_B},{y_B}} \right) $$&lt;p&gt;
Therefore, the furthest point on C in the direction of ${\vec d}$:
&lt;/p&gt;
$$ {s_C}\left( {\vec d} \right) = {s_A}\left( {\vec d} \right) + {s_B}\left( {\vec d} \right) \to \left( {{x_C},{y_C}} \right) $$&lt;p&gt;
&lt;img alt="Notes taken" class="gallery-image" data-flex-basis="320px" data-flex-grow="133" height="6144" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://EMEEEEMMMM.github.io/posts/structureoftheengine/IMG_20260213_154637.jpg" srcset="https://EMEEEEMMMM.github.io/posts/structureoftheengine/IMG_20260213_154637_hu_29e16e6fe08f7158.jpg 800w, https://EMEEEEMMMM.github.io/posts/structureoftheengine/IMG_20260213_154637_hu_bd4682a8a25dfd09.jpg 1600w, https://EMEEEEMMMM.github.io/posts/structureoftheengine/IMG_20260213_154637_hu_bc94e72f21a59986.jpg 2400w, https://EMEEEEMMMM.github.io/posts/structureoftheengine/IMG_20260213_154637.jpg 8192w" width="8192"&gt;
To judge whether the simplex contains the origin, there is a classification for the linear, triangle, tetrahedral cases.&lt;/p&gt;
&lt;h4 id="linear-case"&gt;Linear case:
&lt;/h4&gt;&lt;p&gt;After the initialization, the simplex should contains two points. In 3D space the probability of the origin in a line segment is 0, so the method takes the role of updating the direction variable and returns &lt;em&gt;False&lt;/em&gt;.
Simplex = [B, A] a line segment where A is the latest point added in.
If the dot product $\vec{AB} \cdot \vec{AO} &amp;gt; 0$, the direction is updated as the triple cross $(\vec{AB} \cdot \vec{AO}) \cdot \vec{AB}$. Else, delete point A and update the direction as $\vec{AO}$ since in this case point B is not helpful to find a closer point to origin than A and that makes the result discrete. Finally, returns &lt;em&gt;False&lt;/em&gt;.&lt;/p&gt;
&lt;h4 id="triangle-case"&gt;Triangle case:
&lt;/h4&gt;&lt;p&gt;Simplex = [C, B, A] a triangle. The goal in at this stage is 1. Judge whether the triangle contains the origin. 2. If not, trim the simplex into a line segment and update the direction. Core logic here is 1. Determine whether the origin is on which side of the plane where the triangle is located. 2. Determine whether the origin is outside which side of the plane of the triangle. 3. Reduce the triangle to a line segment and continue the iteration.&lt;/p&gt;
&lt;h4 id="tetrahedral-case"&gt;Tetrahedral case:
&lt;/h4&gt;&lt;p&gt;Simplex = [D, C, B, A] a tetrahedral.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Calculate the normal vector of each face.&lt;/li&gt;
&lt;li&gt;Determine whether the origin is on the outside of each face.&lt;/li&gt;
&lt;li&gt;If the origin is on the outside of any face, trim the point which is not on that face and pass the simplex to the triangle case, returns &lt;em&gt;False&lt;/em&gt;. If the origin is on the inside of all the faces, the tetrahedral contains the origin, the function returns &lt;em&gt;True&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="42-epa"&gt;4.2 EPA:
&lt;/h3&gt;&lt;p&gt;Core logic here is to expand the simplex the GJK returns to approach to the actual Minkowski difference of the two objects.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Obtain the edge with the shortest distance to the origin, and denote the corresponding Minkowski difference as $M_{1},M_{2}$. Find the vector perpendicular to this edge and directed away from the origin.&lt;/li&gt;
&lt;li&gt;Then calculated Minkowski difference $M_{3}$.&lt;/li&gt;
&lt;li&gt;If $\left\vert M_{1}-M_{3} \right\vert+\left\vert M_{2}-M_{3} \right\vert &amp;lt; \epsilon$, exit the iteration.&lt;/li&gt;
&lt;li&gt;If $M_{3}$ not belonging to the point found in the direction, exit iteration.&lt;/li&gt;
&lt;li&gt;If $M_{1}=M_{3}$ or $M_{2}=M_{3}$ if there is a repetition in the existing simplex, exit the iteration.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id="5-contact-generation"&gt;5. Contact Generation:
&lt;/h1&gt;&lt;p&gt;All manifolds of contacts are managed by the class &lt;em&gt;ManifoldManager&lt;/em&gt;, its &lt;em&gt;update()&lt;/em&gt; method returns a list contains the instance of another class &lt;em&gt;PersistentContactManifold&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="51-manifoldmanager"&gt;5.1 ManifoldManager:
&lt;/h2&gt;&lt;p&gt;It has only one method &lt;em&gt;update()&lt;/em&gt;, this method will be executed every physic step to update the contacts between objects:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It walks through the list of objects ($O(n^2)$).&lt;/li&gt;
&lt;li&gt;AABB detects whether the objects are going to collide, if not continue to the next object.&lt;/li&gt;
&lt;li&gt;Generate &lt;em&gt;Keys&lt;/em&gt; to avoid having two identical contact manifold.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;generate_contacts()&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;update_from_collision()&lt;/em&gt; method from &lt;em&gt;PersistentContactManifold&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Clean up the dead keys. (It seems that i had found a bug in the program which there is no method to remove keys from the &lt;em&gt;ActiveKeys&lt;/em&gt;.)&lt;/li&gt;
&lt;li&gt;Returns the Result list.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="52-generate_"&gt;5.2 &lt;em&gt;generate_contacts()&lt;/em&gt;:
&lt;/h2&gt;&lt;h3 id="521-generate_pc_contacts"&gt;5.2.1 generate_pc_contacts():
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;Walk through the list of vertices of the cube.&lt;/li&gt;
&lt;li&gt;If $\begin{bmatrix}0.0 \ 1.0 \ 0.0 \end{bmatrix} \cdot \begin{bmatrix}x \ y \ z \end{bmatrix} - PlaneHeight &amp;lt; 0$, append a contact into the contacts list.&lt;/li&gt;
&lt;li&gt;Returns contacts list and the normal.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="522-generate_ps_contacts"&gt;5.2.2 generate_ps_contacts():
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;If $\begin{bmatrix} 0.0 \ 1.0 \ 0.0 \end{bmatrix} \cdot \begin{bmatrix} x \ y \ z \end{bmatrix}-PlaneHeight \geq R$, returns an empty list and the normal since didn&amp;rsquo;t collide.&lt;/li&gt;
&lt;li&gt;Returns $\begin{bmatrix}x \ y-R \ z\end{bmatrix}$,$R-(\begin{bmatrix}0.0 \ 1.0 \ 0.0 \end{bmatrix} \cdot \begin{bmatrix}x \ y \ z \end{bmatrix} - PlaneHeight)$,normal.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="523-generate_ss_contacts"&gt;5.2.3 generate_ss_contacts():
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;If $\sqrt{(x_{B}-x_{A})^2+(y_{B}-y_{A})^2+(z_{B}-z_{A})^2}\geq R_{A}+R_{B}$, returns two empty lists since didn&amp;rsquo;t collide.&lt;/li&gt;
&lt;li&gt;Returns $\begin{bmatrix}x_{A} \ y_{A} \ z_{A}\end{bmatrix}+\begin{bmatrix}x_{B}-x_{A} \ y_{B}-y_{A} \ z_{B}-z_{A}\end{bmatrix}*R_{A}$,$R_{A}+R_{B} - \sqrt{(x_{B}-x_{A})^2+(y_{B}-y_{A})^2+(z_{B}-z_{A})^2}$, normal.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="524-generate_cc_contacts"&gt;5.2.4 generate_cc_contacts():
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;GJK+EPA returns whether collide, the normal, the Depth.&lt;/li&gt;
&lt;li&gt;Face clipping using Sutherland Hodgman algorithm.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="525-generate_cs_contacts"&gt;5.2.5 generate_cs_contacts():
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;Turn the center of the sphere into the local space of the cube.&lt;/li&gt;
&lt;li&gt;Determine which plane the center of the ball is closest to.&lt;/li&gt;
&lt;li&gt;Choose the normal of that surface.&lt;/li&gt;
&lt;li&gt;Calculate penetration.&lt;/li&gt;
&lt;li&gt;Generate a contact point.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="53-persistentcontactmanifold"&gt;5.3 PersistentContactManifold:
&lt;/h2&gt;&lt;h3 id="warm-start"&gt;Warm start:
&lt;/h3&gt;&lt;p&gt;After the &lt;em&gt;update()&lt;/em&gt; method in ManifoldManager, &lt;em&gt;warm_start()&lt;/em&gt; method will be executed. It uses the impulse from last physic step and applies that to the object by using the method &lt;em&gt;_apply_impulse()&lt;/em&gt; since the contact of objects are not instantaneous but continuous. It makes the system approach the solution more quickly and helps improve the stabilization.&lt;/p&gt;
&lt;h3 id="apply-impulse"&gt;Apply Impulse:
&lt;/h3&gt;&lt;p&gt;All the impulse calculated will be applied by this function.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Velocity&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;J&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReciprocalMass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Velocity&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;J&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReciprocalMass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;$$
\begin{align}
F&amp;=m\frac{dv}{dt} \\
\int F dt&amp;=m \int \frac{dv}{dt} dt \\
J &amp;= m(v'-v) \\
\Delta v &amp;= \frac{J}{m}
\end{align}
$$&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AngularVelocity&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InvInertiaWorld&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cross&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Ra&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;J&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AngularVelocity&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InvInertiaWorld&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cross&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Rb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;J&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;$$
\begin{align}
F &amp;= \frac{dp}{dt} \\
\int F dt &amp;= \int \frac{dp}{dt}dt \\
J &amp;= \Delta p \\ \\
 \\
\Delta L &amp;= r \times \Delta p = r \times J \\
I \Delta \omega &amp;= r \times J \\
\Delta \omega &amp;= I^{-1}(r \times p)
\end{align}
$$&lt;h1 id="6-constraint-solving"&gt;6. Constraint Solving:
&lt;/h1&gt;&lt;h2 id="61-normal-impulse"&gt;6.1 Normal Impulse:
&lt;/h2&gt;$$
\begin{align}
&amp;{r_A} = P - {x_A},{r_B} = P - {x_B}\\
&amp;{v_{P,A}} = {v_A} + {\omega _A} \times {r_A},{v_{P,B}} = {v_B} + {\omega _B} \times {r_B}\\
&amp;{v_{rel}} = {v_{P,B}} - {v_{P,A}}\\
&amp;{v_n} = {v_{rel}} \cdot n\\
&amp;J = jn\\
&amp;v_A' = {v_A} - \frac{j}{{{m_A}}}n,v_B' = {v_B} + \frac{j}{{{m_B}}}n\\
&amp;\omega _A' = {\omega _A} - I_A^{ - 1}\left( {{r_A} \times jn} \right),\omega _B' = {\omega _B} + I_B^{ - 1}\left( {{r_B} \times jn} \right)\\
&amp;v_{P,A}' = v_A' + \omega _A' \times {r_A},v_{P,B}' = v_B' + \omega _B' \times {r_B}\\
&amp;v_{rel}' = v_{P,B}' - v_{P,A}'\\
&amp;v_{re{l^\prime }} \cdot n = - e\left( {{v_{rel}} \cdot n} \right)\\
&amp;j = - \frac{{\left( {1 + e} \right){v_{rel}} \cdot n}}{{\frac{1}{{{m_A}}} + \frac{1}{{{m_B}}} + n \cdot \left[ {\left( {I_A^{ - 1}\left( {{r_A} \times n} \right)} \right) \times {r_A} + \left( {I_B^{ - 1}\left( {{r_B} \times n} \right)} \right) \times {r_B}} \right]}}
\end{align}
$$&lt;h2 id="62-friction"&gt;6.2 Friction:
&lt;/h2&gt;&lt;p&gt;I don&amp;rsquo;t know about this, too complicated.&lt;/p&gt;
&lt;h1 id="7-positional-correction"&gt;7. Positional Correction:
&lt;/h1&gt;&lt;p&gt;Used &lt;strong&gt;Baumgarte Stabilization Method&lt;/strong&gt; to avoid objects sink into each other, a correction directly on position with weighted mass distribution.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Correction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;NDArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;float32&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Penetration&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;SLOP&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReciprocalMass&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReciprocalMass&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Normal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Position&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;Correction&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReciprocalMass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Position&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;Correction&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReciprocalMass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;$$
\begin{align}
Correction_{n}=\beta \cdot (P-slop) \cdot \frac{\vec{n}}{m_{A}^{-1}+m_{B}^{-1}} \cdot w_{n} \\
\small where \; P \; is \; the \; max \; penetration \;,\; w_{n} =m_{n}^{-1}
\end{align}
$$&lt;hr&gt;
&lt;p&gt;The version in c++ is really similar to the version in python but have some major differences.&lt;/p&gt;
&lt;p&gt;In c++ version, I uses SAT + XPBD instead of GJK+EPA+PBD. The reason why is simple, SAT is much more easier to understand than either GJK or EPA. Just imagine a flashlight shining on two objects, if they didn&amp;rsquo;t collide, there must be at least one angle that when the flashlight is on them, the shadow they create are separate. From my personal experience of using GJK+EPA, they are too complicated to notice implementational errors in them. And huge cost of performance for them. As for XPBD, it is a better solution for the engine than PBD that&amp;rsquo;s for sure. But also much more complicated no matter the derivation of it or just implement it into the engine. The explanation for all these amazing algorithm can be found on almost every platform, I don&amp;rsquo;t think I will post blogs about any of these algorithms.&lt;/p&gt;
&lt;p&gt;Since this version is actually not even a half-baked product, no contact manifold in c++ version. This is probably the end of this project. I really like this project, I had been working on it for almost one year (during my school years of course), but it is time to move on.&lt;/p&gt;</description></item><item><title>Quaternions</title><link>https://EMEEEEMMMM.github.io/posts/quaternion/</link><pubDate>Sat, 23 May 2026 12:59:51 +0800</pubDate><guid>https://EMEEEEMMMM.github.io/posts/quaternion/</guid><description>&lt;img src="https://EMEEEEMMMM.github.io/" alt="Featured image of post Quaternions" /&gt;&lt;h1 id="complex-number"&gt;Complex Number
&lt;/h1&gt;&lt;p&gt;We call the numbers of the form $a + bi$ complex numbers.
Set consisting of all complex numbers $\mathbb{C}={a+b \mathrm{i}\mid a,b \in \mathbb{R}}$, complex number is usually represented by letter $z$, so $z=a+b\mathrm{i}(a,b \in \mathbb{R})$ where $a$ is the real part of the number and $b$ is the imaginary part. A complex number is an imaginary number introduced on top of the real numbers in one dimension, forming a two dimensional complex plane. A particular complex number is a vector in that complex plane, as follows:
&lt;img alt="Complex_Vector" class="gallery-image" data-flex-basis="313px" data-flex-grow="130" height="521" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://EMEEEEMMMM.github.io/posts/quaternion/Complex_Vector.png" width="681"&gt;&lt;/p&gt;
&lt;h2 id="operations"&gt;Operations:
&lt;/h2&gt;&lt;h3 id="addition"&gt;Addition:
&lt;/h3&gt;&lt;p&gt;Two complex number $z_{1} = a+b\mathrm{i},\ z_{2} = c+d\mathrm{i} \ (a,b,c,d \in \mathbb{R})$ , their sum is:
&lt;/p&gt;
$$
z_{1} + z_{2} = (a+b\mathrm{i})+(c+d\mathrm{i})=(a+c) + (b+d)\mathrm{i}
$$&lt;p&gt;
For any complex number:
&lt;/p&gt;
$$
\begin{align}
z_{1} + z_{2} &amp;= z_{2} + z_{1} \\
(z_{1} + z_{2}) + z_{3} &amp;= z_{1} + (z_{2} + z_{3})
\end{align}
$$&lt;h3 id="subtraction"&gt;Subtraction:
&lt;/h3&gt;&lt;p&gt;Two complex number $z_{1} = a+b\mathrm{i},\ z_{2} = c+d\mathrm{i} \ (a,b,c,d \in \mathbb{R})$ , their difference is:
&lt;/p&gt;
$$
z_{1} - z_{2} = (a+b\mathrm{i})-(c+d\mathrm{i})=(a-c) + (b-d)\mathrm{i}
$$&lt;h3 id="multiplication"&gt;Multiplication:
&lt;/h3&gt;&lt;p&gt;Two complex number $z_{1} = a+b\mathrm{i},\ z_{2} = c+d\mathrm{i} \ (a,b,c,d \in \mathbb{R})$ , their product is:
&lt;/p&gt;
$$
\begin{align}
z_{1} \cdot z_{2} &amp;= (a+b\mathrm{i}) \cdot (c+d\mathrm{i}) \\
&amp;=ac+ad\mathrm{i}+bc\mathrm{i}+bd\mathrm{i}^2 \\
&amp;=(ac-bd) + (ad+bc)\mathrm{i}
\end{align}
$$&lt;p&gt;
For any complex number:
&lt;/p&gt;
$$
\begin{align}
z_{1} z_{2} &amp;= z_{2} z_{1} \\
(z_{1} z_{2}) z_{3} &amp;= z_{1} (z_{2} z_{3}) \\
z_{1} (z_{2} + z_{3}) &amp;= z_{1} z_{2} + z_{1} z_{3}
\end{align}
$$&lt;h3 id="division"&gt;Division:
&lt;/h3&gt;&lt;p&gt;Two complex number $z_{1} = a+b\mathrm{i},\ z_{2} = c+d\mathrm{i} \ (a,b,c,d \in \mathbb{R})$ , their quotient is:
&lt;/p&gt;
$$
\begin{align}
z_{1} \div z_{2} &amp;= \frac{a+b\mathrm{i}}{c+d\mathrm{i}} \\
&amp;= \frac{(a+b\mathrm{i}) (c-d\mathrm{i})}{(c+d\mathrm{i})(c-d\mathrm{i})} \\
&amp;= \frac{ac - ad\mathrm{i} + bc\mathrm{i} + bd}{c^2+d^2} \\
&amp;= \frac{ac+bd}{c^2+d^2} + \frac{bc-ad}{c^2+d^2}\mathrm{i}
\end{align}
$$&lt;h2 id="eulers-formula"&gt;Euler&amp;rsquo;s Formula:
&lt;/h2&gt;$$
e^{i \theta} = cos(\theta) + \mathrm{i} \sin(\theta) 
$$&lt;h3 id="proof"&gt;Proof:
&lt;/h3&gt;&lt;p&gt;The MacLaurin Series for $e^x$:
&lt;/p&gt;
$$
e^x=\sum_{n=0}^{\infty} \frac{x^n}{n!}=1+x+\frac{x^2}{2}+\frac{x^3}{6}+\cdots
$$&lt;p&gt;
For $e^{\mathrm{i} \theta}$, there exist:
&lt;/p&gt;
$$
\begin{align}
LHS = e^{\mathrm{i} \theta} &amp;= \sum_{n=0}^{\infty} \frac{(\mathrm{i} \theta)^n}{n!} \\
&amp;= 1 + \mathrm{i} \theta - \frac{\theta^2}{2!} + \frac{(\mathrm{i}\theta)^3}{3!} + \frac{\theta^4}{4!} + \cdots \\
&amp;= \left(1-\frac{\theta^2}{2!} + \frac{\theta^4}{4!} - \frac{\theta^6}{6!} + \cdots \right) + \mathrm{i} \left(\theta - \frac{\theta^3}{3!} + \frac{\theta^5}{5!} - \frac{\theta^7}{7!} + \cdots \right) \\
&amp;= \cos \theta + \mathrm{i} \sin \theta \\
&amp;= RHS
\end{align}
$$&lt;h2 id="the-derivation-for-formula-of-cos-ntheta-and-sin-ntheta"&gt;The derivation for formula of $\cos n\theta$ and $\sin n\theta$:
&lt;/h2&gt;$$
\begin{align}
\left(e^{\mathrm{i} \theta}\right)^{n} =e^{\mathrm{i}n\theta} &amp;= \cos n\theta + \mathrm{i} \sin n\theta \\
\left( \cos \theta + \mathrm{i} \sin \theta \right)^{n} &amp;= \cos n\theta + \mathrm{i} \sin n\theta \\
\cos n\theta + \mathrm{i} \sin n\theta &amp; = \sum_{k=0}^{n} \binom{n}{k} \left( \cos \theta \right)^{n-k} \left( \mathrm{i} \sin \theta \right)^k
\end{align}
$$&lt;p&gt;
Extract the real and imaginary parts of the expansion separately:
&lt;/p&gt;
$$
\begin{align}
\cos n\theta &amp;= \sum_{k=0}^{n} \binom{n}{2k} (\cos \theta)^{n-2k} (\mathrm{i} \sin \theta)^{2k} \\
&amp;= \sum_{k=0}^{n} \binom{n}{2k} (-1)^k (\cos \theta)^{n-2k} (\sin \theta)^{2k} \\
\mathrm{i} \sin n\theta &amp;= \sum_{k=0}^{n} \binom{n}{2k+1} (\cos \theta)^{n-2k-1} (\mathrm{i})^{2k+1} (\sin \theta)^{2k+1} \\
&amp;= \mathrm{i} \sum_{k=0}^{n} \binom{n}{2k+1} (\cos \theta)^{n-2k-1} (-1)^k (\sin \theta)^{2k+1} \\
\end{align}
$$&lt;p&gt;
&lt;/p&gt;
$$
\therefore \quad
\begin{cases}
\cos n\theta &amp;= \sum_{k=0}^{n} \binom{n}{2k} (-1)^k (\cos \theta)^{n-2k} (\sin \theta)^{2k} \\
\sin n\theta &amp;= \sum_{k=0}^{n} \binom{n}{2k+1}(-1)^k (\cos \theta)^{n-2k-1} (\sin \theta)^{2k+1} \\
\end{cases}
$$&lt;h3 id="chebyshev-polynomials"&gt;Chebyshev polynomials:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://zhuanlan.zhihu.com/p/55076525" target="_blank" rel="noopener"
 &gt;https://zhuanlan.zhihu.com/p/55076525&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="quaternions"&gt;Quaternions
&lt;/h1&gt;&lt;p&gt;In complex numbers, the multiplication can represent the rotation in 2 dimensional space. For example, by rotating a vector $(a, bi)$ for $30 \degree$, just multiply it by $\cos 30 \degree + \mathrm{i} \sin 30 \degree$. But in three dimensional space, we need something that is stronger than complex numbers since that rotate about the x axis first and then rotate about the y axis is not equal to rotate about the y axis first and then rotate about the x axis, we need a algebraic system which does not satisfy commutative multiplication and is able to describe rotation in 3 dimensional space. So, the hypercomplex number, quaternions is just the right tool to use.&lt;/p&gt;
&lt;h2 id="definition"&gt;Definition:
&lt;/h2&gt;&lt;p&gt;The numbers in the form of:
&lt;/p&gt;
$$
q = a + b \mathrm{i} + c \mathrm{j} + d \mathrm{k} (a,b,c,d \in \mathbb{R})
$$&lt;h2 id="basic-properties"&gt;Basic properties:
&lt;/h2&gt;$$
\begin{align}
i^2 = j^2 = k^2 = -1 \\
ij = k, ji = -k, jk = i, kj = -i, ki = j, ik = -j
\end{align}
$$&lt;p&gt;For any quaternions, their conjugate is given by:
&lt;/p&gt;
$$
q = a - b \mathrm{i} - c \mathrm{j} - d \mathrm{k}
$$&lt;h2 id="operations-1"&gt;Operations:
&lt;/h2&gt;&lt;h3 id="addition-1"&gt;Addition:
&lt;/h3&gt;&lt;p&gt;For two quaternions $q = a + b \mathrm{i} + c \mathrm{j} + d \mathrm{k}$ and $p = t + x \mathrm{i} + y \mathrm{j} + z \mathrm{k}$, their sum is:
&lt;/p&gt;
$$
q+p = (a+t) + (b+x) \mathrm{i} + (c+y) \mathrm{j} + (d+z) \mathrm{k}
$$&lt;p&gt;
For any quaternions:
&lt;/p&gt;
$$
\begin{align}
q_{1} + q_{2} &amp;= q_{2} + q_{1} \\
(q_{1} + q_{2}) + q_{3} &amp;= q_{1} + (q_{2} + q_{3})
\end{align}
$$&lt;h3 id="subtraction-1"&gt;Subtraction:
&lt;/h3&gt;&lt;p&gt;For two quaternions $q = a + b \mathrm{i} + c \mathrm{j} + d \mathrm{k}$ and $p = t + x \mathrm{i} + y \mathrm{j} + z \mathrm{k}$, their difference is:
&lt;/p&gt;
$$
q-p = (a-t) + (b-x) \mathrm{i} + (c-y) \mathrm{j} + (d-z) \mathrm{k}
$$&lt;h3 id="multiplication-1"&gt;Multiplication:
&lt;/h3&gt;&lt;p&gt;For two quaternions $q = a + b \mathrm{i} + c \mathrm{j} + d \mathrm{k}$ and $p = t + x \mathrm{i} + y \mathrm{j} + z \mathrm{k}$, their product is:
&lt;/p&gt;
$$
\begin{align}
q \cdot p &amp;= (a + b \mathrm{i} + c \mathrm{j} + d \mathrm{k}) (t + x \mathrm{i} + y \mathrm{j} + z \mathrm{k}) \\
&amp;= at - bx - cy - dz \\
&amp;+ (ax+bt+cz-dy) \mathrm{i} \\
&amp;+ (ay-bz+ct+dx) \mathrm{j} \\
&amp;+ (az+by-cx+dt) \mathrm{k}
\end{align}
$$&lt;p&gt;Quaternions can also be expressed by a much simpler way:
$q = a + b \mathrm{i} + c \mathrm{j} + d \mathrm{k} = (a, \vec{a})$, where $\vec{a} = (b, c, d)$.
In this way, the multiplication would become:
&lt;/p&gt;
$$
\begin{align}
q \cdot p &amp;= (a + b \mathrm{i} + c \mathrm{j} + d \mathrm{k}) (t + x \mathrm{i} + y \mathrm{j} + z \mathrm{k}) \\
&amp;= (a, \vec{a}) (t, \vec{t}) \\
&amp;= (at - \vec{a} \cdot \vec{t}, a \vec{t} + t \vec{a} + \vec{a} \times \vec{t})
\end{align}
$$&lt;h2 id="rotation"&gt;Rotation:
&lt;/h2&gt;&lt;p&gt;We call the quaternions which have a zero real part the Pure Quaternions. For any vector in 3 dimensional space, we can plug it in a pure quaternion $q$:
&lt;/p&gt;
$$
q = (0, \vec{v}) = 0 + x \mathrm{i} + y \mathrm{j} + z \mathrm{k}
$$&lt;p&gt;
Let&amp;rsquo;s say that we are rotating about a unit vector $\hat{u}$ for $\theta$ angle. Imitate the way of the complex number where we multiply a $\cos \theta + \mathrm{i} \sin \theta$, we construct a similar quaternion:
&lt;/p&gt;
$$
q = (\cos \theta, \sin \theta \hat{u})
$$&lt;p&gt;
If we completely follow the steps of the rotation of the complex number, trying to multiply a pure quaternion:
&lt;/p&gt;
$$
\begin{align}
p \prime &amp;= (\cos \theta, \sin \theta \hat{u}) \cdot (0, \vec{v}) \\
&amp;= (0 - \sin \theta (\hat{u} \cdot \vec{v}), \cos \theta \vec{v} + \sin \theta (\hat{u} \times \vec{v}))
\end{align}
$$&lt;p&gt;
But the real part of this quaternion is not zero which means that unless $\hat{u} \cdot \vec{v} = 0$, the quaternion $p \prime$ won&amp;rsquo;t become a pure quaternion. This means that this equation is unable to handle most of the rotations in 3 dimensional space. We need to multiply another thing to cancel out the non-zero real part.&lt;/p&gt;
&lt;p&gt;Let $q$ be a unit quaternion, $v = (0, \vec{v})$ be a pure quaternion, $v\prime = (0, \vec{v}\prime)$ be the pure quaternion after the rotation. Expand and calculate:
&lt;/p&gt;
$$
\begin{align}
v\prime = qvq^{-1} &amp;= qvq^* \\
&amp;= (s_{q}, \vec{v_{q}}) \cdot (0, \vec{v}) \cdot (s_{q}, -\vec{v_{q}}) \\
&amp;= (- \vec{v_{q}} \cdot \vec{v}, s_{q} \vec{v} + \vec{v_{q}} \times \vec{v}) \cdot (s_{q}, -\vec{v_{q}}) \\
\mathrm{Re}(v\prime) &amp;= s_{q} \cdot (- \vec{v_{q}} \cdot \vec{v}) - (-\vec{v_{q}}) \cdot (s_q \vec{v} + \vec{v_{q}} \times \vec{v}) = 0 \\
\vec{v}\prime &amp;= (-\vec{v_q} \cdot \vec{v}) \cdot (-\vec{v_q}) + s_q \cdot (s_q \vec{v} + \vec{v_q} \times \vec{v}) + (s_q \vec{v} + \vec{v_q} \times \vec{v}) \times (-\vec{v_q}) \\
&amp;= (\vec{v_q} \vec{v}) \cdot \vec{v_q} + s_q^2 \vec{v} + s_q \cdot (\vec{v_q} \times \vec{v}) - s_q (\vec{v} \times \vec{v_q}) - (\vec{v_q} \times \vec{v}) \times \vec{v_q} \\
&amp;= (\vec{v_q} \vec{v}) \cdot \vec{v_q} + s_q^2 \vec{v} + s_q \cdot (\vec{v_q} \times \vec{v}) + s_q (\vec{v_q} \times \vec{v}) - (\vec{v_q} \cdot \vec{v_q}) \cdot \vec{v} + (\vec{v} \cdot \vec{v_q}) \cdot \vec{v_q} \\
&amp;= (s_q^2 - \lvert \lvert \vec{v_q} \rvert \rvert ^2) \vec{v} + 2 s_q (\vec{v_q} \times \vec{v}) + 2(\vec{v} \cdot \vec{v_q}) \cdot \vec{v_q}
\end{align}
$$&lt;p&gt;
So, the full expression for $v\prime$:
&lt;/p&gt;
$$
v\prime = qvq^{-1} = qvq^* = (0, (s_q^2 - \lvert \lvert \vec{v_q} \rvert \rvert ^2) \vec{v} + 2 s_q (\vec{v_q} \times \vec{v}) + 2(\vec{v} \cdot \vec{v_q}) \cdot \vec{v_q})
$$&lt;p&gt;
Now, we need to derive if $q$ express rotate about the rotation axis $u$ of $\theta$ degrees, what is the expression of $s_q$ and $v_q$.&lt;/p&gt;
&lt;p&gt;The imaginary part vector of a quaternion must be in the same direction with the rotation axis.
&lt;/p&gt;
$$
\vec{v_q} = k\vec{u} (k \in \mathbb{R})
$$&lt;p&gt;
Because of $q$ is a unit quaternion, there is $s_q^2 + \lvert\lvert v_q \rvert\rvert^2=s_q^2 + k^2=1$.
Now, we break down the vector $\vec{v}$ into two parts:
&lt;/p&gt;
$$
\vec{v} = \vec{v_{\lvert\lvert}} + \vec{v_\perp}
$$&lt;ul&gt;
&lt;li&gt;$\vec{v_{\lvert\lvert}}$ is collinear with $\vec{u}$, satisfying $\vec{v_{\lvert\lvert}} = (\vec{u}\cdot\vec{v})\cdot\vec{u}$.&lt;/li&gt;
&lt;li&gt;$\vec{v_\perp}$ is orthogonal to $\vec{u}$, meaning $\vec{u} \cdot \vec{v_\perp} = 0$.
First, sub $\vec{v_{\lvert\lvert}}$ into the expression of $\vec{v}\prime$:

$$
\begin{align}
\vec{v_{\lvert\lvert}}\prime &amp;= (s_q^2 - \lvert \lvert \vec{v_q} \rvert \rvert ^2) \vec{v_{\lvert\lvert}} + 2 s_q (\vec{v_q} \times \vec{v_{\lvert\lvert}}) + 2(\vec{v_{\lvert\lvert}} \cdot \vec{v_q}) \cdot \vec{v_q} \\
&amp;= (s_q^2 - k^2) \vec{v_{\lvert\lvert}} + 0 + 2k^2 \vec{v_{\lvert\lvert}} \\
&amp;= (s^2_q + k^2) \vec{v_{\lvert\lvert}} \\
&amp;= \vec{v_{\lvert\lvert}}
\end{align}
$$
This means that component which is parallel to the rotation axis remains completely undisturbed by the operation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Second, sub $\vec{v_\perp}$ into the expression:
&lt;/p&gt;
$$
\begin{align}
\vec{v_\perp}\prime &amp;= (s_q^2 - \lvert \lvert \vec{v_q} \rvert \rvert ^2) \vec{v_\perp} + 2 s_q (\vec{v_q} \times \vec{v_\perp}) + 2(\vec{v_\perp} \cdot \vec{v_q}) \cdot \vec{v_q} \\
&amp;= (s_q^2 - k^2) \vec{v_\perp} + 2s_q(k \vec{u} \times \vec{v_\perp}) + 0 \\
&amp;= (s_q^2 - k^2) \vec{v_\perp} + 2s_q k (\vec{u} \times \vec{v}) 
\end{align}
$$&lt;p&gt;
Combines all these above together, the overall vector after the quaternion operation is:
&lt;/p&gt;
$$
\vec{v} \prime = \vec{v_{\lvert\lvert}} + (s_q^2 - k^2) \vec{v_\perp} + 2s_q k (\vec{u} \times \vec{v}) 
$$&lt;p&gt;
Now, we overlay the standard Rodrigues&amp;rsquo; Rotation Formula which dictates that a vector rotating around a unit axis $\vec{u}$ by a angle of $\theta$ behaves according to:
&lt;/p&gt;
$$
\vec{v} \prime = \vec{v_{\lvert\lvert}} + \cos \theta \vec{v_\perp} + \sin \theta (\vec{u} \times \vec{v})
$$&lt;p&gt;
By directly comparing the corresponding coefficients of our algebraic result against the geometric target:
&lt;/p&gt;
$$
\begin{cases}
s_q^2 - k^2 = \cos \theta \\
2s_qk = \sin \theta
\end{cases}
$$&lt;p&gt;
It is not hard to notice that the solution matches the standard trigonometric double-angle identities where:
&lt;/p&gt;
$$
\begin{align}
\cos \theta = \cos^2(\frac{\theta}{2}) - \sin^2(\frac{\theta}{2}) \\
\sin \theta = 2 \sin(\frac{\theta}{2}) \cos(\frac{\theta}{2})
\end{align}
$$&lt;p&gt;
Matching the terms explicitly yields the values for the scalar and vector scale factors of the quaternion:
&lt;/p&gt;
$$
s_q = \cos(\frac{\theta}{2}), k = \sin(\frac{\theta}{2})
$$&lt;p&gt;
So, substituting back these values into our initial definition $q = (s_q, \vec{v_q}) = (s_q, k \vec{u})$, we get the axis-angle rotation quaternion formula used universally in computer graphics and physics simulators:
&lt;/p&gt;
$$
q = \left[ \cos\left(\frac{\theta}{2}\right), \sin\left(\frac{\theta}{2}\right) \vec{u} \right]
$$&lt;h1 id="reference"&gt;Reference:
&lt;/h1&gt;&lt;ol&gt;
&lt;li&gt;[1] Yan-Bin Jia, Quaternions and Rotations. Com S 477/577 Course Notes, Iowa State University / Stanford Graphics Lab, 2013.
(&lt;a class="link" href="https://graphics.stanford.edu/courses/cs348a-17-winter/Papers/quaternion.pdf" target="_blank" rel="noopener"
 &gt;https://graphics.stanford.edu/courses/cs348a-17-winter/Papers/quaternion.pdf&lt;/a&gt;)&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>Narrow Phase: GJK and EPA</title><link>https://EMEEEEMMMM.github.io/posts/gjkandepa/</link><pubDate>Sat, 02 May 2026 12:18:31 +0800</pubDate><guid>https://EMEEEEMMMM.github.io/posts/gjkandepa/</guid><description>&lt;img src="https://EMEEEEMMMM.github.io/" alt="Featured image of post Narrow Phase: GJK and EPA" /&gt;&lt;h1 id="narrow-phase-collision-detection-gjk-and-epa"&gt;Narrow Phase Collision Detection: GJK and EPA:
&lt;/h1&gt;&lt;p&gt;The narrow phase of the engine consists of two parts: Gilbert-Johnson-Keerthi algorithm (GJK) and Expanding Polytope algorithm (EPA). GJK tells you about whether the two object is colliding and the terminal simplex of the two objects&amp;rsquo; Minkowski difference. EPA tells you about the normal of the contact point and the depth of the collision.&lt;/p&gt;
&lt;h2 id="gjk"&gt;GJK:
&lt;/h2&gt;&lt;p&gt;The GJK does not operate directly on the polygons themselves. Instead, it operates on the mathematical abstraction know as the Minkowski Difference.&lt;/p&gt;
&lt;h3 id="minkowski-sums--differences"&gt;Minkowski Sums / Differences
&lt;/h3&gt;&lt;h4 id="sum"&gt;Sum:
&lt;/h4&gt;$${\rm{A}} \oplus B = \left\{ {a + b|a \in A,b \in B} \right\}$$&lt;h4 id="difference"&gt;Difference:
&lt;/h4&gt;$${\rm{A}} \ominus B = \left\{ {a + \left( { - {\rm{b}}} \right)|a \in A,b \in B} \right\}$$&lt;h4 id="properties"&gt;Properties:
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Preservation of Convexity:&lt;/strong&gt; If objects A and B are convex, their Minkowski difference $A \ominus B$ is strictly convex.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Intersection Equivalence:&lt;/strong&gt; Objects A and B intersect if and only if the origin vector is contained within their Minkowski difference, i.e., $(0,0) \in A \ominus B$.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="support-function2-dimension"&gt;Support function(2 dimension):
&lt;/h3&gt;&lt;p&gt;Instead of explicitly calculating the entire, complex Minkowski difference which is theoretically infinite, GJK relies on a &lt;em&gt;Support Function&lt;/em&gt; to sample it iteratively.&lt;/p&gt;
&lt;p&gt;C(Minkowski Sum):
&lt;/p&gt;
$$C = A \oplus B $$&lt;p&gt;
The furthest point on A in the direction of ${\vec d}$:
&lt;/p&gt;
$$ {s_A}\left( {\vec d} \right) \to \left( {{x_A},{y_A}} \right) $$&lt;p&gt;
The furthest point on B in the direction of ${-\vec d}$:
&lt;/p&gt;
$${s_B}\left( {-\vec d} \right) \to \left( {{x_B},{y_B}} \right) $$&lt;p&gt;
Therefore, a point $S_{A \ominus B} (d)$, we compute:
&lt;/p&gt;
$$ {s_C}\left( {\vec d} \right) = {s_A}\left( {\vec d} \right) - {s_B}\left( {- \vec d} \right) \to \left( {{x_C},{y_C}} \right) $$&lt;p&gt;
&lt;img alt="Notes" class="gallery-image" data-flex-basis="320px" data-flex-grow="133" height="6144" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://EMEEEEMMMM.github.io/posts/gjkandepa/IMG_20260213_154637.jpg" srcset="https://EMEEEEMMMM.github.io/posts/gjkandepa/IMG_20260213_154637_hu_29e16e6fe08f7158.jpg 800w, https://EMEEEEMMMM.github.io/posts/gjkandepa/IMG_20260213_154637_hu_bd4682a8a25dfd09.jpg 1600w, https://EMEEEEMMMM.github.io/posts/gjkandepa/IMG_20260213_154637_hu_bc94e72f21a59986.jpg 2400w, https://EMEEEEMMMM.github.io/posts/gjkandepa/IMG_20260213_154637.jpg 8192w" width="8192"&gt;
To judge whether the simplex contains the origin, there is a classification for the linear, triangle, tetrahedral cases.&lt;/p&gt;
&lt;p&gt;The logic of the implementation of the support function in my prototype of the engine follows the following steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Get the object&amp;rsquo;s model matrix. The matrix contains the object&amp;rsquo;s current # ! Position, Rotation and Scale&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Convert the direction from the World Space -&amp;gt; Local Space. Create a 4D vector for the direction (w = 0 means that it is a direction instead of a point). Multiply the direction by the tranpose of the matrix. Local direction = Direction * Transpose of matrix&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Find the furthest point in local direction&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Convert the point from Local Space -&amp;gt; World Space. Create a 4D vector for the point(w = 1 means the it is a point instead of a direction). World Point = Matrix * Point&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Repeat the above operation on two object. The result point will be Point A - Point B.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="simplex-evolution-and-the-origin-check"&gt;Simplex Evolution and the Origin Check
&lt;/h3&gt;&lt;p&gt;GJK iteratively builds a simplex (a point, line segment, triangle, or tetrahedron) inside the Minkowski Difference to enclose the origin. To judge whether the simplex contains the origin, there is a distinct classification for the linear, triangle, and tetrahedral cases.&lt;/p&gt;
&lt;h4 id="linear-case"&gt;Linear case:
&lt;/h4&gt;&lt;p&gt;After the initialization, the simplex should contains two points. In 3D space the probability of the origin in a line segment is 0, so the method takes the role of updating the direction variable and returns &lt;em&gt;False&lt;/em&gt;.
Simplex = [B, A] a line segment where A is the latest point added in.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If the dot product $\vec{AB} \cdot \vec{AO} &amp;gt; 0$, the origin lies in the region perpendicular to the segment. The search direction is updated as $\vec{AB} \times (\vec{AO} \times \vec{AB})$, which yields a vector perpendicular to $\vec{AB}$ pointing towards the origin.&lt;/li&gt;
&lt;li&gt;Else, delete point A and update the direction as $\vec{AO}$. In this case, point B is not helpful to find a closer point to the origin than A. This makes the geometric result discrete. Finally, the iteration returns &lt;em&gt;False&lt;/em&gt;, and a new point is searched. In 3D space, the probability of the origin lying exactly on a line segment is near 0.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="triangle-case"&gt;Triangle case:
&lt;/h4&gt;&lt;p&gt;Simplex = $[C, B, A]$, forming a triangle. The goals at this stage are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Judge whether the triangle contains the origin.&lt;/li&gt;
&lt;li&gt;If not, trim the simplex into a line segment and update the direction.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The core logic requires determining the region the origin resides in:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Determine which side of the plane the triangle is located relative to the origin.&lt;/li&gt;
&lt;li&gt;Determine whether the origin is outside which specific edge of the triangle. This is achieved using edge normals (e.g., $\vec{AB}^\perp = \vec{AB} \times \vec{ABC}$ where $\vec{ABC}$ is the triangle&amp;rsquo;s surface normal).&lt;/li&gt;
&lt;li&gt;If the origin is outside an edge (e.g., $\vec{AC}$), reduce the triangle to a line segment (keep A and C), update the search direction orthogonal to that edge, and continue the iteration. If it is contained within all edge boundaries, we proceed to 3D analysis or return &lt;em&gt;True&lt;/em&gt; (for 2D).&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="tetrahedral-case"&gt;Tetrahedral case:
&lt;/h4&gt;&lt;p&gt;Simplex = $[D, C, B, A]$, forming a tetrahedral structure.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Calculate the normal vector of each of the four faces. (Ensure normals point outward from the tetrahedron&amp;rsquo;s center).&lt;/li&gt;
&lt;li&gt;Determine whether the origin is on the outside of each face. (Evaluated via dot product: $\vec{Normal} \cdot \vec{AO} &amp;gt; 0$).&lt;/li&gt;
&lt;li&gt;If the origin is on the outside of any face, trim the point which is not on that face. Pass the newly reduced simplex (a triangle) back to the triangle case logic, and return &lt;em&gt;False&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;If the origin is on the inside of all the faces, the tetrahedral definitively contains the origin. The function returns &lt;em&gt;True&lt;/em&gt;, signaling an intersection.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="epa"&gt;EPA:
&lt;/h2&gt;&lt;p&gt;Once GJK returns &lt;em&gt;True&lt;/em&gt;, we have an intersecting simplex. However, GJK cannot calculate penetration depth. The core logic of EPA here is to geometrically expand the simplex that GJK returns to approach the actual boundary of the Minkowski difference of the two objects. The minimum distance from the origin to this boundary represents the penetration depth and collision normal.&lt;/p&gt;
&lt;h3 id="iterative-expansion-logic"&gt;Iterative Expansion Logic:
&lt;/h3&gt;&lt;p&gt;The standard EPA pipeline proceeds as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Find the Closest Feature:&lt;/strong&gt; Obtain the edge (in 2D) or face (in 3D) of the simplex with the shortest perpendicular distance to the origin. Denote the corresponding Minkowski difference vertices of this edge as $M_1, M_2$. Find the normal vector perpendicular to this edge and directed away from the origin.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Support Point Sampling:&lt;/strong&gt; Calculate a new Minkowski difference support point, $M_3$, by evaluating the support function along this normal direction.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Collinearity/Convergence Check:&lt;/strong&gt; If $\left| M_1 - M_3 \right| + \left| M_2 - M_3 \right| &amp;lt; \epsilon$, exit the iteration. &lt;em&gt;(Academic Note: This condition checks if $M_3$ lies exactly on the segment $M_1 M_2$. In practice, standard 3D EPA checks if the dot product of $M_3$ along the normal is minimally larger than the distance to the face).&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Directional Progress Check:&lt;/strong&gt; If $M_3$ does not belong to the furthest point found in the direction (i.e., no significant progress is made outward), exit the iteration. The current distance to the feature is the penetration depth.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Duplication Check:&lt;/strong&gt; If $M_1 = M_3$ or $M_2 = M_3$, indicating a repetition in the existing simplex, exit the iteration. The algorithm has found the true boundary.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Expansion:&lt;/strong&gt; If the checks pass, split the closest edge/face by inserting $M_3$, creating new edges/faces, and repeat the process from Step 1 until the exact boundary is met.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="implementation"&gt;Implementation
&lt;/h2&gt;&lt;p&gt;The full implementation of GJK and EPA can be find at &lt;a class="link" href="https://github.com/EMEEEEMMMM/AtlasPhys/blob/main/prototype_python/utils/GJK.py" target="_blank" rel="noopener"
 &gt;https://github.com/EMEEEEMMMM/AtlasPhys/blob/main/prototype_python/utils/GJK.py&lt;/a&gt; and &lt;a class="link" href="https://github.com/EMEEEEMMMM/AtlasPhys/blob/main/prototype_python/utils/EPA.py" target="_blank" rel="noopener"
 &gt;https://github.com/EMEEEEMMMM/AtlasPhys/blob/main/prototype_python/utils/EPA.py&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The visualization of GJK made by AI.
&lt;div class="interactive-canvas-wrap" style="position:relative;width:100%;padding-top:62.5%;"&gt;
 &lt;canvas id="gjk3dCanvas" class="interactive-canvas" style="position:absolute;inset:0;width:100%;height:100%;display:block;"&gt;&lt;/canvas&gt;
&lt;/div&gt;&lt;script src="https://EMEEEEMMMM.github.io/js/gjk-demo.js" defer&gt;&lt;/script&gt;
&lt;script defer&gt;
window.addEventListener('load', function () {
 const id = "gjk3dCanvas";
 const c = document.getElementById(id);
 if (!c) return;
 const p = c.parentElement;
 function fit() {
 const w = p.clientWidth;
 const h = p.clientHeight || Math.max(window.innerHeight * 0.5, 300);
 c.style.width = '100%';
 c.style.height = '100%';
 try { c.width = w; c.height = h; } catch (e) {}
 window.dispatchEvent(new Event('resize'));
 }
 fit();
 if (typeof ResizeObserver !== 'undefined') {
 try { new ResizeObserver(fit).observe(p); } catch (e) {}
 }
 window.addEventListener('resize', fit);
});
&lt;/script&gt;&lt;/p&gt;
&lt;div style="text-align: center; margin-top: -1rem; margin-bottom: 2rem;"&gt;
 &lt;button id="nextStepBtn" style="padding: 0.6rem 1.5rem; background: #2563eb; color #fff; border: none; border-radius: 6px; cursor: pointer; font-weight: bold;"&gt;Next Step &lt;/button&gt;
&lt;/div&gt;</description></item><item><title>Math Notes</title><link>https://EMEEEEMMMM.github.io/posts/mathnotes/</link><pubDate>Tue, 28 Apr 2026 17:40:36 +0800</pubDate><guid>https://EMEEEEMMMM.github.io/posts/mathnotes/</guid><description>&lt;img src="https://EMEEEEMMMM.github.io/" alt="Featured image of post Math Notes" /&gt;&lt;h1 id="trigonometry"&gt;Trigonometry:
&lt;/h1&gt;$$
\begin{align}
&amp; \sin x = \frac{1}{\csc x} \\
&amp; \cos x = \frac{1}{\sec x} \\
&amp; \tan x = \frac{1}{\cot x} \\
&amp; \tan^2 \theta + 1 = \sec^2 \theta \\
&amp; \cot^2 \theta + 1 = \csc^2 \theta \\
&amp; \arcsin x + \arccos x = \frac{\pi}{2} \\
&amp;f(x)=\arctan x + \arctan \frac{1}{x}=\begin{cases}
\frac{\pi}{2}, x &gt; 0 \\
-\frac{\pi}{2}, x &lt; 0
\end{cases}
\end{align}
$$&lt;h1 id="limits"&gt;Limits:
&lt;/h1&gt;$$
\begin{align}
\lim_{x \to 0} \frac{\sin (x)}{x} &amp;= 1 \\
e = \lim_{x \to \infty} (1+\frac{1}{x})^x&amp;=\lim_{x \to 0^+} (1+x)^{\frac{1}{x}} \\
\end{align}
$$&lt;h1 id="derivative-and-integral"&gt;Derivative and Integral:
&lt;/h1&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Derivative&lt;/th&gt;
 &lt;th&gt;Integral&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;$$\frac{d}{dx}x^n = nx^{n-1} $$&lt;/td&gt;
 &lt;td&gt;$$\int x^n dx= \frac{1}{n+1} x^{n+1} + C$$&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;$$\frac{d}{dx} \sin x = \cos x$$&lt;/td&gt;
 &lt;td&gt;$$\int \cos x \ dx = \sin x + C$$&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;$$\frac{d}{dx} \cos x = - \sin x$$&lt;/td&gt;
 &lt;td&gt;$$\int \sin x \ dx = - \cos x + C$$&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;$$\frac{d}{dx}\ln(x) = \frac{1}{x}$$&lt;/td&gt;
 &lt;td&gt;$$\int \frac{1}{x} dx = \ln \lvert x \rvert + C$$&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;$$\frac{d}{dx} e^x = e^x$$&lt;/td&gt;
 &lt;td&gt;$$\int e^x dx = e^x + C$$&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;$$\frac{d}{dx} a^x = a^x \times \ln a$$&lt;/td&gt;
 &lt;td&gt;$$\int a^x dx=\frac{a^x}{\ln(a)} + C, a&gt;0,a\neq1$$&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;$$\frac{d}{dx} \tan x=\sec^2 x$$&lt;/td&gt;
 &lt;td&gt;$$\int \sec^2 x \ dx = \tan x + C$$&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;$$\frac{d}{dx} \cot x = -csc^2x$$&lt;/td&gt;
 &lt;td&gt;$$\int \csc^2 x \ dx = - \cot x + C$$&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;$$\frac{d}{dx} \sec x = \sec x \cdot \tan x$$&lt;/td&gt;
 &lt;td&gt;$$\int \sec x \cdot \tan x \ dx = \sec x + C$$&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;$$\frac{d}{dx} \csc x = - \csc x \cdot \cot x$$&lt;/td&gt;
 &lt;td&gt;$$\int \csc x \cdot \cot x \ dx = - \csc x + C $$&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;$$\frac{d}{dx} \arcsin x = \frac{1}{\sqrt{ 1-x^2 }}$$&lt;/td&gt;
 &lt;td&gt;$$\int \frac{1}{\sqrt{1-x^2}}dx=\arcsin x + C$$&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;$$\frac{d}{dx} \arccos x = - \frac{1}{\sqrt{ 1-x^2 }}$$&lt;/td&gt;
 &lt;td&gt;$$\int -\frac{1}{\sqrt{1-x^2}}dx = \arccos x + C$$&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;$$\frac{d}{dx} \arctan x = \frac{1}{1+x^2}$$&lt;/td&gt;
 &lt;td&gt;$$\int \frac{1}{1+x^2}dx = \arctan x + C$$&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;$$\frac{d}{dx} sec^{-1} x = \frac{1}{\lvert x \rvert \sqrt{x^2 - 1}}$$&lt;/td&gt;
 &lt;td&gt;$$\int \frac{1}{\lvert x \rvert \sqrt{x^2-1}}dx = sec^{-1}x + C$$&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="more-integration-formula"&gt;More Integration Formula:
&lt;/h2&gt;$$
\begin{align}
\int \tan x \ dx &amp;= \ln \lvert \sec x \rvert + C \ or \ -\ln\lvert \cos x \rvert + C \\
\int \cot x \ dx &amp;= \ln \lvert \sin x \rvert + C \ or \ -\ln\lvert \csc x \rvert + C \\
\int \sec x \ dx &amp;= \ln \lvert \sec x + \tan x \rvert + C \\
\int \csc x \ dx &amp;= \ln \lvert \csc x - \cot x \rvert + C \\
\int \ln x \ dx &amp;= x \ \ln \lvert x \rvert - x + C \\
\int \frac{1}{\sqrt{a^2-x^2}} dx &amp;= \arcsin(\frac{x}{a}) + C \\
\int \frac{1}{a^2+x^2} dx &amp;= \frac{1}{a} \arctan (\frac{x}{a}) + C \\
\int \frac{1}{x{\sqrt{x^2-a^2}}} dx &amp;= \frac{1}{a} \sec^{-1}\lvert\frac{x}{a} \rvert + C \ or \ \frac{1}{a} \arccos \lvert \frac{a}{x} \rvert + C \\
\int \sin^2 x \ dx &amp;= \frac{x}{2} - \frac{\sin 2x}{4} + C
\end{align}
$$&lt;h2 id="u-substitution-method"&gt;U-Substitution Method:
&lt;/h2&gt;&lt;p&gt;If $f(g(x))$ and $f \prime$ are continuous and $F \prime = f$, then
&lt;/p&gt;
$$\int f(g(x))g\prime(x)dx = F(g(x)) + C$$&lt;p&gt;
Let $u=g(x)$, then $du = g \prime (x) dx$:
&lt;/p&gt;
$$\int f(g(x))g\prime(x)dx = \int f(u) du = F(u) + C = F(g(x)) + C$$&lt;h2 id="integration-by-parts"&gt;Integration by Parts:
&lt;/h2&gt;&lt;p&gt;According to the product rule for differentiation:
&lt;/p&gt;
$$
\frac{d}{dx} (uv) = u \frac{dv}{dx} + v \frac{du}{dx}
$$&lt;p&gt;
Integrating tells us that:
&lt;/p&gt;
$$
uv = \int u \frac{dv}{dx} + \int v \frac{du}{dx}
$$&lt;p&gt;
Therefore:
&lt;/p&gt;
$$
\int u \frac{dv}{dx} = uv - \int v \frac{du}{dx}
$$&lt;h2 id="trigonometrical-substitution"&gt;Trigonometrical substitution:
&lt;/h2&gt;&lt;p&gt;Find:
&lt;/p&gt;
$$I = \int \sqrt{a^2-x^2}dx, a \geq 0$$&lt;p&gt;
First, solve the inequality:
&lt;/p&gt;
$$
\begin{align*} \\
a^2 - x^2 &amp;\ge 0 \\
\implies x^2 &amp;\le a^2 \\
\implies -a &amp;\le x \le a
\end{align*}
$$&lt;p&gt;Second, substitute x with a trigonometric function and solve the integral:
Let $x=a \sin t$, $t \in \left[-\frac{\pi}{2},\frac{\pi}{2} \right]$, then $dx = a \cdot \cos t dt$
&lt;/p&gt;
$$
\begin{align}
I &amp;= \int \sqrt{a^2 - (a \sin t)^2} a \cdot \cos t dt \\
&amp;= \int \sqrt{a^2(1-\sin^2 t)} a \cdot \cos t dt \\
&amp;= \int a^2 \cdot \cos^2 t \ dt \\
&amp;= a^2 \int \frac{\cos (2t) + 1}{2} dt \\
&amp;= a^2 \int \frac{1}{2} \cos 2t + \frac{1}{2} dt \\
&amp;= \frac{a^2}{2} \sin t \cdot \cos t + \frac{a^2}{2} \cdot t + C
\end{align}
$$&lt;p&gt;
Third, substitute x back into the expression by imagining a &amp;ldquo;fake&amp;rdquo; triangle:
&lt;/p&gt;
$$
\begin{align}
I &amp;= \frac{x}{2} \sqrt{a^2 - x^2} + \frac{a^2}{2} \arcsin (\frac{x}{a}) + C
\end{align}
$$&lt;h2 id="integration-by-partial-fractions"&gt;Integration by Partial Fractions:
&lt;/h2&gt;&lt;p&gt;Factor the denominator of the function, list the equations and solve them using the undetermined coefficient method. The big function will be split into two or more small functions which are easier to integrate than a whole big function.&lt;/p&gt;
&lt;h1 id="first-fundamental-theorems-of-calculus"&gt;First-Fundamental Theorems of Calculus:
&lt;/h1&gt;&lt;p&gt;If $f$ is continuous on $[a, b]$ and $F$ is an anti derivative of $f$ on $[a, b]$, then
&lt;/p&gt;
$$
\begin{align}
&amp;\int_a^b f(x) dx = F(b) - F(a) \\
&amp;Note: \ F(b) - F(a) \ is \ often \ denoted \ as [F(x)]^b_a
\end{align}
$$&lt;h1 id="area-between-two-curves"&gt;Area Between Two curves:
&lt;/h1&gt;$$
\begin{align}
A = \int^b_a(upper \ curve - lower \ curve) dx
\end{align}
$$&lt;h1 id="volumes-and-definite-integrals"&gt;Volumes and Definite Integrals:
&lt;/h1&gt;&lt;h2 id="the-disc-method"&gt;The Disc Method:
&lt;/h2&gt;&lt;p&gt;Revolving about a line $y=k$:
&lt;/p&gt;
$$
V = \pi \int^b_c(f(x) - k)^2 dx, where \ \lvert f(x) - k \rvert = radius
$$&lt;p&gt;
Revolving about a line $x=b$:
&lt;/p&gt;
$$
V = \pi \int^d_c (g(y) - h)^2 dy, where \ \lvert g(y) - h \rvert = radius
$$&lt;h2 id="the-washer-method"&gt;The Washer Method:
&lt;/h2&gt;&lt;p&gt;The volume of a solid (with a hole in the middle) generated by revolving a region bounded by 2 curves:
About a line $x=h$:
&lt;/p&gt;
$$
V = \pi \int^b_a \left[ (f(x) - h)^2 - (g(x) - h)^2 \right]dx
$$&lt;p&gt;
About a line $y=k$:
&lt;/p&gt;
$$
V = \pi \int^d_c \left[(p(y) - k)^2 - (q(y) - k)^2 \right]dy
$$&lt;h1 id="integration-of-parametric-polar-curves"&gt;Integration of Parametric, Polar Curves:
&lt;/h1&gt;&lt;h2 id="parametric-curves"&gt;Parametric Curves:
&lt;/h2&gt;&lt;h3 id="area"&gt;Area:
&lt;/h3&gt;&lt;p&gt;For a curve defined parametrically by $x=f(t)$ and $y=g(t)$, the area bounded by the curve between $t=\alpha$ and $t=\beta$ is $A = \int^\beta_\alpha g(t)f\prime(t)dt$.&lt;/p&gt;
&lt;h3 id="arc-length-for-parametric-curves"&gt;Arc Length for Parametric Curves:
&lt;/h3&gt;&lt;p&gt;The length of that arc is $L = \int^\beta_\alpha \sqrt{(\frac{dx}{dt})^2+(\frac{dy}{dt})^2} dt$.&lt;/p&gt;
&lt;p&gt;Proof:
Divide the parametric interval $\left[\alpha, \beta \right]$ into $n$ intervals.
&lt;/p&gt;
$$
\alpha = t_0 &lt; t_1 &lt; t_2 &lt; \cdots &lt; t_n = \beta
$$&lt;p&gt;
The corresponding delta t for every interval is $\Delta t_i=t_i - t_{i-1}$, correspond to the point on the curve is $P_i(x_i, y_i)$, where $x_i=f(t_i), y_i=g(t_i)$.
Connect the neighboring points $P_{i-1}$ and $P_{i}$ with a straight line, the total length of which is the sum of the lengths of all the segments:
&lt;/p&gt;
$$
L_n = \Sigma_{i=1}^n \lvert P_{i-1}P_{i} \rvert
$$&lt;p&gt;
When the maximum length of the intervals $\lambda = \max (\Delta t_1, \Delta t_2, \cdots, \Delta t_n) \to 0$, the limit of $L_n$ exist, this limit is the length of the curve:
&lt;/p&gt;
$$
L = \lim_{\lambda \to 0} \Sigma_{i=1}^n \lvert P_{i-1} P_{i} \rvert
$$&lt;p&gt;According to Pythagorean theorem, every segment $\lvert P_{i-1} P_{i} \rvert$ can be expressed as:
&lt;/p&gt;
$$
\begin{align}
&amp;\lvert P_{i-1} P_{i} \rvert = \sqrt{(\Delta x_i)^2 + (\Delta y_{i})^2} \\
&amp;where \ \Delta x_i = x_i - x_{i-1} = f(t_i) - f(t_{i-1}), \Delta y_i = y_i - y_{i-1} = g(t_i) - g(t_{i-1})
\end{align}
$$&lt;p&gt;According to the Lagrange mean value theorem, for every interval $\left[t_{i-1} , t_i \right]$, there must exist $\xi_i \in (t_{i-1}, t_i)$, such that $\Delta x_i = f\prime(\xi_i) \cdot \Delta t_i$. Similarly, there must also exist $\eta_i \in (t_{i-1}, t_i)$, such that $\Delta y_i = g\prime(\eta_i) \cdot \Delta t_i$.
Substitute them into the segments&amp;rsquo; expression:
&lt;/p&gt;
$$
\begin{align}
\lvert P_{i-1} P_{i} \rvert &amp;= \sqrt{(f\prime (\xi_i)\Delta t_i)^2 + (g\prime(\eta_i)\Delta t_i)^2} \\
\lvert P_{i-1} P_{i} \rvert &amp;= \sqrt{(f\prime (\xi_i))^2 + (g\prime(\eta_i))^2} \ \cdot \Delta t_i
\end{align}
$$&lt;p&gt;
So the expression of the length of the curve becomes:
&lt;/p&gt;
$$
L = \lim_{\lambda \to 0} \Sigma_{i=1}^n \sqrt{(f\prime (\xi_i))^2 + (g\prime(\eta_i))^2} \ \cdot \Delta t_i
$$&lt;p&gt;
Since when $\lambda \to 0$, the difference between $\eta_i$ and $\xi_i$ is also approaching 0 $\eta_i - \xi_i \to 0$, replacing $\eta_i$ by $\xi_i$ will remain the limit unchanged.
According to the definition of the definite integral, when $\lambda \to 0$, the limit of Riemann sum is the definite integral on interval $\left[\alpha, \beta \right]$:
&lt;/p&gt;
$$
L = \lim_{\lambda \to 0} L_n = \int ^\beta_\alpha \sqrt{(f\prime (t))^2 + (g\prime(t))^2} \ dt = \int^\beta_\alpha \sqrt{(\frac{dx}{dt})^2 + (\frac{dy}{dt})^2} \ dt
$$&lt;h3 id="surface-area-for-parametric-curves"&gt;Surface Area for Parametric Curves:
&lt;/h3&gt;&lt;p&gt;The surface area created when that arc is revolved about the x-axis is
&lt;/p&gt;
$$
S = \int^\beta_\alpha 2 \pi y \sqrt{(\frac{dx}{dt})^2 + (\frac{dy}{dt})^2} dt
$$&lt;h2 id="polar-curves"&gt;Polar Curves
&lt;/h2&gt;&lt;h3 id="area-for-polar-curves"&gt;Area for Polar Curves:
&lt;/h3&gt;&lt;p&gt;If $r=f(\theta)$ is a continuous polar curve on the interval $\alpha \leq \theta \leq \beta$ and $\alpha &amp;lt; \beta &amp;lt; \alpha + 2 \pi$, then the area enclosed by the polar curve is
&lt;/p&gt;
$$
A = \frac{1}{2} \int^\beta_\alpha \left[f(\theta)\right]^2 d\theta = \frac{1}{2} \int^\beta_\alpha r^2 d\theta
$$&lt;h3 id="arc-length-for-polar-curves"&gt;Arc Length for Polar Curves:
&lt;/h3&gt;&lt;p&gt;For a polar graph defined on a interval $\left(\alpha, \beta \right)$, if the graph does not retrace itself in that interval and if $\frac{dr}{d\theta}$ is continuous, then the length of the arc from $\theta=\alpha$ to $\theta = \beta$ is
&lt;/p&gt;
$$
L = \int^\beta_\alpha \sqrt{r^2 + (\frac{dr}{d\theta})^2} d\theta
$$&lt;h1 id="differential-equations"&gt;Differential Equations
&lt;/h1&gt;&lt;h2 id="separable-differential-equations"&gt;Separable Differential Equations:
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;Separate the variables: $g(y)dy = f(x) dx$&lt;/li&gt;
&lt;li&gt;Integrate both sides: $\int g(y) dy = \int f(x) dx$&lt;/li&gt;
&lt;li&gt;Solve for $y$ to get a general solution&lt;/li&gt;
&lt;li&gt;Substitute given conditions to get a particular solution&lt;/li&gt;
&lt;li&gt;Verify your result by differentiating&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="logistic-differential-equations"&gt;Logistic Differential Equations:
&lt;/h2&gt;&lt;p&gt;Logistic growth is represented by the differential equation
&lt;/p&gt;
$$
\frac{dP}{dt} = kP ( 1 - \frac{P}{K})
$$&lt;p&gt;
where $P$ is the population, $K$ is the carrying capacity, and $k$ is the proportional constant.
Derivation:
This is a separable differential equation so
&lt;/p&gt;
$$
\begin{align}
\frac{dP}{dt} &amp;= \frac{kP(K-P)}{K} \\
\frac{K}{P(K-P)} dP &amp;= k dt \\
\int \frac{KdP}{P(K-P)}dP &amp;= \int k dt \\
\int (\frac{1}{P} + \frac{1}{K-P})dP &amp;= \int k dt \\
\ln{\lvert P \rvert} - \ln{\lvert K-P \rvert} &amp;= kt + C_1 \\
\ln{\left\lvert \frac{P}{K-P} \right\rvert} &amp;= kt + C_1 \\
e^{kt+C_1} &amp;= \frac{P}{K-P} \\
let \ C_2&amp;=e^{C_{1}} \\
C_2 e^{kt} (K - P) &amp;= P \\
C_2 e^{kt} K &amp;= P (C_2 e^{kt} + 1) \\
P &amp;= \frac{C_2 e^{kt} K}{C_2 e^{kt} + 1} \\
P(t) &amp;= \frac{K}{(\frac{1}{C_2})e^{-kt}+1}
\end{align}
$$</description></item><item><title>Foundations of Vectors And Matrices</title><link>https://EMEEEEMMMM.github.io/posts/foundationsofvectorsandmatrices/</link><pubDate>Sat, 04 Apr 2026 11:47:35 +0800</pubDate><guid>https://EMEEEEMMMM.github.io/posts/foundationsofvectorsandmatrices/</guid><description>&lt;img src="https://EMEEEEMMMM.github.io/" alt="Featured image of post Foundations of Vectors And Matrices" /&gt;&lt;h1 id="vectors-and-matrices"&gt;Vectors And Matrices
&lt;/h1&gt;&lt;p&gt;Vectors and matrices are the fundamental elements in the engine. They are capable for so many things and act important roles in different areas. I&amp;rsquo;m going to introduce some properties about them from a mathematical way.&lt;/p&gt;
&lt;h2 id="vectors"&gt;Vectors
&lt;/h2&gt;&lt;h3 id="definition-of-a-vector"&gt;Definition of a Vector:
&lt;/h3&gt;&lt;p&gt;A vector possesses &lt;strong&gt;magnitude&lt;/strong&gt; (its size or length) and &lt;strong&gt;direction&lt;/strong&gt;. Unlike a scalar quantity, which is defined only by its magnitude, a vector requires both a value and an orientation in the space to be fully described.&lt;/p&gt;
&lt;p&gt;In an $n$ dimensional space, a vector can be represented as:
&lt;/p&gt;
$$
\vec{v} = \begin{pmatrix} v_{1} \\ v_{2} \\ v_{3} \\ \vdots \\ v_{n} \end{pmatrix}
$$&lt;p&gt;Its magnitude can be expressed as:
&lt;/p&gt;
$$
\lVert \vec{v}\rVert = \sqrt{v_{1}^{2} + v_{2}^{2} + v_{3}^{2} + \dots + v_{n}^{2}} = \sqrt{\sum_{i=1}^n v_{i}^{2}}
$$&lt;p&gt;Its direction can be expressed by its unit vector:
&lt;/p&gt;
$$
\hat{v} = \frac{\vec{v}}{\lVert \vec{v} \rVert} = \begin{pmatrix} \frac{v_{1}}{\lVert \vec{v} \rVert} \\ \frac{v_{2}}{\lVert \vec{v} \rVert} \\ \frac{v_{3}}{\lVert \vec{v} \rVert} \\ \vdots \\ \frac{v_{n}}{\lVert \vec{v} \rVert} \end{pmatrix}
$$&lt;h3 id="vector-properties"&gt;Vector Properties:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Commutativity of Addition: $\vec{u} + \vec{v} = \vec{v} + \vec{u}$&lt;/li&gt;
&lt;li&gt;Associativity of Addition: $(\vec{u} + \vec{v}) + \vec{w} = \vec{u} + (\vec{v} + \vec{u})$&lt;/li&gt;
&lt;li&gt;Distributivity: $c(\vec{u} + \vec{v}) = c\vec{u} + c\vec{v}$&lt;/li&gt;
&lt;li&gt;Zero Vector: There exists a unique zero vector $\vec{0} = \left( 0, 0, \dots, 0 \right)$ such that $\vec{v} + \vec{0} = \vec{v}$.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="vector-operations"&gt;Vector Operations:
&lt;/h3&gt;&lt;h4 id="addition--subtraction"&gt;Addition &amp;amp; Subtraction:
&lt;/h4&gt;&lt;p&gt;The sum of two vectors $\vec{v}$ and $\vec{u}$ can be visualized by using the &lt;strong&gt;Triangle Law&lt;/strong&gt; or the &lt;strong&gt;Parallelogram Law&lt;/strong&gt;:
&lt;img alt="alt text" class="gallery-image" data-flex-basis="461px" data-flex-grow="192" height="402" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://EMEEEEMMMM.github.io/posts/foundationsofvectorsandmatrices/VectorSum.jpg" width="773"&gt;
Subtraction can also use these two method by adding the negative vectors.&lt;/p&gt;
&lt;h4 id="the-dot-product"&gt;The Dot Product:
&lt;/h4&gt;&lt;p&gt;The dot product of two vectors $\vec{v}$ and ${\vec{u}}$ results in a scalar which can be used in countless areas. It is crucial for determining the angle between the vectors.
&lt;strong&gt;Geometric Interpretation&lt;/strong&gt;:
&lt;/p&gt;
$$
\vec{v} \cdot \vec{u} = \lVert \vec{v} \rVert \lVert \vec{u} \rVert \cos(\theta)
$$&lt;p&gt;
Here $\theta$ is the angle between $\vec{v}$ and $\vec{u}$.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Algebraic Definition&lt;/strong&gt;:
&lt;/p&gt;
$$
\vec{v} \cdot \vec{u} = v_{1} \cdot u_{1} + v_{2} \cdot u_{2} + \dots + v_{n} \cdot u_{n} = \Sigma_{i = 1}^{n} v_{i} u_{i}
$$&lt;p&gt;&lt;strong&gt;Derivation&lt;/strong&gt;:
Consider the dot product in 3 dimensional space where any two vectors can be expressed as $\vec{v}=(x_{1}, y_{1}, z_{1})$ and $\vec{u}=(x_{2}, y_{2}, z_{2})$. The orthonormal basis in the space have these properties:
&lt;/p&gt;
$$
\begin{aligned}
 \hat i \cdot \hat i = \hat j \cdot \hat j = \hat k \cdot \hat k = 1 \\
 \hat i \cdot \hat j = \hat i \cdot \hat k = \hat j \cdot \hat k = 0
\end{aligned}
$$&lt;p&gt;
The two vectors can then be expressed as:
&lt;/p&gt;
$$
\begin{aligned}
 \vec{v} = \begin{bmatrix}
 x_{1} \hat i \\ 
 y_{1} \hat j \\
 z_{1} \hat k
 \end{bmatrix}
 \vec{u} = \begin{bmatrix}
 x_{2} \hat i \\ 
 y_{2} \hat j \\
 z_{2} \hat k
 \end{bmatrix}
\end{aligned}
$$&lt;p&gt;So, we have:
&lt;/p&gt;
$$
\begin{split}
\vec{v} \cdot \vec{u}
&amp;= (x_{1} \hat i + y_{1} \hat j + z_{1} \hat k) \cdot (x_{2} \hat i + y_{2} \hat j + z_{2} \hat k) \\
&amp;= x_{1} x_{2} \hat i \cdot \hat i + x_{1} y_{2} \hat i \cdot \hat j + x_{1} z_{2} \hat i \cdot \hat k + \\
&amp; \phantom{=} y_{1} x_{2} \hat j \cdot \hat i + y_{1} y_{2} \hat j \cdot \hat j + y_{1} z_{2} \hat j \cdot \hat k + \\
&amp; \phantom{=} z_{1} x_{2} \hat k \cdot \hat i + z_{1} y_{2} \hat k \cdot \hat j + z_{1} z_{2} \hat k \cdot \hat k \\
&amp;= x_{1} x_{2} \hat i \cdot \hat i + y_{1} y_{2} \hat j \cdot \hat j + z_{1} z_{2} \hat k \cdot \hat k \\
&amp;= x_{1} x_{2} + y_{1} y_{2} + z_{1} z_{2}
\end{split}
$$&lt;p&gt;Here is a handwriten note to help you understand.
&lt;img alt="alt text" class="gallery-image" data-flex-basis="598px" data-flex-grow="249" height="597" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://EMEEEEMMMM.github.io/posts/foundationsofvectorsandmatrices/DotProduct.jpg" srcset="https://EMEEEEMMMM.github.io/posts/foundationsofvectorsandmatrices/DotProduct_hu_447af0425b46f82.jpg 800w, https://EMEEEEMMMM.github.io/posts/foundationsofvectorsandmatrices/DotProduct.jpg 1489w" width="1489"&gt;&lt;/p&gt;
&lt;p&gt;From the geometric definition, we can derive the relationship for the angle:
&lt;/p&gt;
$$
\cos(\theta) = \frac{\vec{v} \cdot \vec{u}}{\lVert \vec{v} \rVert \lVert \vec{u} \rVert}
$$&lt;p&gt;If $\vec{v} \cdot \vec{u} &amp;gt; 0$, the angle $\theta$ is actue ($0 \leq \theta &amp;lt; \frac{\pi}{2}$).
If $\vec{v} \cdot \vec{u} = 0$, the angle $\theta = \frac{\pi}{2}$, meaning the vectors are perpendicular to each other.
If $\vec{v} \cdot \vec{u} &amp;lt; 0$, the angle $\theta$ is obtuse ($\frac{\pi}{2} &amp;lt; \theta \leq \pi$).&lt;/p&gt;
&lt;h4 id="the-cross-product"&gt;The Cross Product:
&lt;/h4&gt;&lt;p&gt;The cross product is only defined for vectors in three-dimensional space.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Geometric Interpretation&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Direction: The resulting vector $\vec{v} = \vec{u} \times \vec{w}$ is perpendicular to the plane spanned by $\vec{u}$ and $\vec{w}$. The direction of $\vec{v}$ is determined by the &lt;strong&gt;right-hand rule&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Magnitude: The magnitude of the resulting vector is given by:

$$
\lVert \vec{u} \times \vec{w} \rVert = \lVert \vec{u} \rVert \lVert \vec{w} \rVert \sin(\theta)
$$&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Special Cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Parallel Vectors ($\theta = 0 \enspace or \enspace \pi$): $\sin(\theta)=0$, so $\vec{u} \times \vec{w} = 0$. (The Zero Vector)&lt;/li&gt;
&lt;li&gt;Orthogonal Vectors($\theta = \frac{\pi}{2}$): $\sin(\frac{\pi}{2}) = 1$, so $\lVert \vec{u} \times \vec{w} \rVert = \lVert \vec{u} \rVert \lVert \vec{w} \rVert$. The resulting vector is the largest possible magnitude for the given lengths.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Algebraic Interpretation&lt;/strong&gt;:
For vectors $a=(a_{x},a_{y},a_{z})$, $b=(b_{x},b_{y},b_{z})$, $\hat i, \hat j, \hat k$ is unit vectors for x, y, z respectively(orthonormal basis). We have:
&lt;/p&gt;
$$
\vec{a} \times \vec{b} = \begin{vmatrix}
 i &amp; j &amp; k \\
 a_{x} &amp; a_{y} &amp; a_{z} \\
 b_{x} &amp; b_{y} &amp; b_{z}
\end{vmatrix} = (a_{y} b_{z} - a_{z} b_{y}) \hat i + (a_{z} b_{x} - a_{x} b_{z}) \hat j + (a_{x} b_{y} - a_{y} b_{x}) \hat k
$$&lt;p&gt;In coordinate form:
&lt;/p&gt;
$$
\vec{a} \times \vec{b} = (a_{x}, a_{y}, a_{z}) \times (b_{x}, b_{y}, b_{z}) = (a_{y} b_{z} - a_{z} b_{y}, a_{z} b_{x} - a_{x} b_{z}, a_{x} b_{y} - a_{y} b_{x})
$$&lt;p&gt;&lt;strong&gt;Derivation&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;For the unit vectors $\hat i, \hat j, \hat k$, they have the following properties:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;$\hat i \times \hat j = \hat k, \hat j \times \hat k = \hat i, \hat k \times \hat i = \hat j$&lt;/li&gt;
&lt;li&gt;$\hat j \times \hat i = - \hat k, \hat k \times \hat j = - \hat i, \hat i \times \hat k = - \hat j$&lt;/li&gt;
&lt;li&gt;$\hat i \times \hat i = \hat j \times \hat j = \hat k \times \hat k = 0$&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For $\vec{u}$ and $\vec{v}$ which are in the coordinate system consisting of $\hat i, \hat j, \hat k$ can be expressed as:
&lt;/p&gt;
$$
\begin{aligned}
 \vec{u} = x_{u} \hat i + y_{u} \hat j + z_{u} \hat k \\
 \vec{v} = x_{v} \hat i + y_{v} \hat j + z_{v} \hat k \\
\end{aligned}
$$&lt;p&gt;Then calculate $\vec{u} \times \vec{v}$:
&lt;/p&gt;
$$
\begin{split}
\vec{u} \times \vec{v}
&amp;= (x_{u} \hat i + y_{u} \hat j + z_{u} \hat k) \times (x_{v} \hat i + y_{v} \hat j + z_{v} \hat k) \\
&amp;= x_{u} x_{v} (\hat i \times \hat i) + x_{u} y_{v} (\hat i \times \hat j) + x_{u} z_{v} (\hat i \times \hat k) + \\
&amp; \phantom{=} y_{u} x_{v} (\hat j \times \hat i) + y_{u} y_{v} (\hat j \times \hat j) + y_{u} z_{v} (\hat j \times \hat k) + \\
&amp; \phantom{=} z_{u} x_{v} (\hat k \times \hat i) + z_{u} y_{v} (\hat k \times \hat j) + z_{u} z_{v} (\hat k \times \hat k) \\
&amp;= (y_{u} z_{v} - z_{u} y_{v}) \hat i + (z_{u} x_{v} - x_{u} z_{v}) \hat j + (x_{u} y_{v} - y_{u} x_{v}) \hat k
\end{split}
$$&lt;h2 id="matrices"&gt;Matrices
&lt;/h2&gt;&lt;p&gt;Matrices is a set of numbers in a rectangular array.&lt;/p&gt;
&lt;p&gt;A table of numbers in $m$ rows and $n$ columns arranged by $m \times n$ numbers is called a $m \times n$ matrix. Denoted as:&lt;/p&gt;
$$
A = \begin{bmatrix}
 a_{11} &amp; a_{12} &amp; \dots &amp; a_{1n} \\
 a_{21} &amp; a_{22} &amp; \dots &amp; a_{2n} \\
 \vdots &amp; \vdots &amp; \ddots &amp; \vdots \\
 a_{m1} &amp; a_{m2} &amp; \dots &amp; a_{mn}
\end{bmatrix}
$$&lt;h3 id="matrix-operations"&gt;Matrix Operations:
&lt;/h3&gt;&lt;h4 id="addition--subtraction-1"&gt;Addition &amp;amp; Subtraction:
&lt;/h4&gt;$$
\begin{bmatrix}
 a_{11} &amp; a_{12} &amp; \dots &amp; a_{1n} \\
 a_{21} &amp; a_{22} &amp; \dots &amp; a_{2n} \\
 \vdots &amp; \vdots &amp; \ddots &amp; \vdots \\
 a_{m1} &amp; a_{m2} &amp; \dots &amp; a_{mn}
\end{bmatrix} + 
\begin{bmatrix}
 b_{11} &amp; b_{12} &amp; \dots &amp; b_{1n} \\
 b_{21} &amp; b_{22} &amp; \dots &amp; b_{2n} \\
 \vdots &amp; \vdots &amp; \ddots &amp; \vdots \\
 b_{m1} &amp; b_{m2} &amp; \dots &amp; b_{mn}
\end{bmatrix} = 
\begin{bmatrix}
 a_{11} + b_{11} &amp; a_{12} + b_{12} &amp; \dots &amp; a_{1n} + b_{1n} \\
 a_{21} + b_{21} &amp; a_{22} + b_{22} &amp; \dots &amp; a_{2n} + b_{2n} \\
 \vdots &amp; \vdots &amp; \ddots &amp; \vdots \\
 a_{m1} + b_{m1} &amp; a_{m2} + b_{m2} &amp; \dots &amp; a_{mn} + b_{mn}
\end{bmatrix}
$$&lt;p&gt;Addition of matrices satisfies the following operator laws:
&lt;/p&gt;
$$
\begin{align}
 A + B &amp;= B + A \\
 (A + B) + C &amp;= A + (B + C)
\end{align}
$$&lt;h4 id="scalar-multiplication"&gt;Scalar Multiplication:
&lt;/h4&gt;$$
k \cdot
\begin{bmatrix}
 a_{11} &amp; a_{12} &amp; \dots &amp; a_{1n} \\
 a_{21} &amp; a_{22} &amp; \dots &amp; a_{2n} \\
 \vdots &amp; \vdots &amp; \ddots &amp; \vdots \\
 a_{m1} &amp; a_{m2} &amp; \dots &amp; a_{mn}
\end{bmatrix} =
\begin{bmatrix}
 k \cdot a_{11} &amp; k \cdot a_{12} &amp; \dots &amp; k \cdot a_{1n} \\
 k \cdot a_{21} &amp; k \cdot a_{22} &amp; \dots &amp; k \cdot a_{2n} \\
 \vdots &amp; \vdots &amp; \ddots &amp; \vdots \\
 k \cdot a_{m1} &amp; k \cdot a_{m2} &amp; \dots &amp; k \cdot a_{mn}
\end{bmatrix}
$$&lt;p&gt;The scalar multiplication of a matrix satisfies the following operator laws:
&lt;/p&gt;
$$
\begin{aligned}
 \lambda(\mu A) &amp;= \mu(\lambda A) \\ 
 \lambda(\mu A) &amp;= (\lambda \mu) A \\ 
 (\lambda + \mu) A &amp;= \lambda A + \mu A \\
 \lambda(A + B) &amp;= \lambda A + \lambda B 
\end{aligned}
$$&lt;h4 id="transpose"&gt;Transpose:
&lt;/h4&gt;&lt;p&gt;The matrix resulting from interchanging the rows and the columns of the matrix A is called the transposed matrix of A ($A^T$)
&lt;/p&gt;
$$
\begin{bmatrix}
 a_{11} &amp; a_{12} &amp; a_{13} \\
 a_{21} &amp; a_{22} &amp; a_{23} \\
\end{bmatrix} ^ T = \begin{bmatrix}
 a_{11} &amp; a_{21} \\
 a_{12} &amp; a_{22} \\
 a_{13} &amp; a_{23}
\end{bmatrix}
$$&lt;p&gt;The transpose of a matrix satisifes the following operator laws:
&lt;/p&gt;
$$
\begin{align}
 (A^T)^T &amp;= A \\
 (\lambda A)^T &amp;= \lambda A^T \\
 (AB)^T &amp;= B^T A^T 
\end{align}
$$&lt;h4 id="multiplication"&gt;Multiplication:
&lt;/h4&gt;&lt;p&gt;If $A$ is a $m \times n$ matrix and $B$ is a $n \times p$ matrix, their product $C$ is a $m \times p$ matrix $C = (c_{ij})$, any of its element can be expressed as:
&lt;/p&gt;
$$
c_{i,j} = a_{i,1}b_{1,j} + a_{i,2}b_{2,j} + \cdots + a_{i,n}b_{n,j} = \Sigma_{r=1}^n a_{i,r}b{r,j}
$$&lt;p&gt;
This product can be denoted as: $C = AB$&lt;/p&gt;
&lt;p&gt;The multiplication of matrices satisfies following operators:
&lt;/p&gt;
$$
\begin{align}
 (AB)C = A(BC) \\
 (A+B)C = AC + BC \\
 C(A+B) = CA + CB
\end{align}
$$</description></item><item><title>Impulse Solution</title><link>https://EMEEEEMMMM.github.io/posts/impulsesolution/</link><pubDate>Tue, 31 Mar 2026 19:30:31 +0800</pubDate><guid>https://EMEEEEMMMM.github.io/posts/impulsesolution/</guid><description>&lt;img src="https://EMEEEEMMMM.github.io/" alt="Featured image of post Impulse Solution" /&gt;&lt;h1 id="problem"&gt;Problem:
&lt;/h1&gt;&lt;p&gt;For a rigid body A with mass $m_{A}$ and another rigid body B with mass $m_{B}$ collide with linear velocity $v_{A},v_{B}$ respectively, solve for the scalar impulse $j$ of the two object. Friction is negligible.&lt;/p&gt;
&lt;h1 id="variables"&gt;Variables:
&lt;/h1&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th style="text-align: left"&gt;Symbol&lt;/th&gt;
 &lt;th&gt;Definition&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;$m_{A},m_{B}$&lt;/td&gt;
 &lt;td&gt;Mass of object A and B&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;$I_{A},I_{B}$&lt;/td&gt;
 &lt;td&gt;Moment of inertia tensor of object A and B&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;$x_{A},x_{B}$&lt;/td&gt;
 &lt;td&gt;Center of Mass&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;$P$&lt;/td&gt;
 &lt;td&gt;Contact point&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;$r_{A},r_{B}$&lt;/td&gt;
 &lt;td&gt;$P-x$&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;$v_{A},v_{B}$&lt;/td&gt;
 &lt;td&gt;linear velocity before impact&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;$\omega_{A},\omega_{B}$&lt;/td&gt;
 &lt;td&gt;Angular velocity before impact&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;$v_{PA},v_{PB}$&lt;/td&gt;
 &lt;td&gt;Absolute linear velocity of the contact point&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;$v_{rel}$&lt;/td&gt;
 &lt;td&gt;relative velocity of contact point&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;$n$&lt;/td&gt;
 &lt;td&gt;Contact normal (unit vector)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;$e$&lt;/td&gt;
 &lt;td&gt;coefficient of restitution&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;$J$&lt;/td&gt;
 &lt;td&gt;impulse vector&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;$j$&lt;/td&gt;
 &lt;td&gt;impulse scalar&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h1 id="derivation"&gt;Derivation:
&lt;/h1&gt;&lt;p&gt;The velocity of any point on a rigid body is the sum of its linear velocity and its tangential velocity due to rotation.
From the definition:&lt;/p&gt;
$$
\begin{align}
r_{A} = P - x_{A}, r_{B} = P - x_{B} 
\begin{aligned}
v_{PA} &amp;=v_{A}+\omega_{A} \times r_{A} \\
v_{PB} &amp;= v_{B}+\omega_{B} \times r_{B} \\
\end{aligned}
\end{align}
$$&lt;p&gt;The relative velocity of body B with respect to body A at the contact point:&lt;/p&gt;
$$
v_{rel} = v_{PB} - v_{PA}
$$&lt;p&gt;
The impulse $J$ acts along the contact normal $n$:
&lt;/p&gt;
$$
J = jn
$$&lt;p&gt;
According to Impulse-Momentum Theorem ($\Delta v=\frac{J}{m}$):
&lt;/p&gt;
$$
\begin{align}
v_{A}'=v_{A}-\frac{j}{m_{A}}n \\
v_{B}'=v_{B}+\frac{j}{m_{B}}n
\end{align}
$$&lt;p&gt;
The impulse also applies a torque which changes the angular velocities ($\Delta \omega = I^{-1}(r \times J)$):
&lt;/p&gt;
$$
\begin{align}
\omega_{A}'=\omega_{A} - I^{-1}_{A}(r_{A}\times jn) \\
\omega_{B}'=\omega_{B} + I^{-1}_{B}(r_{B}\times jn)
\end{align}
$$&lt;p&gt;
Then the velocity of the contact point immediately after the impact can be expressed as:
&lt;/p&gt;
$$
\begin{align}
v_{PA}'=v_{A}'+\omega_{A}'\times r_{A} \\ \\
v_{PB}'=v_{B}'+\omega_{B}'\times r_{B}
\end{align}
$$&lt;p&gt;
Substitute the equations into this expression:
&lt;/p&gt;
$$
\begin{align}
v_{PA}' &amp;= (v_{A}-\frac{j}{m_{A}}n)+(\omega_{A} - I^{-1}_{A}(r_{A}\times jn)) \times r_{A} \\
v_{PB}' &amp;= (v_{B}+\frac{j}{m_{B}}n) + (\omega_{B} + I^{-1}_{B}(r_{B}\times jn)) \times r_{B}
\end{align}
$$&lt;p&gt;
Factor out the $j$ and simplify:
&lt;/p&gt;
$$
\begin{align}
v_{PA}' &amp;= v_{PA} - j[\frac{n}{m_{A}} + (I^{-1}_{A}(r_{A}\times n)) \times r_{A}] \\
v_{PB}' &amp;= v_{PB} + j[\frac{n}{m_{B}} + (I^{-1}_{B}(r_{B}\times n)) \times r_{B}]
\end{align}
$$&lt;p&gt;
The new relative velocity:
&lt;/p&gt;
$$
\begin{align}
v_{rel}'=v_{PB}'-v_{PA}'&amp;= ((v_{B}+\frac{j}{m_{B}}n) + (\omega_{B} + I^{-1}_{B}(r_{B}\times jn)) \times r_{B}) - (v_{PA} - j[\frac{n}{m_{A}} + (I^{-1}_{A}(r_{A}\times n)) \times r_{A}]) \\
v_{rel}'&amp;=v_{rel}+j(\frac{n}{m_{A}} + (I^{-1}_{A}(r_{A}\times n)) \times r_{A} + \frac{n}{m_{B}} + (I^{-1}_{B}(r_{B}\times n)) \times r_{B})
\end{align}
$$&lt;p&gt;
According to Newton&amp;rsquo;s law of Restitution, the ratio of the relative speed of separation and the relative speed of approach when two objects collide equals to the coefficient of restitution.
&lt;/p&gt;
$$
v_{rel}' \cdot n = -e (v_{rel} \cdot n), e \in [0, 1]
$$&lt;p&gt;
Substitute $v_{rel}&amp;rsquo;$ and simplify the equation:
&lt;/p&gt;
$$
\begin{align}
\left[ v_{rel}+j\left( \frac{n}{m_{A}} + (I^{-1}_{A}(r_{A}\times n)) \times r_{A} + \frac{n}{m_{B}} + (I^{-1}_{B}(r_{B}\times n)) \times r_{B} \right) \right] \cdot n &amp;= -e (v_{rel} \cdot n) \\
j\left( \frac{n}{m_{A}} + (I^{-1}_{A}(r_{A}\times n)) \times r_{A} + \frac{n}{m_{B}} + (I^{-1}_{B}(r_{B}\times n)) \times r_{B} \right) \cdot n &amp;= -(1+e)(v_{rel} \cdot n) \\
j = \frac{-(1+e)(v_{rel} \cdot n)}{\left( \frac{n}{m_{A}} + (I^{-1}_{A}(r_{A}\times n)) \times r_{A} + \frac{n}{m_{B}} + (I^{-1}_{B}(r_{B}\times n)) \times r_{B} \right) \cdot n } \\
j = \frac{-(1+e)(v_{rel} \cdot n)}{ \frac{1}{m_{A}} + \frac{1}{m_{B}} + \left[(I^{-1}_{A}(r_{A}\times n)) \times r_{A} + (I^{-1}_{B}(r_{B}\times n)) \times r_{B} \right] \cdot n }
\end{align}
$$</description></item></channel></rss>