From 51b5ec5904f2d631c1d665ce2a5da75d9f936de5 Mon Sep 17 00:00:00 2001
From: dengwirda
Date: Sun, 27 Jul 2025 20:25:04 +1000
Subject: [PATCH 01/14] Add min/max limits for dual mesh weight optim.
---
jigsawpy/jig_l.py | 10 ++++++++++
jigsawpy/jig_t.py | 9 +++++++++
jigsawpy/libsaw.py | 10 ++++++++++
jigsawpy/loadjig.py | 5 +++++
jigsawpy/savejig.py | 5 +++++
5 files changed, 39 insertions(+)
diff --git a/jigsawpy/jig_l.py b/jigsawpy/jig_l.py
index c1287a8..4c1f73f 100644
--- a/jigsawpy/jig_l.py
+++ b/jigsawpy/jig_l.py
@@ -269,6 +269,16 @@ class libsaw_jig_t(ct.Structure):
("optm_qlim", real_t),
+ # OPTM_WMIN - {default=-7./8.} lower limit on dual
+ # mesh weights relative to cell radius.
+
+ ("optm_wmin", real_t),
+
+ # OPTM_WMAX - {default=+1./80} upper limit on dual
+ # mesh weights relative to cell radius.
+
+ ("optm_wmax", real_t),
+
# OPTM_TRIA - {default= true} allow for optimisation
# of TRIA grid geometry.
diff --git a/jigsawpy/jig_t.py b/jigsawpy/jig_t.py
index d61028e..a6f71f3 100644
--- a/jigsawpy/jig_t.py
+++ b/jigsawpy/jig_t.py
@@ -207,6 +207,12 @@
function above which gradient-based optimisation is
attempted.
+ OPTS.OPTM_WMIN - {default=-7./8.} lower limit on dual
+ mesh weights relative to cell radius.
+
+ OPTS.OPTM_WMAX - {default=+1./80} upper limit on dual
+ mesh weights relative to cell radius.
+
OPTS.OPTM_TRIA - {default= true} allow for optimisation
of TRIA grid geometry.
@@ -322,6 +328,9 @@ def __init__(self):
self.optm_qtol = None
self.optm_qlim = None
+ self.optm_wmin = None
+ self.optm_wmax = None
+
self.optm_zip_ = None
self.optm_div_ = None
self.optm_tria = None
diff --git a/jigsawpy/libsaw.py b/jigsawpy/libsaw.py
index ca6faec..e8f3245 100644
--- a/jigsawpy/libsaw.py
+++ b/jigsawpy/libsaw.py
@@ -317,6 +317,16 @@ def put_jig_t(jigt, jigl):
elif (jigt.optm_qlim is not None):
raise TypeError("OPTM-QLIM type")
+ if (is_type_t(jigt.optm_wmin, float)):
+ jigl.optm_wmin = real_t(jigt.optm_wmin)
+ elif (jigt.optm_wmin is not None):
+ raise TypeError("OPTM-WMIN type")
+
+ if (is_type_t(jigt.optm_wmax, float)):
+ jigl.optm_wmax = real_t(jigt.optm_wmax)
+ elif (jigt.optm_wmax is not None):
+ raise TypeError("OPTM-WMAX type")
+
if (is_type_t(jigt.optm_tria, bool)):
jigl.optm_tria = indx_t(jigt.optm_tria)
elif (jigt.optm_tria is not None):
diff --git a/jigsawpy/loadjig.py b/jigsawpy/loadjig.py
index 3be3e03..dffdba2 100644
--- a/jigsawpy/loadjig.py
+++ b/jigsawpy/loadjig.py
@@ -160,6 +160,11 @@ def loadjig(name, opts):
if (item == "OPTM_QLIM"):
opts.optm_qlim = float(ltag[1])
+ if (item == "OPTM_WMIN"):
+ opts.optm_wmin = float(ltag[1])
+ if (item == "OPTM_WMAX"):
+ opts.optm_wmax = float(ltag[1])
+
if (item == "OPTM_ZIP_"):
opts.optm_zip_ = bool(ltag[1])
if (item == "OPTM_DIV_"):
diff --git a/jigsawpy/savejig.py b/jigsawpy/savejig.py
index 3cb9fef..2bd9948 100644
--- a/jigsawpy/savejig.py
+++ b/jigsawpy/savejig.py
@@ -203,6 +203,11 @@ def savejig(name, opts):
if (opts.optm_qlim is not None):
savereal(fptr, opts.optm_qlim, "OPTM_QLIM")
+ if (opts.optm_wmin is not None):
+ savereal(fptr, opts.optm_wmin, "OPTM_WMIN")
+ if (opts.optm_wmax is not None):
+ savereal(fptr, opts.optm_wmax, "OPTM_WMAX")
+
if (opts.optm_zip_ is not None):
savebool(fptr, opts.optm_zip_, "OPTM_ZIP_")
if (opts.optm_div_ is not None):
From 2084cd62a896370c5133f10c464f4529061c72fc Mon Sep 17 00:00:00 2001
From: dengwirda
Date: Sun, 27 Jul 2025 20:51:55 +1000
Subject: [PATCH 02/14] Adjust TETRIS iteration scheme
---
jigsawpy/jigsaw.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/jigsawpy/jigsaw.py b/jigsawpy/jigsaw.py
index 2fda9b7..f78fba1 100644
--- a/jigsawpy/jigsaw.py
+++ b/jigsawpy/jigsaw.py
@@ -253,6 +253,9 @@ def jitter(opts, imax, ibad, mesh=None):
for iter in range(imax):
+ if (opts.optm_dual is not None):
+ OPTS.optm_dual = iter == imax - 1
+
if (mesh.point is not None and
mesh.point.size != +0):
@@ -363,7 +366,7 @@ def tetris(opts, nlev, mesh=None):
OPTS.hfun_hmin = \
opts.hfun_hmin * SCAL
- if (opts.hfun_file is not None):
+ if (opts.hfun_file is not None and SCAL > 1.0):
#------------------------ create/write current HFUN data
path = Path(opts.hfun_file).parent
name = Path(opts.hfun_file).stem
@@ -384,7 +387,7 @@ def tetris(opts, nlev, mesh=None):
savemsh(OPTS.hfun_file, HFUN)
#------------------------ call JIGSAW kernel at this lev
- jitter(OPTS, 4 + (nlev > 0) * 44, 3, mesh)
+ jitter(OPTS, 4 + (nlev > 0) *12, 3, mesh)
nlev = nlev - 1
SCAL = SCAL / 2.
From cf78c83beb8280c51602828f833d2e0e6564cd5a Mon Sep 17 00:00:00 2001
From: dengwirda
Date: Tue, 12 Aug 2025 01:54:51 +1000
Subject: [PATCH 03/14] Ensure correct reshape for scaling
---
jigsawpy/project.py | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/jigsawpy/project.py b/jigsawpy/project.py
index e4c5a1c..ea247a9 100644
--- a/jigsawpy/project.py
+++ b/jigsawpy/project.py
@@ -98,14 +98,14 @@ def project(mesh, proj, sign):
if (mesh.value is not None and
mesh.value.size != +0):
- mesh.value = mesh.value * SCAL
+ mesh.value*= SCAL.reshape(mesh.value.shape)
if (mesh.power is not None and
mesh.power.size != +0):
SPOW = np.sqrt(SCAL)
- mesh.power = mesh.power * SPOW
+ mesh.power*= SPOW.reshape(mesh.power.shape)
elif (kind == "euclidean-grid" or
kind == "ellipsoid-grid"):
@@ -220,8 +220,7 @@ def project(mesh, proj, sign):
tset.append(triaB)
- mesh.tria3 = \
- np.concatenate(tset, axis=0)
+ mesh.tria3 = np.concatenate(tset, axis=0)
#----------------------------------- setup proj.'d extras
if (mesh.slope is not None and
@@ -236,7 +235,7 @@ def project(mesh, proj, sign):
mesh.value = np.reshape(
mesh.value, mesh.value.size)
- mesh.value = mesh.value * SCAL
+ mesh.value*= SCAL.reshape(mesh.value.shape)
if (mesh.power is not None and
mesh.power.size != +0):
@@ -246,6 +245,6 @@ def project(mesh, proj, sign):
SPOW = np.sqrt(SCAL)
- mesh.power = mesh.power * SPOW
+ mesh.power*= SPOW.reshape(mesh.power.shape)
return
From e640170c070995d8303eb63e0b6bf43306f17079 Mon Sep 17 00:00:00 2001
From: dengwirda
Date: Tue, 12 Aug 2025 02:04:45 +1000
Subject: [PATCH 04/14] Update bindings for jigsaw-1.1.0.xx
---
jigsawpy/__init__.py | 6 ++++--
jigsawpy/jig_l.py | 16 ++++++++++++++++
jigsawpy/jig_t.py | 15 +++++++++++++++
jigsawpy/jigsaw.py | 15 +++++++++++----
jigsawpy/libsaw.py | 10 ++++++++++
jigsawpy/loadjig.py | 8 ++++++--
jigsawpy/savejig.py | 5 +++++
setup.py | 33 +++++++++++----------------------
8 files changed, 78 insertions(+), 30 deletions(-)
diff --git a/jigsawpy/__init__.py b/jigsawpy/__init__.py
index 67f8f9b..884f8ea 100644
--- a/jigsawpy/__init__.py
+++ b/jigsawpy/__init__.py
@@ -13,9 +13,9 @@
* JIGSAW: Interface to the JIGSAW meshing library.
------------------------------------------------------------
*
- * Last updated: 10 Jan., 2023
+ * Last updated: 04 Aug., 2025
*
- * Copyright 2019-2023
+ * Copyright 2019-2025
* Darren Engwirda
* d.engwirda@gmail.com
* https://github.com/dengwirda
@@ -65,6 +65,8 @@
from jigsawpy.savemsh import savemsh
from jigsawpy.loadjig import loadjig
from jigsawpy.savejig import savejig
+from jigsawpy.loadprj import loadprj
+from jigsawpy.saveprj import saveprj
from jigsawpy.certify import certify
diff --git a/jigsawpy/jig_l.py b/jigsawpy/jig_l.py
index 4c1f73f..519ef66 100644
--- a/jigsawpy/jig_l.py
+++ b/jigsawpy/jig_l.py
@@ -107,6 +107,22 @@ class libsaw_jig_t(ct.Structure):
("mesh_iter", indx_t),
+ # MESH_ORPH - {default=true} allow "orphaned" facets
+ # to remain in the mesh. A K-1 dimensional subcell is
+ # orphaned if it does not appear in any K-dimensional
+ # cell, e.g. a surface triangle that is not the face
+ # of any interior tetrahedron.
+
+ ("mesh_orph", indx_t),
+
+ # MESH_LOCK - {default=false} prevent the refinement
+ # of subfaces during subsequent refinement. The
+ # refinement of a K-dimensional cell is deferred if
+ # doing so would cause any K-1 dimensional subfaces to
+ # be refined.
+
+ ("mesh_lock", indx_t),
+
# MESH_TOP1 - {default=false} enforce 1-dim. topolog-
# ical constraints. 1-dim. edges are refined until all
# embedded nodes are "locally 1-manifold", i.e. nodes
diff --git a/jigsawpy/jig_t.py b/jigsawpy/jig_t.py
index a6f71f3..e0f6b47 100644
--- a/jigsawpy/jig_t.py
+++ b/jigsawpy/jig_t.py
@@ -96,6 +96,18 @@
inement iterations. Set ITER=N to see progress after
N iterations.
+ OPTS.MESH_ORPH - {default=true} allow "orphaned" facets
+ to remain in the mesh. A K-1 dimensional subcell is
+ orphaned if it does not appear in any K-dimensional
+ cell, e.g. a surface triangle that is not the face
+ of any interior tetrahedron.
+
+ OPTS.MESH_LOCK - {default=false} prevent the refinement
+ of subfaces during subsequent refinement. The
+ refinement of a K-dimensional cell is deferred if
+ doing so would cause any K-1 dimensional subfaces to
+ be refined.
+
OPTS.MESH_TOP1 - {default=false} enforce 1-dim. topolog-
ical constraints. 1-dim. edges are refined until all
embedded nodes are "locally 1-manifold", i.e. nodes
@@ -292,6 +304,9 @@ def __init__(self):
self.mesh_iter = None
+ self.mesh_orph = None
+ self.mesh_lock = None
+
self.mesh_dims = None
self.mesh_top1 = None
diff --git a/jigsawpy/jigsaw.py b/jigsawpy/jigsaw.py
index f78fba1..378fee6 100644
--- a/jigsawpy/jigsaw.py
+++ b/jigsawpy/jigsaw.py
@@ -253,16 +253,19 @@ def jitter(opts, imax, ibad, mesh=None):
for iter in range(imax):
+ npts = npwr = 0
+ if (mesh.point is not None): npts = mesh.point.size
+ if (mesh.power is not None): npwr = mesh.power.size
+
if (opts.optm_dual is not None):
- OPTS.optm_dual = iter == imax - 1
+ OPTS.optm_dual = iter == imax-1 or npts == npwr
if (mesh.point is not None and
mesh.point.size != +0):
nvrt = mesh.point.size
- keep = np.full(
- (nvrt), True, dtype=bool)
+ keep = np.full((nvrt), True, dtype=bool)
#------------------------------ setup initial conditions
path = Path(opts.mesh_file).parent
@@ -304,11 +307,15 @@ def jitter(opts, imax, ibad, mesh=None):
#------------------------------ keep nodes far from seam
init = jigsaw_msh_t()
- init.point = mesh.point[keep]
+ if (mesh.point is not None):
+ init.point = mesh.point[keep]
+ if (mesh.power is not None):
+ init.power = mesh.power[keep]
savemsh(OPTS.init_file, init)
#------------------------------ call JIGSAW with new ICs
+ print("optm_dual:", OPTS.optm_dual)
jigsaw (OPTS, mesh) # noqa
return
diff --git a/jigsawpy/libsaw.py b/jigsawpy/libsaw.py
index e8f3245..34c9f2d 100644
--- a/jigsawpy/libsaw.py
+++ b/jigsawpy/libsaw.py
@@ -221,6 +221,16 @@ def put_jig_t(jigt, jigl):
elif (jigt.mesh_iter is not None):
raise TypeError("MESH-ITER type")
+ if (is_type_t(jigt.mesh_orph, bool)):
+ jigl.mesh_orph = indx_t(jigt.mesh_orph)
+ elif (jigt.mesh_orph is not None):
+ raise TypeError("MESH-ORPH type")
+
+ if (is_type_t(jigt.mesh_lock, bool)):
+ jigl.mesh_lock = indx_t(jigt.mesh_lock)
+ elif (jigt.mesh_lock is not None):
+ raise TypeError("MESH-LOCK type")
+
if (is_type_t(jigt.mesh_top1, bool)):
jigl.mesh_top1 = indx_t(jigt.mesh_top1)
elif (jigt.mesh_top1 is not None):
diff --git a/jigsawpy/loadjig.py b/jigsawpy/loadjig.py
index dffdba2..4507994 100644
--- a/jigsawpy/loadjig.py
+++ b/jigsawpy/loadjig.py
@@ -33,8 +33,7 @@ def loadjig(name, opts):
#----------------------- parse next non-null section
line = line.strip()
- if (line[0] == "#"):
- continue
+ if (line[0] == "#"): continue
ltag = line.split("=")
item = ltag[0].upper().strip()
@@ -103,6 +102,11 @@ def loadjig(name, opts):
if (item == "MESH_ITER"):
opts.mesh_iter = int(ltag[1])
+ if (item == "MESH_ORPH"):
+ opts.mesh_orph = bool(ltag[1])
+ if (item == "MESH_LOCK"):
+ opts.mesh_lock = bool(ltag[1])
+
if (item == "MESH_DIMS"):
opts.mesh_dims = int(ltag[1])
diff --git a/jigsawpy/savejig.py b/jigsawpy/savejig.py
index 2bd9948..2c41ccd 100644
--- a/jigsawpy/savejig.py
+++ b/jigsawpy/savejig.py
@@ -146,6 +146,11 @@ def savejig(name, opts):
if (opts.mesh_iter is not None):
saveints(fptr, opts.mesh_iter, "MESH_ITER")
+ if (opts.mesh_orph is not None):
+ savebool(fptr, opts.mesh_orph, "MESH_ORPH")
+ if (opts.mesh_lock is not None):
+ savebool(fptr, opts.mesh_lock, "MESH_LOCK")
+
if (opts.mesh_dims is not None):
saveints(fptr, opts.mesh_dims, "MESH_DIMS")
diff --git a/setup.py b/setup.py
index 374404f..0992fa9 100644
--- a/setup.py
+++ b/setup.py
@@ -5,7 +5,6 @@
import shutil
from setuptools import setup, find_packages, Command
-from packaging import version
NAME = "jigsawpy"
DESCRIPTION = \
@@ -13,7 +12,7 @@
AUTHOR = "Darren Engwirda"
AUTHOR_EMAIL = "d.engwirda@gmail.com"
URL = "https://github.com/dengwirda/"
-VERSION = "1.0.0"
+VERSION = "1.1.0"
REQUIRES_PYTHON = ">=3.6.0"
KEYWORDS = "Mesh-generation Delaunay Voronoi"
@@ -45,18 +44,6 @@
LONG_DESCRIPTION = DESCRIPTION
-def get_cmake_version():
- try:
- out = subprocess.check_output(
- ["cmake", "--version"]).decode("utf-8")
- sln = out.splitlines()[0]
- ver = sln.split()[2]
- return ver
-
- except:
- print("cmake not found!")
-
-
class build_external(Command):
description = "build external JIGSAW dependencies"
@@ -114,22 +101,24 @@ def run(self):
self.announce("cmake complie", level=3)
- ver = get_cmake_version()
- if version.parse(ver) < version.parse("3.12"):
+ try:
compilecall = [
"cmake", "--build", ".",
"--config", "Release",
- "--target", "install"
+ "--target", "install",
+ "--parallel", "4"
]
- else:
+ subprocess.run(
+ compilecall, check=True)
+
+ except:
compilecall = [
"cmake", "--build", ".",
"--config", "Release",
- "--target", "install",
- "--parallel", "4"
+ "--target", "install"
]
-
- subprocess.run(compilecall, check=True)
+ subprocess.run(
+ compilecall, check=True)
self.announce("cmake cleanup", level=3)
From cf62b8646eedf7d0d6819236260907e4ab888350 Mon Sep 17 00:00:00 2001
From: dengwirda
Date: Tue, 12 Aug 2025 02:06:26 +1000
Subject: [PATCH 05/14] Add load/save routines for projection obj.
---
jigsawpy/loadprj.py | 58 ++++++++++++++++++++++++++
jigsawpy/saveprj.py | 99 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 157 insertions(+)
create mode 100644 jigsawpy/loadprj.py
create mode 100644 jigsawpy/saveprj.py
diff --git a/jigsawpy/loadprj.py b/jigsawpy/loadprj.py
new file mode 100644
index 0000000..a004b89
--- /dev/null
+++ b/jigsawpy/loadprj.py
@@ -0,0 +1,58 @@
+
+from pathlib import Path
+from jigsawpy.prj_t import jigsaw_prj_t
+
+
+def loadprj(name, opts):
+ """
+ LOADPRJ: load a PRJ config. obj. from file.
+
+ LOADPRJ(NAME, OPTS)
+
+ OPTS is a user-defined set of projection data. See PRJ_t
+ for details.
+
+ Data in OPTS is loaded on-demand -- any objects included
+ in the file will be read.
+
+ """
+
+ if (not isinstance(name, str)):
+ raise TypeError("Incorrect type: NAME.")
+
+ if (not isinstance(opts, jigsaw_prj_t)):
+ raise TypeError("Incorrect type: OPTS.")
+
+ with Path(name).open("r") as fptr:
+ while (True):
+
+ #----------------------- get the next line from file
+ line = fptr.readline()
+
+ if (len(line) != +0):
+
+ #----------------------- parse next non-null section
+ line = line.strip()
+ if (line[0] == "#"): continue
+
+ ltag = line.split("=")
+ item = ltag[0].upper().strip()
+
+ #-------------------------------------- PROJ options
+ if (item == "PRJID"):
+ opts.prjID = ltag[1].strip()
+
+ if (item == "RADII"):
+ opts.radii = float(ltag[1])
+
+ if (item == "X-MID"):
+ opts.xbase = float(ltag[1])
+
+ if (item == "Y-MID"):
+ opts.ybase = float(ltag[1])
+
+ else:
+ #----------------------- reached end-of-file: done!!
+ break
+
+ return
diff --git a/jigsawpy/saveprj.py b/jigsawpy/saveprj.py
new file mode 100644
index 0000000..ada761f
--- /dev/null
+++ b/jigsawpy/saveprj.py
@@ -0,0 +1,99 @@
+
+from pathlib import Path
+from jigsawpy.prj_t import jigsaw_prj_t
+
+
+def savechar(fptr, sval, stag):
+
+ if (isinstance(sval, str)):
+ fptr.write(" " + stag + "=" + sval + "\n")
+ else:
+ raise TypeError(
+ "Invalid [CHARA] data: OPTS." + stag)
+
+ return
+
+
+def saveints(fptr, ival, stag):
+
+ if (isinstance(ival, int)):
+ fptr.write(
+ " " + stag + "=" + str(ival) + "\n")
+ else:
+ raise TypeError(
+ "Invalid [INDEX] data: OPTS." + stag)
+
+ return
+
+
+def savereal(fptr, fval, stag):
+
+ if (isinstance(fval, float)):
+ fptr.write(
+ " " + stag + "=" + str(fval) + "\n")
+ else:
+ raise TypeError(
+ "Invalid [FLOAT] data: OPTS." + stag)
+
+ return
+
+
+def savebool(fptr, bval, stag):
+
+ if (isinstance(bval, bool)):
+ if (bval is True):
+ fptr.write(" " + stag + "=TRUE \n")
+ else:
+ fptr.write(" " + stag + "=FALSE\n")
+ else:
+ raise TypeError(
+ "Invalid [BOOLS] data: OPTS." + stag)
+
+ return
+
+
+def saveprj(name, opts):
+ """
+ SAVEPRJ: save a PRJ config. obj. to file.
+
+ SAVEPRJ(NAME, OPTS)
+
+ OPTS is a user-defined set of projection data. See PRJ_t
+ for details.
+
+ Data in OPTS is written as-needed -- any objects defined
+ will be saved to file.
+
+ """
+
+ if (not isinstance(name, str)):
+ raise TypeError("Incorrect type: NAME.")
+
+ if (not isinstance(opts, jigsaw_prj_t)):
+ raise TypeError("Incorrect type: OPTS.")
+
+ fext = Path(name).suffix
+
+ if (fext.strip() != ".prj"): name = name + ".prj"
+
+ with Path(name).open("w") as fptr:
+
+ fptr.write(
+ "# " + Path(name).name +
+ " config. file;"
+ " created by JIGSAW's PYTHON interface \n")
+
+ #------------------------------------------ MISC options
+ if (opts.prjID is not None):
+ savechar(fptr, opts.prjID, "PRJID")
+
+ if (opts.radii is not None):
+ savereal(fptr, opts.radii, "RADII")
+
+ if (opts.xbase is not None):
+ savereal(fptr, opts.xbase, "X-MID")
+
+ if (opts.ybase is not None):
+ savereal(fptr, opts.ybase, "Y-MID")
+
+ return
From df1886f01a7ef13bb9d5136337c0db8a4bf122ec Mon Sep 17 00:00:00 2001
From: dengwirda
Date: Tue, 12 Aug 2025 02:10:24 +1000
Subject: [PATCH 06/14] Simplify dependencies
---
requirements.txt | 1 -
1 file changed, 1 deletion(-)
diff --git a/requirements.txt b/requirements.txt
index f1c7422..6bad103 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1,2 @@
numpy
scipy
-packaging
From 5a570519315135edfb69043f0120919bbbfbde59 Mon Sep 17 00:00:00 2001
From: dengwirda
Date: Tue, 12 Aug 2025 02:51:07 +1000
Subject: [PATCH 07/14] Simplify README.md
---
README.md | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index bc667e6..c738055 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,9 @@
-`JIGSAW` is an unstructured mesh generator and tessellation library; designed to generate high-quality triangulations and polyhedral decompositions of general planar, surface and volumetric domains. `JIGSAW` includes refinement-based algorithms for the construction of new meshes, optimisation-driven techniques for the improvement of existing grids, as well as routines to assemble (restricted) Delaunay tessellations, Voronoi complexes and Power diagrams.
+`JIGSAW` is an unstructured mesh generator and tessellation library; designed to generate high-quality triangulations and polyhedral decompositions of general planar, surface and volumetric domains.
+
+`JIGSAW` includes refinement-based algorithms for constructing new meshes, optimisation-driven techniques for improving existing grids, as well as routines to assemble (restricted) Delaunay tessellations, Voronoi complexes and Power diagrams.
This package provides a `Python` based scripting interface to the underlying `JIGSAW` mesh generator, including a range of additional facilities for file I/O, mesh visualisation and post-processing operations.
@@ -21,7 +23,7 @@ This package provides a `Python` based scrip
python3 setup.py install
python3 example.py --IDnumber=0
-Note: installation of `JIGSAW` requires a `c++` compiler and the `cmake` utility. `JIGSAW` may also be installed as a `conda` package. See here for details.
+Note: installation of `JIGSAW` requires a `c++` compiler and the `cmake` utility.
### `Function Listing`
@@ -75,7 +77,7 @@ This program may be freely redistributed under the condition that the copyright
### `References`
-There are a number of publications that describe the algorithms used in `JIGSAW` in detail. If you make use of `JIGSAW` in your work, please consider including a reference to the following:
+There are a number of publications that describe the algorithms used in `JIGSAW` in detail. If you make use of `JIGSAW` in your work, please include references as appropriate:
`[1]` - Darren Engwirda: Generalised primal-dual grids for unstructured co-volume schemes, J. Comp. Phys., 375, pp. 155-176, https://doi.org/10.1016/j.jcp.2018.07.025, 2018.
From 17b658e2d032769af7c9bc9ae85ddff98bd2e55d Mon Sep 17 00:00:00 2001
From: dengwirda
Date: Tue, 12 Aug 2025 03:07:03 +1000
Subject: [PATCH 08/14] Squashed 'external/jigsaw/' changes from
595ff4b..a3afb93
a3afb93 Merge pull request #56 from dengwirda/dev-v1.1.0
125afa4 Update mesh optim. div/zip schedule
8db4b07 Add indexing hint for element-centred h(x) eval.
77f7a06 Update unit test config.'s
eb99e86 Simplify README.md
e29bcd7 Simplify README.md
c2273db Update CI workflow
26120b1 Ensure R^d+1 weight is initialised
05e8951 Ensure rDT face counter is initialised
dae33aa Force fast stdout for unit tests
e9f8d67 Update API interface
47c877a Correct circumball array size
275d7db Update CI workflow
4c71306 Simplify README.md
36e4db6 Simplify README.md
4944f66 Update CI workflow
ccb7894 Simplify README.md
c048284 Squelch compiler warnings
00bb2f4 Simplify README.md
e2eac64 Update CI workflow
5650f61 Add unit tests for MARCHE in E^3
1362b95 Remove discontinued conda build detail
14c170e Add min/max limits for dual mesh weight optim.
d0f9f4c Add min/max limits for dual mesh weight optim.
b5f81c7 Add min/max limits for dual mesh weight optim.
4c11b70 Adjust dual mesh weight optimisation
48593bd Update CI workflow
4047d6c Reduce error on -ve h(x) data to warning
930249c Squelch unused variables
304234f Fix spatially-variable initial point selection
d563c1c Fix auto disambiguation of multiple types
22c1fdb Fix | vs || usage
fa0cfef std::