{"id":19876723,"url":"https://github.com/dirktoewe/deltri4s","last_synced_at":"2025-07-09T09:07:33.579Z","repository":{"id":176082565,"uuid":"172978833","full_name":"DirkToewe/DelTri4S","owner":"DirkToewe","description":"(Constrained) 2D Delaunay Triangulation in Scala(JS)","archived":false,"fork":false,"pushed_at":"2019-03-06T20:13:10.000Z","size":205,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-24T05:35:08.519Z","etag":null,"topics":["computational-geometry","constrained-delaunay-triangulation","delaunay-triangulation","scala","scala-js"],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DirkToewe.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,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-02-27T19:43:13.000Z","updated_at":"2021-08-30T21:29:05.000Z","dependencies_parsed_at":null,"dependency_job_id":"66078455-7b5c-4f29-99c5-d6423eabacfa","html_url":"https://github.com/DirkToewe/DelTri4S","commit_stats":null,"previous_names":["dirktoewe/deltri4s"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DirkToewe%2FDelTri4S","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DirkToewe%2FDelTri4S/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DirkToewe%2FDelTri4S/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DirkToewe%2FDelTri4S/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DirkToewe","download_url":"https://codeload.github.com/DirkToewe/DelTri4S/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241304294,"owners_count":19941101,"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":["computational-geometry","constrained-delaunay-triangulation","delaunay-triangulation","scala","scala-js"],"created_at":"2024-11-12T16:34:04.561Z","updated_at":"2025-03-01T01:42:44.005Z","avatar_url":"https://github.com/DirkToewe.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Animated DelTri4S Logo](https://dirktoewe.github.io/DelTri4S/logo.svg)\n\nDelTri4S is a 2D constrained Delaunay Triangulation library for Scala and ScalaJS.\nTo that end it implements both mutable and immutable data structures\nthat allow the fast creation, manipulation and traversal of 2D triangle meshes.\nFor educational and debugging purposes, DelTri4S supports the export of triangle\nmesh objects to an interactive HTML visualization. Said visualizations allow to\nretrace the modifications that were made to the mesh thus helping the understanding\nand debugging of algorithms.\n\nFor a demonstration of how a Constrained Delaunay Triangulation is performed,\nsee [this example](https://dirktoewe.github.io/DelTri4S/cdt_example.html#-1).\n\n  * [Mesh Creation](#mesh-creation)\n  * [Mesh Traversal](#mesh-traversal)\n  * [Delaunay Triangulation](#delaunay-triangulation)\n  * [Constrained Delaunay Triangulation](#constrained-delaunay-triangulation)\n\nMesh Creation\n-------------\n`TriMesh` is the super-type for mutable triangle meshes. A triangle mesh in DelTri4S\nis composed of the following elements:\n\n\u003cdl\u003e\n  \u003cdt\u003eNodes:\u003cdd\u003e Uniquely identifiable points on the 2D plane. A mesh may contain multiple\n  nodes with the same coordinates but it will not be Delaunay triangulatable.\n   \n  \u003cdt\u003eSegments:\u003cdd\u003e Lines that are uniquely defined by a pair of Nodes. A mesh may contain\n  intersecting segments but it woll not be Delaunay triangulatable. Segments are used in\n  constrained Delaunay Triangulations to confine triangulated areas and to enforce that\n  certain edges are part of the triangulation.\n\n  \u003cdt\u003eTriangle:\u003cdd\u003e Triangles that are uniquely identified by a triple of Nodes with positive\n  orientation. Each node pair may only be part of one triangle.\n\u003c/dl\u003e\n\n`TriMeshIndexed` is the fastest `TriMesh` implementation available.\n```scala\nimport deltri.TriMeshIndexed\n\nval mesh = TriMeshIndexed.empty\nval a = mesh.addNode(0,0)\nval b = mesh.addNode(2,0)\nval c = mesh.addNode(1,1)\nmesh.addTri(a,b,c)\nval d = mesh.addNode(0,0.4)\nmesh.addTri(a,c,d)\nval e = mesh.addNode(0,0.8)\nmesh.addTri(d,c,e)\nmesh.addSegment(d,c)\n```\n\n![Mesh Creation Example](./docs/readme_example1.svg)\n\nThe Node objects returned by `addNode` are used to reference nodes in further\noperations like adding segments or triangles. The Node object contains the x\nand y coordinate but the `equals` and `hashCode` method use object identity to\ncompare objects. The Node objects themselves do however not contain any reference\nto their mesh and do not prevent the mesh object from being garbage collected.\n\nThe `toHTML` methods returns an HTML document string containing an interactive visualization.\n```scala\nimport java.awt.Desktop.getDesktop\nimport java.nio.file.Files\nimport java.util.Arrays.asList\n\nval tmp = Files.createTempFile(\"example1_\",\".html\")\nFiles.write( tmp, asList(mesh.toHtml) )\ngetDesktop.browse(tmp.toUri resolve \"#-1\")\n```\n\n`TriMeshImmutable` is an immutable/persistent triangle mesh data structure. It is roughly 50%\nslower than `TriMeshIndexed` but allows for faster and simpler undo/backtracking operations and\nis safely shareable without protective copying. \n```scala\nval mesh1 = TriMeshImmutable.empty\nval(mesh2,a) = mesh1 addedNode (0 , 0)\nval(mesh3,b) = mesh2 addedNode (2 , 0)\nval(mesh4,c) = mesh3 addedNode (1 , 1)\nval(mesh5,d) = mesh4 addedNode (0 , 0.4)\nval(mesh6,e) = mesh5 addedNode (0 , 0.8)\nval mesh7    = mesh6.addedTri(a,b,c)\n                    .addedTri(a,c,d)\n                    .addedTri(d,c,e)\n                    .addedSegment(d,c)\n```\nNote that the example code above can be greatly simplified by using pure functional programming\ntechniques, e.g. by using the State Monad, as implement for example in [Cats](https://typelevel.org/cats/datatypes/state.html)\nor [ScalaZ](http://eed3si9n.com/learning-scalaz/State.html). `TriMeshMutable` is a wrapper around\n`TriMeshImmutable` that allow the conversion from and to a mutable representation in O(1).\n\nMesh Traversal\n--------------\nThe `adjacent` method allows fast querying of neighbor/adjacent triangles. For the nodes\n`a` and `b`, `adjacent(a,b)` returns the node `c` iff there is a triangle `(a,b,c)` in\nthe mesh. Keep in mind that triangles in a mesh all have a positive orientation. \n\n```scala\nval     mesh = TriMeshIndexed.empty()\nval a = mesh addNode (-1, -1)\nval b = mesh addNode (+1, -1)\nval c = mesh addNode (+1, +1)\nval d = mesh addNode (-1, +1)\nmesh addTri (a,b,c)\nmesh addTri (c,d,a)\n\nassert( mesh.adjacent(a,c).exists )\nassert( mesh.adjacent(a,c).nodeOrNull  eq  d )\n\nfor( e \u003c- mesh.adjacent(a,b) )\n  assert( e eq c )\n```\n\n`foreachTri` allows the traversal of all triangles in a mesh.\n\n```scala\nmesh foreachTri {\n  (a,b,c) =\u003e\n    printf( \"Tri(\\n  %s,\\n  %s,\\n  %s\\n)\\n\", a,b,c )\n}\n```\n\n`foreachTriAround(a)` traverses every triangle that contains node `a`.\n\n```scala\nmesh.foreachTriAround(a){\n  (b,c) =\u003e\n    printf( \"Tri(\\n  %s,\\n  %s,\\n  %s\\n)\\n\", a,b,c )\n}\n```\n\nAnalogue to the aforementioned methods there is also `foreachNode`, `foreachSegement` and\n`foreachSegmentAround`.\n\nNote that the author of DelTri4S is not a pure functional programmer and most traversal operations\nare not well suited for that programming paradigm. Contributions to improve that situation are of\ncourse welcome.\n\nDelaunay Triangulation\n----------------------\nThe companion object of every `TriMesh` class exposes a `delaunay` method which takes a sequence\nof points and returns a mesh of said class containing delaunay triangulation. `TriMeshTaped` is a\nthin wrapper around a `TriMesh` that records every modification made to the mesh, which can be\ninspected using `toHTML`.\n\n```scala\nval rng = new Random(1337)\nval points = Array.tabulate(128){\n  _ =\u003e (rng.nextDouble*2-1,\n        rng.nextDouble*2-1)\n}.toMap.toSeq // \u003c- remove duplicates\n\nval (mesh,nodes) = TriMeshTaped.delaunay(points: _*)\n```\n\n![Delaunay Triangulation Example](./docs/readme_example2.svg)\n\nConstrained Delaunay Triangulation\n----------------------------------\nThe input to the Constrained Delaunay Triangulation (CDT) in DelTri4S is a Piecewise Linear Complex\n(PLC). A PLC consists of:\n\n  * A sequence of `nodes: Seq[(Double,Double)]`\n  * A sequence of `segments: Seq[(Int,Int)]`, where `Seq( (i,j) )` means the CDT must contain edge `(nodes(i),nodes(j))`\n  * Information about holes and the boundary\n\nHoles must be entirely enclosed by a closed chain of segments. One way to specify holes or the outside,\nis to specify one or more nodes that lie inside of a hole or the outside.\n\n```scala\nval center = (0.0, 0.0)\nval innerCircle = Vector range (45,405,90) map (_.toRadians) map {\n  angle =\u003e ( 0.5 * Math.cos(angle),\n             0.5 * Math.sin(angle) )\n}\nval outerCircle = Vector range (45,405,90) map (_.toRadians) map {\n  angle =\u003e ( 1 * Math.cos(angle),\n             1 * Math.sin(angle) )\n}\n\nval plc = PLC(\n  nodes     = (innerCircle :+ center) ++ outerCircle,\n  segments  =  innerCircle.indices map { i =\u003e i -\u003e (i+1) % innerCircle.length },\n  holeNodes = Set(innerCircle.length) // \u003c- put a hole in the center\n)\n\nval (mesh, meshNodes) = TriMeshTaped.delaunayConstrained(plc)\n```\n\n![Delaunay Triangulation Example](./docs/readme_example3.svg)\n\nAnother way to specify holes is to specifiy one or more segments, to the right/positive side of which,\nall triangles are to be removed.\n\n```scala\nval innerCircle = Vector range (0,360,120) map (_.toRadians) map {\n  angle =\u003e ( 0.5 * Math.cos(angle),\n    0.5 * Math.sin(angle) )\n}\nval outerCircle = Vector range (0,360,120) map (_.toRadians) map {\n  angle =\u003e ( 1 * Math.cos(angle),\n    1 * Math.sin(angle) )\n}\n\nval plc = PLC(\n  nodes     = innerCircle ++ outerCircle,\n  segments  = innerCircle.indices map { i =\u003e i -\u003e (i+1) % innerCircle.length },\n  orientedBoundarySegments = Seq( (0,1) )\n)\n\nval (mesh, meshNodes) = TriMeshTaped.delaunayConstrained(plc)\n```\n\n![Delaunay Triangulation Example](./docs/readme_example4.svg)\n\nIf the PLC is enclosed by an outer boundary of segments, `confinedBySegments` can be set to true in\nthe PLC and the CDT will not contain any triangles outside of the outermost segment boundary.\n\n```scala\nval innerCircle = Vector range ( 0,360,30) map (_.toRadians) map {\n  angle =\u003e ( 0.6 * Math.cos(angle),\n             0.6 * Math.sin(angle) )\n}\nval outerCircle = Vector range (15,375,30) map (_.toRadians) map {\n  angle =\u003e ( 1 * Math.cos(angle),\n             1 * Math.sin(angle) )\n}\nval n      = innerCircle.length\nval points = innerCircle ++ outerCircle\n\nval segments = innerCircle.indices flatMap { i =\u003e Seq(\n   i    -\u003e (i+n),\n  (i+n) -\u003e (i+1) % n\n)}\n\nval plc = PLC(\n  points,\n  segments,\n  confinedBySegments = true\n)\n\nval (mesh, nodes) = TriMeshTaped.delaunayConstrained(plc)\n```\n\n![Delaunay Triangulation Example](./docs/readme_example5.svg)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdirktoewe%2Fdeltri4s","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdirktoewe%2Fdeltri4s","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdirktoewe%2Fdeltri4s/lists"}