\newpage \section{Class \tkzClass{occs}} \label{sec:orthonormal_cartesian_coordinate_system} \subsection{Description} The \texttt{occs} class models an \emph{orthonormal Cartesian coordinate system} (OCCS). Its primary use is to transition from the default coordinate system to one aligned with geometric features of the figure (e.g., a directrix, a major axis, or the vertex of a conic). All calculations in this package are performed in a fixed OCCS. For convenience and clarity, this class allows defining and transforming to a new OCCS using a direction (a line) and a new origin point. \medskip The typical use case is to simplify the coordinates of geometric objects such as conics, by aligning the axes with their natural directions. \subsection{Creating an occs}\label{occs:create} An OCCS (orthonormal Cartesian coordinate system) is defined by: \begin{itemize} \item a line, which sets the direction of the new \emph{ordinate} axis (the $y$-axis), and \item a point, which becomes the new origin. \end{itemize} The abscissa axis (the $x$-axis) is automatically computed to be orthogonal to the ordinate axis, ensuring a right-handed coordinate system. \medskip There are two equivalent ways to create an OCCS: \begin{mybox} \code{O.S = occs(L.axis, z.S)} \hfill (short form, recommended) \\ \code{O.S = occs:new(L.axis, z.S)} \hfill (explicit constructor) \end{mybox} The result is stored in the table \code{O} under the key \code{"S"}, representing the OCCS centered at point \code{z.S}. \medskip This object can then be used to: \begin{itemize} \item compute coordinates of points in the new system, \item project points onto the new axes, or \item reconstruct geometric elements aligned with the new frame. \end{itemize} The new abscissa axis is automatically computed to ensure orthonormality. \subsection{Attributes of an occs} \bgroup \catcode`_=12 \small \captionof{table}{Attributes of an \texttt{occs} object.}\label{occs:attributes} \begin{tabular}{ll} \toprule \textbf{Attribute} & \textbf{Description} \\ \midrule \tkzAttr{occs}{type} & Object type name, always \texttt{"occs"} \\ \tkzAttr{occs}{origin} & The new origin point \\ \tkzAttr{occs}{x} & Point that defines the new $x$-axis (abscissa) \\ \tkzAttr{occs}{y} & Point that defines the new $y$-axis (ordinate) \\ \tkzAttr{occs}{abscissa} & Line representing the abscissa axis \\ \tkzAttr{occs}{ordinate} & Line representing the ordinate axis \\ \bottomrule \end{tabular} \egroup \subsubsection{Example: attributes of \texttt{occs}} \label{ssub:example_attributes_of_occs} A few words about the arguments of a new OCCS. The most important is the line that defines the direction of the new ordinate axis. For a parabola, this direction should point from the directrix to the focus. For a hyperbola or an ellipse, it should go from the center to the principal focus. The orientation is determined by the order of the two points used to construct the line: it runs from the first to the second. If this line is constructed as an orthogonal to another line (as in the example below), then its orientation depends on the orientation of the original line. \vspace{1em} \begin{verbatim} \directlua{ init_elements() z.O = point(0, 0) z.i = point(1, 0) z.j = point(0, 1) z.A = point(-1, -1) z.B = point(4, 2) L.AB = line(z.A, z.B) z.S = point(0, 3) L.axis = L.AB:ortho_from(z.S) % new occs O.S = occs(L.axis, z.S) z.u = O.S.x z.v = O.S.y z.ax = O.S.abscissa.pa z.bx = O.S.ordinate.pa z.ay = O.S.abscissa.pb z.by = O.S.ordinate.pb} \begin{tikzpicture} \tkzGetNodes \tkzDrawLines(A,B) \tkzDrawLines[purple,add=4 and 4](ax,ay bx,by) \tkzDrawSegments[->,red,thick](O,i O,j) \tkzDrawSegments[->,purple,thick](S,u S,v) \tkzLabelSegment[below,sloped,pos=.9](A,B){L.AB the directrix} \tkzLabelSegment[below,sloped,pos=3](ax,ay){abscissa} \tkzLabelSegment[below,sloped,pos=5](bx,by){ordinate major\_axis} \tkzLabelPoints(O,S) \tkzLabelPoints[left](j,v) \tkzLabelPoints[below right](i,u) \end{tikzpicture} \end{verbatim} \directlua{ init_elements() z.O = point(0, 0) z.i = point(1, 0) z.j = point(0, 1) z.A = point(-1, -1) z.B = point(4, 2) L.AB = line(z.A, z.B) z.S = point(0, 3) L.axis = L.AB:ortho_from(z.S) % new occs O.S = occs(L.axis, z.S) z.u = O.S.x z.v = O.S.y z.ax = O.S.abscissa.pa z.bx = O.S.ordinate.pa z.ay = O.S.abscissa.pb z.by = O.S.ordinate.pb} \begin{center} \begin{tikzpicture} \tkzGetNodes \tkzDrawLines(A,B) \tkzDrawLines[purple,add=4 and 4](ax,ay bx,by) \tkzDrawSegments[->,red,thick](O,i O,j) \tkzDrawSegments[->,purple,thick](S,u S,v) \tkzLabelSegment[below,sloped,pos=.9](A,B){L.AB the directrix} \tkzLabelSegment[below,sloped,pos=3](ax,ay){abscissa} \tkzLabelSegment[below,sloped,pos=5](bx,by){ordinate major\_axis} \tkzLabelPoints(O,S) \tkzLabelPoints[left](j,v) \tkzLabelPoints[below right](i,u) \end{tikzpicture} \end{center} \subsection{Methods of the class \texttt{occs}} This class provides the following methods: \bgroup \small \captionof{table}{occs methods.}\label{occs:methods} \begin{tabular}{ll} \toprule \textbf{Methods} & \textbf{Reference} \\ \midrule \textbf{Creation} & \\ \midrule \tkzMeth{occs}{occs(dir, origin)} & Note\footnote{occs(L, pt) (short form, recommended)}; [\ref{occs:new}; \ref{ssub:example_attributes_of_occs}] \\ \tkzMeth{occs}{coordinates(pt)} & [\ref{occs:coordinates}] \\ \bottomrule \end{tabular} \egroup \subsection{Method \tkzMeth{occs}{occs(L, pt)}} \label{occs:new} The general creation of an orthonormal coordinate system attached to a line has already been presented [see \ref{occs:create}]. Here we emphasize the important role of the two points defining the line~\(L\). If these points are swapped, the resulting coordinate system is not the same: the orientation of the axes is reversed. In every case, the system is oriented in the forward direction, following the order of the defining points. \begin{tkzexample}[latex=.5\textwidth] \directlua{% z.O = point(0, 0) z.A = point(0, 1) z.B = point(4, 2) z.S = point(1, 3) L.AB = line(z.A, z.B) z.K = L.AB:projection(z.S) O.sys = occs(L.AB, z.S) z.u, z.v = O.sys.x, O.sys.y} \begin{tikzpicture} \tkzGetNodes \tkzDrawLines[purple](A,B) \tkzDrawPoints(A,B,S,O,K) \tkzLabelPoints(A,B,S,O,K,u,v) \tkzDrawSegments[thick,->](S,u S,v) \end{tikzpicture} \end{tkzexample} \begin{tkzexample}[latex=.5\textwidth] \directlua{% z.O = point(0, 0) z.A = point(0, 1) z.B = point(4, 2) z.S = point(1, 3) L.AB = line(z.B, z.A) z.K = L.AB:projection(z.S) O.sys = occs(L.AB, z.S) z.u, z.v = O.sys.x, O.sys.y} \begin{tikzpicture} \tkzGetNodes \tkzDrawLines[purple](A,B) \tkzDrawPoints(A,B,S,O,K) \tkzLabelPoints(A,B,S,O,K,u,v) \tkzDrawSegments[thick,->](S,u S,v) \end{tikzpicture} \end{tkzexample} \subsection{Method \tkzMeth{occs}{coordinates(pt)}}\label{occs:coordinates} We want to construct the parabola passing through three given points, knowing that the axis of symmetry of the parabola is parallel to a given line \((MN)\). \begin{enumerate} \item First, we must check that the three points \(A,B,C\) are not collinear, and that no two of them lie on the same line perpendicular to \((MN)\). \item Next, we define a reference system \((M,\overrightarrow{MU},\overrightarrow{MV})\) attached to the line \((MN)\). \item In this new system, there exists a unique parabola through the three points. The function \tkzFct{tkz}{parabola(pt, pt, pt)} [see \ref{tkz:parabola}] computes the coefficients of the quadratic function \(y = Ax^2 + Bx + C\). \item To apply this function, we need the coordinates of \(A,B,C\) in the new system. This is exactly the role of the method \tkzMeth{occs}{coordinates(pt)}. \end{enumerate} \directlua{ z.O = point(0, 0) z.A = point(-1.5, 1) z.B = point(1, 0.25) z.C = point(2.5, 1.8) z.M = point(3, 0) z.N = point(2, 1) L.MN = line(z.M, z.N) sys = occs(L.MN, z.M) z.U = sys.x z.V = sys.y L.MV = line(z.M, z.V) L.MU = line(z.M, z.U) local a, b, c = tkz.parabola(point(sys:coordinates(z.A)), point(sys:coordinates(z.B)), point(sys:coordinates(z.C))) function f(x) return a * x ^ 2 + b * x + c end xf = - b / (2 * a) yf = (4 * a * c - b ^ 2 + 1) / (4 * a) xk = xf yk = (4 * a * c - (b ^ 2) - 1) / (4 * a) z.K = L.MV:report(yk, L.MU:report(xk)) z.f = L.MU:report(xf) z.F = L.MV:report(yf, z.f) L.dir = L.MU:ll_from(z.K) PA = conic(z.F, L.dir, 1) curve = PA:points(-3, 3, 30) } \begin{tikzpicture} \tkzGetNodes \tkzDrawSegments[->,purple,thick](M,U M,V) \tkzDrawLines(M,N) \tkzDrawCoordinates[smooth,red,thick](curve) \tkzDrawPoints(A,B,C) \tkzLabelPoints(A,B,U,V) \tkzLabelPoints[above](M,N,C) \end{tikzpicture} \subsection{Example: Using \texttt{occs} with a parabola} Let us consider a practical example. Suppose we want to compute the intersection points between a parabola and a line. The parabola is defined by its directrix and focus. In a coordinate system centered at the vertex $S$ of the parabola, with the $x$-axis parallel to the directrix and passing through $S$, the equation of the parabola becomes \[ y = \frac{x^2}{2p} \] where $p$ is the \emph{latus rectum}, i.e., the distance from the focus to the directrix. \vspace{1em} To determine the intersection points, we first express the equation of the given line in the new coordinate system. Then, we solve the equation system using $y = \frac{x^2}{2p}$. Internally, this is handled using two utility functions. \vspace{1em} If solutions exist, the result consists of two values $r_1$ and $r_2$, which are the abscissas of the intersection points in the new OCCS. Once the corresponding ordinates are computed, we can either: \begin{itemize} \item express the coordinates in \TIKZ{} directly using a projection onto the new OCCS, or \item geometrically reconstruct the points: for each $r$, find the corresponding point $x$ on the new $x$-axis (\code{OCCS.abscissa}), and use it to locate the point on the parabola. \end{itemize} \vspace{1em} \begin{verbatim} \directlua{ init_elements() z.O = point(0, 0) z.i = point(1, 0) z.j = point(0, 1) z.A = point(-1, 0) z.B = point(5, 4) L.dir = line(z.A, z.B) z.F = point(0, 3) CO.parabola = conic(z.F, L.dir, 1) PA.curve = CO.parabola:points(-3, 3, 50) local p = CO.parabola.p z.P = L.dir:report(p, z.K) z.X = PA:point(p) z.H = L.dir:projection(z.X) z.K = CO.parabola.K z.S = CO.parabola.vertex L.KF = CO.parabola.major_axis % new occs O.SKF = occs(L.KF, z.S) z.u = O.SKF.x z.v = O.SKF.y % line a,b z.a = point(-1, 1) z.b = point(3, 5) L.ab = line(z.a, z.b) % % coordinates in the new occs X, Y = O.SKF:coordinates(z.F) Xa, Ya = O.SKF:coordinates(z.a) Xb, Yb = O.SKF:coordinates(z.b) % solve in the new occs local r, s = tkz.line_coefficients(Xa, Ya, Xb, Yb) r1, r2 = solve_para_line(p, r, s) z.x = O.SKF.abscissa:report(r1, z.K) z.y = O.SKF.abscissa:report(r2, z.K) L1 = L.dir:ortho_from(z.x) L2 = L.dir:ortho_from(z.y) z.s1 = intersection(L.ab, L1) z.s2 = intersection(L.ab, L2)} \begin{tikzpicture} \tkzGetNodes \tkzDrawCoordinates[smooth,orange,thick](PA.curve) \tkzDrawLines(A,B) \tkzDrawLines[add = 1 and 1](K,F) \tkzDrawSegments[add = .5 and .5,blue](a,b) \tkzDrawSegments[dashed](s1,x s2,y) \tkzDrawPoints(A,B,F,K,S) \tkzDrawPoints[blue,size=2](a,b) \tkzDrawPoints[blue,size=2](s1,s2,x,y) \tkzLabelPoints[blue](a,b) \tkzLabelPoints[blue,above left](s1,s2) \tkzLabelPoints(O,i,u,S,A,B,x,y) \tkzLabelPoints[left](j,v) \tkzLabelPoints[right](F,K) \tkzDrawSegments[->,red,thick](O,i O,j) \tkzDrawSegments[->,purple,thick](S,u S,v) \tkzLabelSegment[below,sloped,pos=.7](A,B){Directrix} \end{tikzpicture} \end{verbatim} \directlua{ init_elements() z.O = point(0, 0) z.i = point(1, 0) z.j = point(0, 1) z.A = point(-1, 0) z.B = point(5, 4) L.dir = line(z.A, z.B) z.F = point(0, 3) CO.parabola = conic(z.F, L.dir, 1) PA.curve = CO.parabola:points(-3, 3, 50) local p = CO.parabola.p z.P = L.dir:report(p, z.K) z.X = CO.parabola:point(p) z.H = L.dir:projection(z.X) z.K = CO.parabola.K z.S = CO.parabola.vertex L.KF = CO.parabola.major_axis % new occs O.SKF = occs(L.KF, z.S) z.u = O.SKF.x z.v = O.SKF.y % line a,b z.a = point(-1, 1) z.b = point(3, 5) L.ab = line(z.a, z.b) % % coordinates in the new occs X, Y = O.SKF:coordinates(z.F) Xa, Ya = O.SKF:coordinates(z.a) Xb, Yb = O.SKF:coordinates(z.b) % solve in the new occs local r, s = tkz.line_coefficients(Xa, Ya, Xb, Yb) r1, r2 = tkz.solve_quadratic_(1, -2 * p * r, -2 * p * s) z.x = O.SKF.abscissa:report(r1, z.K) z.y = O.SKF.abscissa:report(r2, z.K) local L1 = L.dir:ortho_from(z.x) local L2 = L.dir:ortho_from(z.y) z.s1 = intersection(L.ab, L1) z.s2 = intersection(L.ab, L2)} \begin{center} \begin{tikzpicture} \tkzGetNodes \tkzDrawCoordinates[smooth,orange,thick](PA.curve) \tkzDrawLines(A,B) \tkzDrawLines[add = 1 and 1](K,F) \tkzDrawSegments[add = .5 and .5,blue](a,b) \tkzDrawSegments[dashed](s1,x s2,y) \tkzDrawPoints(A,B,F,K,S) \tkzDrawPoints[blue,size=2](a,b) \tkzDrawPoints[blue,size=2](s1,s2,x,y) \tkzLabelPoints[blue](a,b) \tkzLabelPoints[blue,above left](s1,s2) \tkzLabelPoints(O,i,u,S,A,B,x,y) \tkzLabelPoints[left](j,v) \tkzLabelPoints[right](F,K) \tkzDrawSegments[->,red,thick](O,i O,j) \tkzDrawSegments[->,purple,thick](S,u S,v) \tkzLabelSegment[below,sloped,pos=.7](A,B){Directrix} \end{tikzpicture} \end{center} \endinput