118 std::size_t requestedLevels,
121 std::size_t targetSamplesPerAxis)
125 out.
logDecades = std::max(0.25f, std::min(12.0f, logDecades));
127 if (field.
empty() || field.
width() < 2u || field.
height() < 2u || requestedLevels == 0u) {
131 float maxProbability = 0.0f;
132 for (std::size_t y = 0u; y < field.
height(); ++y) {
133 for (std::size_t x = 0u; x < field.
width(); ++x) {
134 maxProbability = std::max(maxProbability, probability(field, x, y));
138 if (!(maxProbability > 1.0e-30f) || !std::isfinite(
static_cast<double>(maxProbability))) {
142 const std::size_t count = std::max<std::size_t>(1u, requestedLevels);
143 out.
levels.reserve(count);
144 for (std::size_t i = 0u; i < count; ++i) {
145 const float f =
static_cast<float>(i + 1u) /
static_cast<float>(count + 1u);
150 const float exponent = -out.
logDecades * (1.0f - f);
151 level = maxProbability * std::pow(10.0f, exponent);
153 level = maxProbability * f;
155 out.
levels.push_back(level);
161 for (std::size_t li = 0u; li < out.
levels.size(); ++li) {
162 const float level = out.
levels[li];
166 const float normalizedLevel =
167 static_cast<float>(li + 1u) /
static_cast<float>(out.
levels.size() + 1u);
169 for (std::size_t y0 = 0u; y0 + 1u < field.
height(); y0 += stride) {
170 const std::size_t y1 = std::min(field.
height() - 1u, y0 + stride);
174 for (std::size_t x0 = 0u; x0 + 1u < field.
width(); x0 += stride) {
175 const std::size_t x1 = std::min(field.
width() - 1u, x0 + stride);
180 const float v0 = probability(field, x0, y0);
181 const float v1 = probability(field, x1, y0);
182 const float v2 = probability(field, x1, y1);
183 const float v3 = probability(field, x0, y1);
186 if (v0 > level) mask |= 1;
187 if (v1 > level) mask |= 2;
188 if (v2 > level) mask |= 4;
189 if (v3 > level) mask |= 8;
190 if (mask == 0 || mask == 15) {
194 const P2 p0 = { xCoordinate(field, x0), yCoordinate(field, y0) };
195 const P2 p1 = { xCoordinate(field, x1), yCoordinate(field, y0) };
196 const P2 p2 = { xCoordinate(field, x1), yCoordinate(field, y1) };
197 const P2 p3 = { xCoordinate(field, x0), yCoordinate(field, y1) };
200 edge[0] = interpolate(p0, p1, v0, v1, level);
201 edge[1] = interpolate(p1, p2, v1, v2, level);
202 edge[2] = interpolate(p2, p3, v2, v3, level);
203 edge[3] = interpolate(p3, p0, v3, v0, level);
206 case 1:
case 14: addSegment(out, edge[3], edge[0], level, normalizedLevel);
break;
207 case 2:
case 13: addSegment(out, edge[0], edge[1], level, normalizedLevel);
break;
208 case 3:
case 12: addSegment(out, edge[3], edge[1], level, normalizedLevel);
break;
209 case 4:
case 11: addSegment(out, edge[1], edge[2], level, normalizedLevel);
break;
210 case 6:
case 9: addSegment(out, edge[0], edge[2], level, normalizedLevel);
break;
211 case 7:
case 8: addSegment(out, edge[3], edge[2], level, normalizedLevel);
break;
213 const float centre = 0.25f * (v0 + v1 + v2 + v3);
214 if (centre > level) {
215 addSegment(out, edge[3], edge[2], level, normalizedLevel);
216 addSegment(out, edge[0], edge[1], level, normalizedLevel);
218 addSegment(out, edge[3], edge[0], level, normalizedLevel);
219 addSegment(out, edge[2], edge[1], level, normalizedLevel);
224 const float centre = 0.25f * (v0 + v1 + v2 + v3);
225 if (centre > level) {
226 addSegment(out, edge[3], edge[0], level, normalizedLevel);
227 addSegment(out, edge[2], edge[1], level, normalizedLevel);
229 addSegment(out, edge[3], edge[2], level, normalizedLevel);
230 addSegment(out, edge[0], edge[1], level, normalizedLevel);