Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Contour Smoothing Option: Dual Marching Squares #53

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"npm.packageManager": "yarn"
}
16 changes: 16 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "test",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [],
"label": "yarn: test",
"detail": "tape 'test/**/*-test.js' && eslint src"
}
]
}
57 changes: 56 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,62 @@ If *size* is specified, sets the expected size of the input *values* grid to the

<a name="contours_smooth" href="#contours_smooth">#</a> <i>contours</i>.<b>smooth</b>([<i>smooth</i>]) · [Source](https://github.com/d3/d3-contour/blob/master/src/contours.js), [Examples](https://observablehq.com/@d3/contours-smooth)

If *smooth* is specified, sets whether or not the generated contour polygons are smoothed using linear interpolation. If *smooth* is not specified, returns the current smoothing flag, which defaults to true.
If *smooth* is specified, sets the smoothing method to use when generating the contour polygons. If *smooth* is not specified, returns the current smoothing method, which defaults to true.

The available *smooth* options are:

- `false`: Smoothing is disabled.
- `true` or `"linear"` (Default): Linear interpolation smoothing, as described in the original [Marching Squares algorithm](https://en.wikipedia.org/wiki/Marching_squares).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `true` or `"linear"` (Default): Linear interpolation smoothing, as described in the original [Marching Squares algorithm](https://en.wikipedia.org/wiki/Marching_squares).
- `true` or `"linear"` (default): Linear interpolation smoothing, as described in the original [Marching Squares algorithm](https://en.wikipedia.org/wiki/Marching_squares).

- `"linearDual"`: Dual linear interpolation smoothing, as described in the [Dual Marching Squares algorithm](https://ieeexplore.ieee.org/document/7459173).

In general, the quality of each smoothing method is inversely proportional to its runtime performance.

Additionally, the density of the source data impacts contour smoothness: the differences between the smoothing methods are more noticeable with low-density data than they are with high-density data. With _very_ high-density data, there is no discernible quality difference between the three methods.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Additionally, the density of the source data impacts contour smoothness: the differences between the smoothing methods are more noticeable with low-density data than they are with high-density data. With _very_ high-density data, there is no discernible quality difference between the three methods.
Additionally, the density of the source data impacts contour smoothness: the differences between the smoothing methods are more noticeable with low-density data than they are with medium-density data. With high-density data, there is no discernible quality difference between the three methods.


<table>
<thead>
<tr>
<th colspan="2" scope="colgroup"></th>
<th colspan="2" scope="colgroup" style="text-align: center;">Low-density data</th>
<th colspan="2" scope="colgroup" style="text-align: center;">High-density data</th>
</tr>
<tr>
<th colspan="2" scope="col">Smoothing method</th>
<th scope="col" style="text-align: center;">Contour<br/>quality</th>
<th scope="col" style="text-align: center;">Performance<br/>cost*</th>
<th scope="col" style="text-align: center;">Contour<br/>quality</th>
<th scope="col" style="text-align: center;">Performance<br/>cost*</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">None</th>
<th scope="row"><code>false</code></th>
<td>Poor</td>
<td>+0%</td>
<td>Good</td>
<td>+0%</td>
</tr>
<tr>
<th scope="row">Linear (Default)</th>
<th scope="row"><code>true</code> or<br /><code>"linear"</code></th>
<td>Good</td>
<td>+2.40%</td>
<td>Best</td>
<td>+1.55%</td>
</tr>
<tr>
<th scope="row">Dual linear</th>
<th scope="row"><code>"linearDual"</code></th>
<td>Best</td>
<td>+2.70%</td>
<td>Best</td>
<td>+2.00%</td>
</tr>
</tbody>
</table>

\* Estimated performance cost based on 2 sample datasets.
Comment on lines +112 to +156
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove (this is interesting in the PR but too overwhelming for the README)


<a name="contours_thresholds" href="#contours_thresholds">#</a> <i>contours</i>.<b>thresholds</b>([<i>thresholds</i>]) · [Source](https://github.com/d3/d3-contour/blob/master/src/contours.js), [Examples](https://observablehq.com/@d3/volcano-contours)

Expand Down
35 changes: 34 additions & 1 deletion src/contours.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,39 @@ export default function() {
});
}

/**
* Applies smoothing to an iso-ring according to the Dual Marching Squares algorithm.
* @param {[number, number][]} ring The sorted list of (x,y) coordinates of points for a given iso-ring.
* @param {number[]} values The underlying grid values.
* @param {number} value The iso-value for this iso-ring.
*/
function smoothLinearDual(ring, values, value) {
var point, x, y, x1, y1;

// The first step in Dual Marching Squares smoothing is linear interpolation.
smoothLinear(ring, values, value);

for (var i = 0; i < ring.length; i++) {
point = ring[i];
x = point[0];
y = point[1];

if (i < ring.length - 1) {
// Next point
x1 = ring[i + 1][0];
y1 = ring[i + 1][1];

// Set the current point to the midpoint between it and the next point.
point[0] = x + (x1 - x) / 2;
point[1] = y + (y1 - y) / 2;
} else {
// This is the last point, complete the ring by matching the first point
point[0] = ring[0][0];
point[1] = ring[0][1];
}
}
}

contours.contour = contour;

contours.size = function(_) {
Expand All @@ -196,7 +229,7 @@ export default function() {
};

contours.smooth = function(_) {
return arguments.length ? (smooth = _ ? smoothLinear : noop, contours) : smooth === smoothLinear;
return arguments.length ? (smooth = _ === 'linearDual' ? smoothLinearDual : _ ? smoothLinear : noop, contours) : smooth === smoothLinear || smooth === smoothLinearDual;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return arguments.length ? (smooth = _ === 'linearDual' ? smoothLinearDual : _ ? smoothLinear : noop, contours) : smooth === smoothLinear || smooth === smoothLinearDual;
return arguments.length ? (smooth = _ === 'dual' ? smoothLinearDual : _ ? smoothLinear : noop, contours) : smooth === smoothLinear || smooth === smoothLinearDual;

};

return contours;
Expand Down
Loading