{"id":24616304,"url":"https://github.com/wunkolo/qtriangle","last_synced_at":"2025-05-07T02:25:35.810Z","repository":{"id":83991101,"uuid":"135952650","full_name":"Wunkolo/qTriangle","owner":"Wunkolo","description":"A small study in SIMD-accelerated point-in-triangle tests","archived":false,"fork":false,"pushed_at":"2019-02-19T18:33:09.000Z","size":2271,"stargazers_count":23,"open_issues_count":1,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-31T05:25:17.130Z","etag":null,"topics":["math","simd"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Wunkolo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2018-06-04T00:48:03.000Z","updated_at":"2025-03-27T23:12:56.000Z","dependencies_parsed_at":"2023-10-20T23:51:25.530Z","dependency_job_id":null,"html_url":"https://github.com/Wunkolo/qTriangle","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Wunkolo%2FqTriangle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Wunkolo%2FqTriangle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Wunkolo%2FqTriangle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Wunkolo%2FqTriangle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Wunkolo","download_url":"https://codeload.github.com/Wunkolo/qTriangle/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252800131,"owners_count":21806102,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["math","simd"],"created_at":"2025-01-24T22:16:47.418Z","updated_at":"2025-05-07T02:25:35.785Z","avatar_url":"https://github.com/Wunkolo.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# qTriangle [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/Wunkolo/qTriangle/master/LICENSE) (WIP)\n\n|||||\n|:-:|:-:|:-:|:-:|\n|Serial|SSE/NEON|AVX2|AVX512|\n|![Serial](media/Serial.gif)|![SSE/NEON](media/SSE-NEON.gif)|![AVX2](media/AVX2.gif)|![AVX512](media/AVX512.gif)|\n\nqTriangle is a personal study to design a **q**uick way to detect if a point is within a **Triangle** by means of vectorization\n\n[![](media/glsl.png)](https://www.shadertoy.com/view/4t3czN)\n\n\n### [Check out a live GLSL sample here!](https://www.shadertoy.com/view/4t3czN)\n\nThe domain of the Point-In-Triangle problem is determining if a cartesian coordinate happens to land upon the interior of a triangle. In this case the 2D case of triangles will be examined and will require some kind of surface **area** for a point to land on so a case in which all three points are collinear(which is the worst case of having a *very* slim triangle) are ruled out.\n\nThis problem comes up a lot in the domain of computer graphics and gameplay programming at times. Sometimes it's testing if a single point lands upon a polygon(made up of triangles) and sometimes it's testing if thousands of points happen to land on a triangle or not(such as when rendering a vector triangle against a regular grid during rasterization).\n\nThere are several methods to test if a point happens to land within a triangle in 2D space, each have their own pros and cons and scaling properties.\n\n# Cross Product Method\n\nThe cross-product operation in vector algebra is a binary operation that takes two vectors in 3D space and creates a new vector that is perpendicular to them both. You can think of the two vectors as describing some kind of plane in 2D space, and the cross product creates a new vector that is perpendicular to this plane. Though, there are two ways to create a vector perpendicular to a plane, by going \"in\" the plane and going \"out\" the plane.\n\nThe Cross-Product has a lot of useful properties but one of interest at the moment is the **magnitude** of the resulting vector of the cross product which will be the **area** of the parallelogram that the two original vectors create. Since the points are on the X-Y plane in 3D space this *magnitude* will always be the Z-component of the cross product since all vectors perpendicular to the orthogonal X-Y plane will take the form `[ 0, 0, (some value)]`. This becomes useful later on.\n\n![](media/Cross.gif)\n\nThe particular numerical value of this area is not of importance either but rather the *parity* of the area is of interest(while a negative-surface-area does not make sense, this value tells us something about two directional vectors). Notice that whenever the direction to the moving point goes to the \"left\" of the black directional vector, that the area becomes negative, but when it is to the \"right\", the area is positive.\nThis is due to the [right hand rule](https://en.wikipedia.org/wiki/Right-hand_rule) where the direction of positive-rotation being **clockwise** or **counter-clockwise** causes the order of the original two directional vectors to determine the proper orientation of the cross product.\n\nThe parity of the cross-product-area depending on which side the direction of the \"point\" lands on solves the problem at the same tone of turning each edge into a linear inequality then testing if the point solves each of them at once but in a somewhat more optimal way.\n\nThe three positional vectors of the triangle must be in **clockwise** or **counter-clockwise** order so that three directional vectors can be determinately created.\n```\nEdgeDir0 = Vertex1 - Vertex0\nEdgeDir1 = Vertex2 - Vertex1\nEdgeDir2 = Vertex0 - Vertex2\n```\nThen, three additional directional vectors can be made that point from the triangle vertex position to the point that is being tested against\n```\nPointDir0 = Point - Vertex0\nPointDir1 = Point - Vertex1\nPointDir2 = Point - Vertex2\n```\n\nNow, finding out if a point lands within the triangle is determined by using three cross-products, and checking if each area is positive. If they are all positive. Then the point is to the \"right\" of all the edges. If any of them are negative, then it is not within the triangle.\n```\n| EdgeDir0 × PointDir0 | \u003e= 0 \u0026\u0026\n| EdgeDir1 × PointDir1 | \u003e= 0 \u0026\u0026\n| EdgeDir2 × PointDir2 | \u003e= 0\n```\n\n![](media/CrossMethod.gif)\n\n## Optimizations\n\nPreviously it was determined that all cross products against the X-Y plane will take the form `[ 0, 0, (some value)]`. With this the arithmetic behind the cross-product operation can be much more simplified. Since the cross product can be [calculated using partial determinants of a 3x3 matrix](https://en.wikipedia.org/wiki/Rule_of_Sarrus) then attention only has to be given to the calculations that determine the Z-component alone which is but a 2x2 determinant of the two input vectors.\n\nThis means that if I had two vectors `A` and `B` on the X-Y plane. The cross-product's magnitude is simply:\n```\nA.x * B.y - A.y * B.x;\n```\nwhich reduces the previous arithmetic to:\n```\nEdgeDir0.x * PointDir0.y - EdgeDir0.y * PointDir0.x \u003e= 0 \u0026\u0026\nEdgeDir1.x * PointDir1.y - EdgeDir1.y * PointDir1.x \u003e= 0 \u0026\u0026\nEdgeDir2.x * PointDir2.y - EdgeDir2.y * PointDir2.x \u003e= 0\n```\n\nThe full pseudo-code:\n```cpp\n// Point\t   - Position that is being tested\n// Vertex0,1,2 - Vertices of the triangle in **clockwise order**\n\n// Directional vertices along the edges of the triangle in clockwise order\nEdgeDir0 = Vertex1 - Vertex0\nEdgeDir1 = Vertex2 - Vertex1\nEdgeDir2 = Vertex0 - Vertex2\n\n// Directional vertices pointing from the triangle vertices to the point\nPointDir0 = Point - Vertex0\nPointDir1 = Point - Vertex1\nPointDir2 = Point - Vertex2\n\n// Test if each cross-product results in a positive area\nif(\n\tEdgeDir0.x * PointDir0.y - EdgeDir0.y * PointDir0.x \u003e= 0 \u0026\u0026\n\tEdgeDir1.x * PointDir1.y - EdgeDir1.y * PointDir1.x \u003e= 0 \u0026\u0026\n\tEdgeDir2.x * PointDir2.y - EdgeDir2.y * PointDir2.x \u003e= 0\n)\n{\n\t// CurPoint is in triangle!\n}\n```\n\n## Scaling\n\nIf I was to throw thousands of points at a triangle in a for-loop using this algorithm then not all variables have to be re-calculated for each point.\n\nThe vectors `EdgeDir0`, `EdgeDir1`, `EdgeDir2` only have to be calculated once. For each point the vectors `PointDir0`, `PointDir1`, `PointDir2` have to be recreated.\n\n```\nEdgeDir0 = Vertex1 - Vertex0\nEdgeDir1 = Vertex2 - Vertex1\nEdgeDir2 = Vertex0 - Vertex2\nforeach(CurPoint in LotsOfPoints)\n{\n\tPointDir0 = Point - Vertex0\n\tPointDir1 = Point - Vertex1\n\tPointDir2 = Point - Vertex2\n\tif(\n\t\tEdgeDir0.x * PointDir0.y - EdgeDir0.y * PointDir0.x \u003e= 0 \u0026\u0026\n\t\tEdgeDir1.x * PointDir1.y - EdgeDir1.y * PointDir1.x \u003e= 0 \u0026\u0026\n\t\tEdgeDir2.x * PointDir2.y - EdgeDir2.y * PointDir2.x \u003e= 0\n\t)\n\t{\n\t\t// CurPoint is in triangle!\n\t}\n}\n```\nWhich results in the total overhead for each point being\n\nSubtractions|Multiplications|Comparisons\n:-:|:-:|:-:\n6|6|3\n\n# Barycentric Coordinate Method\n\nWith some barycentric coordinate trickery one can derive a coordiante system that allows a triangle to be described as a linear \"mixture\" of its three vertices, with some constraints on how they mix.\n\nThe Barycentric coordinates of a triangle involves it's three position-vectors `p1`, `p2`, `p3`.\nUsing these three points, any new point `p'` _within_ this triangle can be generated by *mixing* the three vertex positions according to three scalar weights `w1`, `w2`, `w3` such that:\n`p' = w1 * p1 + w2 * p2 + w3 * p3`.\nThis is just a linear combination of three points, but `p'` isnt meant to just be any wild combination of three points. What you actually want is for the combination of three points to always land on the triangular surface that they all contain. This is called a [convex combination](https://en.wikipedia.org/wiki/Convex_combination) where if you want to only reach every point within this triangle then you must bind these three weight weight to the conditions of being non-negative and also summing to the exact value `1.0`. Making this the full barycentric equation for a triangle defined by three points:\n\n\u003cimg src=\"https://latex.codecogs.com/png.latex?\\dpi{150}\u0026space;\\\\w_1\u0026space;\u003e=\u0026space;0\\\\w_2\u0026space;\u003e=\u0026space;0\\\\w_3\u0026space;\u003e=\u0026space;0\\\\\u0026space;p'\u0026space;=\u0026space;w_1\u0026space;*\u0026space;p_1\u0026space;\u0026plus;\u0026space;w_2\u0026space;*\u0026space;p_2\u0026space;\u0026plus;\u0026space;w_3\u0026space;*\u0026space;p_3\\\\\u0026space;1\u0026space;=\u0026space;w_1\u0026space;\u0026plus;\u0026space;w_2\u0026space;\u0026plus;\u0026space;w_3\\\\\u0026space;%\u0026space;p'_x\u0026space;=\u0026space;w_1\u0026space;*\u0026space;p_1_x\u0026space;\u0026plus;\u0026space;w_2\u0026space;*\u0026space;p_2_x\u0026space;\u0026plus;\u0026space;w_3\u0026space;*\u0026space;p_3_x\\\\\u0026space;p'_y\u0026space;=\u0026space;w_1\u0026space;*\u0026space;p_1_y\u0026space;\u0026plus;\u0026space;w_2\u0026space;*\u0026space;p_2_y\u0026space;\u0026plus;\u0026space;w_3\u0026space;*\u0026space;p_3_y\\\\\" title=\"\\\\w_1 \u003e= 0\\\\w_2 \u003e= 0\\\\w_3 \u003e= 0\\\\ p' = w_1 * p_1 + w_2 * p_2 + w_3 * p_3\\\\ 1 = w_1 + w_2 + w_3\\\\ % p'_x = w_1 * p_1_x + w_2 * p_2_x + w_3 * p_3_x\\\\ p'_y = w_1 * p_1_y + w_2 * p_2_y + w_3 * p_3_y\\\\\" /\u003e\n\nIn this case though. **You already have `p'` and want to determine if it is within this triangle!** Time to cleverly work backwards!\n\n---\n\nSo given a `p1`, `p2`, `p3` and `p'`, you have to figure out the three positive unknowns `w1`, `w2`, `w3` that balance these conditions. Some linear alg!\n\nSo starting with this:\n\n\u003cimg src=\"https://latex.codecogs.com/png.latex?\\dpi{150}\u0026space;\\\\w_1\u0026space;\u003e=\u0026space;0\\\\w_2\u0026space;\u003e=\u0026space;0\\\\w_3\u0026space;\u003e=\u0026space;0\\\\\u0026space;p'\u0026space;=\u0026space;w_1\u0026space;*\u0026space;p_1\u0026space;\u0026plus;\u0026space;w_2\u0026space;*\u0026space;p_2\u0026space;\u0026plus;\u0026space;w_3\u0026space;*\u0026space;p_3\\\\\u0026space;1\u0026space;=\u0026space;w_1\u0026space;\u0026plus;\u0026space;w_2\u0026space;\u0026plus;\u0026space;w_3\\\\\u0026space;%\u0026space;p'_x\u0026space;=\u0026space;w_1\u0026space;*\u0026space;p_1_x\u0026space;\u0026plus;\u0026space;w_2\u0026space;*\u0026space;p_2_x\u0026space;\u0026plus;\u0026space;w_3\u0026space;*\u0026space;p_3_x\\\\\u0026space;p'_y\u0026space;=\u0026space;w_1\u0026space;*\u0026space;p_1_y\u0026space;\u0026plus;\u0026space;w_2\u0026space;*\u0026space;p_2_y\u0026space;\u0026plus;\u0026space;w_3\u0026space;*\u0026space;p_3_y\\\\\" title=\"\\\\w_1 \u003e= 0\\\\w_2 \u003e= 0\\\\w_3 \u003e= 0\\\\ p' = w_1 * p_1 + w_2 * p_2 + w_3 * p_3\\\\ 1 = w_1 + w_2 + w_3\\\\ % p'_x = w_1 * p_1_x + w_2 * p_2_x + w_3 * p_3_x\\\\ p'_y = w_1 * p_1_y + w_2 * p_2_y + w_3 * p_3_y\\\\\" /\u003e\n\nHow about expanding those vectors into their individual(2D) dimensions.\n\n\u003cimg src=\"https://latex.codecogs.com/png.latex?\\dpi{150}\u0026space;\\\\w1\u0026space;\u003e=\u0026space;0\\\\w2\u0026space;\u003e=\u0026space;0\\\\w3\u0026space;\u003e=\u0026space;0\\\\\u0026space;p'_x\u0026space;=\u0026space;w_1\u0026space;*\u0026space;p_1_x\u0026space;\u0026plus;\u0026space;w_2\u0026space;*\u0026space;p_2_x\u0026space;\u0026plus;\u0026space;w_3\u0026space;*\u0026space;p_3_x\\\\\u0026space;p'_y\u0026space;=\u0026space;w_1\u0026space;*\u0026space;p_1_y\u0026space;\u0026plus;\u0026space;w_2\u0026space;*\u0026space;p_2_y\u0026space;\u0026plus;\u0026space;w_3\u0026space;*\u0026space;p_3_y\\\\\u0026space;1\u0026space;=\u0026space;w_1\u0026space;\u0026plus;\u0026space;w_2\u0026space;\u0026plus;\u0026space;w_3\\\\\" title=\"\\\\w1 \u003e= 0\\\\w2 \u003e= 0\\\\w3 \u003e= 0\\\\ p'_x = w_1 * p_1_x + w_2 * p_2_x + w_3 * p_3_x\\\\ p'_y = w_1 * p_1_y + w_2 * p_2_y + w_3 * p_3_y\\\\ 1 = w_1 + w_2 + w_3\\\\\" /\u003e\n\nNow that looks like a matrix! Take out all those weights and put it into a vector!\n\n\u003cimg src=\"https://latex.codecogs.com/png.latex?\\dpi{150}\u0026space;\\\\w_1\u0026space;\u003e=\u0026space;0\\\\w_2\u0026space;\u003e=\u0026space;0\\\\w_3\u0026space;\u003e=\u0026space;0\\\\\u0026space;\\begin{bmatrix}\u0026space;p'_x\\\\\u0026space;p'_y\\\\\u0026space;1\\\\\u0026space;\\end{bmatrix}\u0026space;=\u0026space;\\begin{bmatrix}\u0026space;p_1_x\u0026space;\u0026\u0026space;p_2_x\u0026space;\u0026\u0026space;p_3_x\u0026space;\\\\\u0026space;p_1_y\u0026space;\u0026\u0026space;p_2_y\u0026space;\u0026\u0026space;p_3_y\u0026space;\\\\\u0026space;1\u0026space;\u0026\u0026space;1\u0026space;\u0026\u0026space;1\u0026space;\\end{bmatrix}\u0026space;*\u0026space;\\begin{bmatrix}\u0026space;w_1\\\\\u0026space;w_2\\\\\u0026space;w_3\\\\\u0026space;\\end{bmatrix}\" title=\"\\\\w_1 \u003e= 0\\\\w_2 \u003e= 0\\\\w_3 \u003e= 0\\\\ \\begin{bmatrix} p'_x\\\\ p'_y\\\\ 1\\\\ \\end{bmatrix} = \\begin{bmatrix} p_1_x \u0026 p_2_x \u0026 p_3_x \\\\ p_1_y \u0026 p_2_y \u0026 p_3_y \\\\ 1 \u0026 1 \u0026 1 \\end{bmatrix} * \\begin{bmatrix} w_1\\\\ w_2\\\\ w_3\\\\ \\end{bmatrix}\" /\u003e\n\nSo the solution is to invert that 3x3 matrix there and multiplying it by the point we are testing it against to get the resulting three weights. And once you get the three weights. All you have to do is test if they are positive(**Note**: If this smells somewhat like a close derivation of the cross-product method you're right!)\n\n\u003cimg src=\"https://latex.codecogs.com/png.latex?\\dpi{150}\u0026space;\\\\w_1\u0026space;\u003e=\u0026space;0\\\\w_2\u0026space;\u003e=\u0026space;0\\\\w_3\u0026space;\u003e=\u0026space;0\\\\\u0026space;\\\u0026space;\\begin{bmatrix}\u0026space;p_1_x\u0026space;\u0026\u0026space;p_2_x\u0026space;\u0026\u0026space;p_3_x\u0026space;\\\\\u0026space;p_1_y\u0026space;\u0026\u0026space;p_2_y\u0026space;\u0026\u0026space;p_3_y\u0026space;\\\\\u0026space;1\u0026space;\u0026\u0026space;1\u0026space;\u0026\u0026space;1\u0026space;\\end{bmatrix}\u0026space;^{-1}\u0026space;*\u0026space;\\begin{bmatrix}\u0026space;p'_x\\\\\u0026space;p'_y\\\\\u0026space;1\\\\\u0026space;\\end{bmatrix}\u0026space;=\u0026space;\\begin{bmatrix}\u0026space;w_1\\\\\u0026space;w_2\\\\\u0026space;w_3\\\\\u0026space;\\end{bmatrix}\" title=\"\\\\w_1 \u003e= 0\\\\w_2 \u003e= 0\\\\w_3 \u003e= 0\\\\ \\ \\begin{bmatrix} p_1_x \u0026 p_2_x \u0026 p_3_x \\\\ p_1_y \u0026 p_2_y \u0026 p_3_y \\\\ 1 \u0026 1 \u0026 1 \\end{bmatrix} ^{-1} * \\begin{bmatrix} p'_x\\\\ p'_y\\\\ 1\\\\ \\end{bmatrix} = \\begin{bmatrix} w_1\\\\ w_2\\\\ w_3\\\\ \\end{bmatrix}\" /\u003e\n\nMatrix inverse... This is where it gets a little hairy\n\n\u003cimg src=\"https://latex.codecogs.com/png.latex?\\dpi{150}\u0026space;\\\\w_1\u0026space;\u003e=\u0026space;0\\\\w_2\u0026space;\u003e=\u0026space;0\\\\w_3\u0026space;\u003e=\u0026space;0\\\\\u0026space;\\\u0026space;Det\u0026space;=\u0026space;-p_2_x\u0026space;p_1_y\u0026plus;p_3_x\u0026space;p_1_y\u0026plus;p_1_x\u0026space;p_2_y-p_3_x\u0026space;p_2_y-p_1_x\u0026space;p_3_y\u0026plus;p_2_x\u0026space;p_3_y\\\\\u0026space;\\\\\u0026space;\\frac{1}{Det}\u0026space;*\u0026space;\\begin{bmatrix}\u0026space;p_2_y-p_3_y\u0026space;\u0026\u0026space;-p_2_x\u0026plus;p_3_x\u0026space;\u0026\u0026space;-p_3_x\u0026space;p_2_y\u0026plus;p_2_x\u0026space;p_3_y\\\\\u0026space;-p_1_y\u0026plus;p_3_y\u0026space;\u0026\u0026space;p_1_x-p_3_x\u0026space;\u0026\u0026space;p_3_x\u0026space;p_1_y-p_1_x\u0026space;p_3_y\\\\\u0026space;p_1_y-p_2_y\u0026space;\u0026\u0026space;-p_1_x\u0026plus;p_2_x\u0026space;\u0026\u0026space;-p_2_x\u0026space;p_1_y\u0026plus;p_1_x\u0026space;p_2_y\\\\\u0026space;\\end{bmatrix}\u0026space;*\u0026space;\\begin{bmatrix}\u0026space;p'_x\\\\\u0026space;p'_y\\\\\u0026space;1\\\\\u0026space;\\end{bmatrix}\u0026space;=\u0026space;\\begin{bmatrix}\u0026space;w_1\\\\\u0026space;w_2\\\\\u0026space;w_3\\\\\u0026space;\\end{bmatrix}\" title=\"\\\\w_1 \u003e= 0\\\\w_2 \u003e= 0\\\\w_3 \u003e= 0\\\\ \\ Det = -p_2_x p_1_y+p_3_x p_1_y+p_1_x p_2_y-p_3_x p_2_y-p_1_x p_3_y+p_2_x p_3_y\\\\ \\\\ \\frac{1}{Det} * \\begin{bmatrix} p_2_y-p_3_y \u0026 -p_2_x+p_3_x \u0026 -p_3_x p_2_y+p_2_x p_3_y\\\\ -p_1_y+p_3_y \u0026 p_1_x-p_3_x \u0026 p_3_x p_1_y-p_1_x p_3_y\\\\ p_1_y-p_2_y \u0026 -p_1_x+p_2_x \u0026 -p_2_x p_1_y+p_1_x p_2_y\\\\ \\end{bmatrix} * \\begin{bmatrix} p'_x\\\\ p'_y\\\\ 1\\\\ \\end{bmatrix} = \\begin{bmatrix} w_1\\\\ w_2\\\\ w_3\\\\ \\end{bmatrix}\" /\u003e\n\n\nAnd with this, `w1`, `w2`, and `w3` all reduce to relatively \"simple\" linear equations and all that would have to be checked is if they are greater than `0`!\n\nHere is the equivalent code in GLSL. Keep in mind that GLSL defines matrices and vectors as column-major. So going `vec3(1)` means a 1x3(_width_ x _height_) arrangement of elements and `mat3(vec(1),vec(2),vec(3))` means a 3x3 matrix with the columns(the vertical ones) being defined by `{1,1,1}`,`{2,2,2}`,`{3,3,3}`.\n```c\nbool PointInTriangleBarycentric(\n\tin vec2 Triangle[3],\n\tin vec2 Point\n)\n{\n\tmat3 Barycentric = inverse(\n\t\tmat3(\n\t\t\tTriangle[0], 1.0f,\n\t\t\tTriangle[1], 1.0f,\n\t\t\tTriangle[2], 1.0f\n\t\t)\n\t);\n\n\tvec3 Weights = Barycentric * vec3( Point, 1.0 );\n\n\tif(\n\t\t// Weights.x \u003e= 0.0f \u0026\u0026\n\t\t// Weights.y \u003e= 0.0f \u0026\u0026\n\t\t// Weights.z \u003e= 0.0f\n\t\tall( greaterThanEqual( Weights, vec3(0.0f) ) )\n\t)\n\t{\n\t\treturn true;\n\t}\n\t\n\treturn false;\n}\n```\n\nThough, this is a pretty naive approach. It still has its uses.\nIf you wanted to test a million points against a single triangle. You'd have to do a single matrix inverse(pretty expensive!) and then the overhead for testing each individual point you want to test would be: a matrix-vector multiplication(a 3x3 matrix times an ℝ³ vector, which is pretty much just three dot-products) and three comparisons:\n\nAdditions|Multiplications|Comparisons\n:-:|:-:|:-:\n6|9|3\n\nThough, a matrix inverse is pretty expensive operation to do. Especially in a context of having possibly thousands upon millions of triangles and a matrix inverse each involving almost dozens of multiplications, additions, and a division on top of it all. Some more clever observations can allow for some slim optimizations. Especially since all that matters is if the weights are positive or not.\n\n## Optimizations\n\n\n\n---\n\nThe two directional vectors are derived from three points that describe a plane while the two scalars are typically denoted as *U* and *V* and determine how much these two directional vectors should mix together to create another point on this plane.\nSince a triangle has three points, these two vectors can be derived by picking any one point of the triangle and obtaining two directional vectors from this point to the two other points.\n\nThe *U* and *V* scalar values are typically normalized within the [0.0,1.0] range to easily translate these values into *percentages* that determine how much much the two vectors should contribute to the resulting vector.\nEx, if I had the two directional vectors `( 8, 2 )` and `( 7, 1 )` and the `U` `V` values `0.5` `1.0` respectively. The resulting point is ` ( 8, 2 ) * 0.5 + ( 7, 1 ) * 1.0 = ( 11, 3 )` which in english would be something like `I want 50% of the ( 8, 2 ) direction and 140% of ( 7, 1 )`.\n\nThe actual *triangle shape* is made by constraining the `U` and `V` values so that rather than describing a plane very generally it instead will stay within the bounds of a triangle.\n\n\nThe first two constraints are `U \u003e= 0` and `V \u003e= 0` which guarentee that the U,V coordinates are always on the *positive* side of the two vectors and do not go backwards, off the triangle. The third constraint is `U + V \u003c= 1` is [just the line](http://www.wolframalpha.com/input/?i=1+-+x+-+y++%3D+0) `y = 1 - x` [turned into an inequality](http://www.wolframalpha.com/input/?i=1+-+x+-+y++%3D%3E+0) such that all solutions to the inequality equate to a point within a triangle. The actual derivation of this involves some barycentric coordinate limbo.\n\n\n\nGiven a triangle, the two directional vectors are easy to calculate. Pick any of the three points of a triangle, get the vector direction from this point, to the two other points ( which is just a vector subtraction). After the two directional vectors are obtained, now all that has to be done to see if a point is within a triangle is [*projecting*](https://en.wikipedia.org/wiki/Vector_projection) this point against the two directional vectors to get the *U* and *V* values to test against the three conditions.\n\nProjecting a point against these two vectors to get the *U* and *V* values is but trivial dot-product arithmetic. First, another directional vector has to be created as a positional-vector and a directional-vector wouldn't make sense in this instance. The very same point that was selected to in step 1 to generate the first two directional vectors must be used once more to generate a third directional vector between this triangle vertex and the point being sampled against (another vector subtraction). This new vector will then be dot-product-ed against the two directional edges ( vertial vector multiplication and horizontal addition ) to finally determine the `U` and `V` values to test against `U \u003e= 0`, `V \u003e= 0`, and `U + V \u003c= 1`.\n\n![](media/BarycentricMethod.gif)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwunkolo%2Fqtriangle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwunkolo%2Fqtriangle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwunkolo%2Fqtriangle/lists"}