784 std::vector<std::vector<OGRPoint>>& existingSamples,
786 uint64_t queinnecMultiplier,
787 xso::xoshiro_4x64_plus& rng,
788 std::string allocation,
790 std::vector<double> weights,
794 T nanInt =
static_cast<T
>(band.
nan);
799 if (xBlockSize != width) {
803 yBlockSize = std::min(128, height);
807 band.
p_buffer = VSIMalloc3(xBlockSize, yBlockSize + fw.
vpad * 2, band.
size);
808 T *p_buffer =
reinterpret_cast<T *
>(band.
p_buffer);
809 int8_t *p_access =
nullptr;
811 access.band.p_buffer = VSIMalloc3(xBlockSize, yBlockSize,
access.band.size);
812 p_access =
reinterpret_cast<int8_t *
>(
access.band.p_buffer);
819 optim.
init(numStrata, xBlockSize, yBlockSize);
823 int yBlocks = (height + yBlockSize - 1) / yBlockSize;
826 for (
int yBlock = 0; yBlock < yBlocks; yBlock++) {
829 int yOff = yBlock * yBlockSize;
831 int yValid = std::min(yBlockSize, height - yBlock * yBlockSize);
835 CPLErr err = band.
p_band->RasterIO(GF_Read, xOff, yOff, xValid, yValid, band.
p_buffer, xValid, yValid, band.
type, 0, 0);
837 throw std::runtime_error(
"error reading block from raster.");
841 int stratYOff = yOff - fw.
vpad * 2;
842 int stratYValid = yValid + fw.
vpad * 2;
843 CPLErr err = band.
p_band->RasterIO(GF_Read, xOff, stratYOff, xValid, stratYValid, band.
p_buffer, xValid, stratYValid, band.
type, 0, 0);
845 throw std::runtime_error(
"error reading block from raster.");
851 CPLErr err =
access.band.p_band->RasterIO(GF_Read, xOff, yOff, xValid, yValid,
access.band.p_buffer, xValid, yValid, GDT_Int8, 0, 0);
853 throw std::runtime_error(
"error reading block from raster.");
859 CPLErr err = optim.
band.
p_band->RasterIO(GF_Read, xOff, yOff, xValid, yValid, optim.
band.
p_buffer, xValid, yValid, optim.
band.
type, 0, 0);
861 throw std::runtime_error(
"error reading block from raster.");
871 int newBlockStart = (yBlock == 0) ? 0 : width * fw.
vpad * 2;
874 for (
int y = 0; y < yValid; y++) {
876 fw.
reset(yBlock * yBlockSize + y);
880 for (
int x = 0; x < fw.
hpad; x++) {
881 T val = p_buffer[newBlockStart + y * width + x];
884 bool isNan = val == nanInt;
885 bool accessible = !
access.used || p_access[y * width + x] != 1;
895 optim.
update(y * width + x, val);
902 if (alreadySampled) {
903 existingSamples[val].push_back(
existing.getPoint(index.
x, index.
y));
907 if (accessible && !alreadySampled) {
916 for (
int x = fw.
hpad; x < width - fw.
hpad; x++) {
917 T val = p_buffer[newBlockStart + y * width + x];
920 bool isNan = val == nanInt;
921 bool accessible = !
access.used || p_access[y * width + x] != 1;
931 optim.
update(y * width + x, val);
938 if (alreadySampled) {
939 existingSamples[val].push_back(
existing.getPoint(index.
x, index.
y));
943 int start = newBlockStart + y * width + x - fw.
hpad;
946 fw.
m[fwyi + x] = p_buffer[start] == p_buffer[start + 1] &&
947 p_buffer[start] == p_buffer[start + 2];
950 fw.
m[fwyi + x] = p_buffer[start] == p_buffer[start + 1] &&
951 p_buffer[start] == p_buffer[start + 2] &&
952 p_buffer[start] == p_buffer[start + 3] &&
953 p_buffer[start] == p_buffer[start + 4];
956 fw.
m[fwyi + x] = p_buffer[start] == p_buffer[start + 1] &&
957 p_buffer[start] == p_buffer[start + 2] &&
958 p_buffer[start] == p_buffer[start + 3] &&
959 p_buffer[start] == p_buffer[start + 4] &&
960 p_buffer[start] == p_buffer[start + 5] &&
961 p_buffer[start] == p_buffer[start + 6];
964 throw std::runtime_error(
"wcol must be one of 3, 5, 6.");
968 if (accessible && !alreadySampled) {
975 fw.
valid[fwyi + x] =
true;
980 if (fw.
check(fwIndex.
x, fwIndex.
y)) {
982 int start = newBlockStart + y * width + x - 2 * width * fw.
vpad;
985 add = p_buffer[start] == p_buffer[start + width * 1] &&
986 p_buffer[start] == p_buffer[start + width * 2];
989 add = p_buffer[start] == p_buffer[start + width * 1] &&
990 p_buffer[start] == p_buffer[start + width * 2] &&
991 p_buffer[start] == p_buffer[start + width * 3] &&
992 p_buffer[start] == p_buffer[start + width * 4];
995 add = p_buffer[start] == p_buffer[start + width * 1] &&
996 p_buffer[start] == p_buffer[start + width * 2] &&
997 p_buffer[start] == p_buffer[start + width * 3] &&
998 p_buffer[start] == p_buffer[start + width * 4] &&
999 p_buffer[start] == p_buffer[start + width * 5] &&
1000 p_buffer[start] == p_buffer[start + width * 6];
1008 if (queinnecRand.
next()) {
1017 for (
int x = width - fw.
hpad; x < width; x++) {
1018 T val = p_buffer[newBlockStart + y * width + x];
1021 bool isNan = val == nanInt;
1022 bool accessible = !
access.used || p_access[y * width + x] != 1;
1032 optim.
update(y * width + x, val);
1039 if (alreadySampled) {
1040 existingSamples[val].push_back(
existing.getPoint(index.
x, index.
y));
1044 if (accessible && !alreadySampled) {
1054 if (fwyi == width * fw.
wrow) {
1062 VSIFree(
access.band.p_buffer);
1076 return strataSampleCounts;
1164 std::string allocation,
1165 std::vector<double> weights,
1175 std::string layerName,
1178 std::vector<std::pair<std::string, int>> mapStratMapping,
1180 std::optional<uint64_t> random_state,
1181 std::string filename,
1182 std::string tempFolder)
1186 double mindist_sq = mindist * mindist;
1187 bool useMindist = mindist != 0;
1191 bool mapped = mapStratMapping.size() != 0;
1193 std::mutex bandMutex;
1194 std::mutex rngMutex;
1195 std::mutex accessMutex;
1204 band.
nan = band.
p_band->GetNoDataValue();
1211 GDALDriver *p_driver = GetGDALDriverManager()->GetDriverByName(
"MEM");
1213 throw std::runtime_error(
"unable to create output sample dataset driver.");
1215 GDALDataset *p_samples = p_driver->Create(
"", 0, 0, 0, GDT_Unknown,
nullptr);
1217 throw std::runtime_error(
"unable to create output dataset with driver.");
1221 OGRLayer *p_layer = p_samples->CreateLayer(
"samples", p_wrapper->
getSRS(), wkbPoint,
nullptr);
1223 throw std::runtime_error(
"unable to create output dataset layer.");
1227 OGRFieldDefn strataField(band.
p_band->GetDescription(), OFTInteger);
1228 OGRErr err = p_layer->CreateField(&strataField);
1230 throw std::runtime_error(
"cannot create field for strata name.");
1234 for (
size_t i = 0; i < mapStratMapping.size(); i++) {
1235 OGRFieldDefn strataField(mapStratMapping[i].first.c_str(), OFTInteger);
1236 OGRErr err = p_layer->CreateField(&strataField);
1238 throw std::runtime_error(
"cannot create create field for strata name.");
1255 std::vector<double> xCoords, yCoords;
1256 std::vector<std::vector<OGRPoint>> existingSamples(numStrata);
1271 xso::xoshiro_4x64_plus rng = random_state ? xso::xoshiro_4x64_plus(*random_state) : xso::xoshiro_4x64_plus();
1302 std::vector<int64_t> strataSampleCounts;
1303 if (method ==
"random") {
1304 switch (band.
type) {
1307 existing, indices, existingSamples,
1308 multiplier, rng, allocation, optim,
1309 weights, width, height);
1313 existing, indices, existingSamples,
1314 multiplier, rng, allocation, optim,
1315 weights, width, height);
1319 existing, indices, existingSamples,
1320 multiplier, rng, allocation, optim,
1321 weights, width, height);
1326 switch (band.
type) {
1329 indices, queinnecIndices, fw, existingSamples,
1330 multiplier, queinnecMultiplier, rng, allocation,
1331 optim, weights, width, height);
1335 indices, queinnecIndices, fw, existingSamples,
1336 multiplier, queinnecMultiplier, rng, allocation,
1337 optim, weights, width, height);
1341 indices, queinnecIndices, fw, existingSamples,
1342 multiplier, queinnecMultiplier, rng, allocation,
1343 optim, weights, width, height);
1348 std::vector<std::vector<helper::Index> *> strataIndexVectors;
1349 std::vector<size_t> nextIndexes(numStrata, 0);
1351 std::vector<bool> completedStrata(numStrata,
false);
1352 std::vector<bool> completedStrataQueinnec(numStrata,
false);
1353 std::vector<int64_t> samplesAddedPerStrata(numStrata, 0);
1354 int64_t numCompletedStrata = 0;
1355 int64_t numCompletedStrataQueinnec = 0;
1356 int64_t curStrata = 0;
1357 int64_t addedSamples = 0;
1395 std::vector<helper::Field> strataFields(mapped ? 0 : numStrata);
1396 std::vector<std::vector<helper::Field>> mappedStrataFields(mapped ? mapStratMapping.size() : 0);
1398 strataFields.resize(numStrata);
1399 for (
int i = 0; i < numStrata; i++) {
1400 strataFields[i].fname = std::string(band.
p_band->GetDescription());
1401 strataFields[i].fval = i;
1405 for (
size_t i = 0; i < mapStratMapping.size(); i++) {
1406 mappedStrataFields[i].resize(mapStratMapping[i].second);
1408 mappedStrataFields[i][
strat].fname = mapStratMapping[i].first;
1414 int fieldVectorCount =
existing.used ? numStrata * 2 : numStrata;
1415 std::vector<std::vector<helper::Field *>> fieldVectors(fieldVectorCount);
1418 std::vector<std::vector<helper::Field *> *> fieldVectorPointersExistingTrue(
existing.used ? numStrata : 0);
1419 std::vector<std::vector<helper::Field *> *> fieldVectorPointersExistingFalse(
existing.used ? numStrata : 0);
1420 std::vector<std::vector<helper::Field *> *> fieldVectorPointersNoExisting(
existing.used ? 0 : numStrata);
1423 for (
int strata = 0; strata < numStrata; strata++) {
1425 fieldVectors[fvi].resize(2);
1426 fieldVectors[fvi + 1].resize(2);
1429 fieldVectors[fvi][0] = &fieldExistingTrue;
1430 fieldVectors[fvi + 1][0] = &fieldExistingFalse;
1431 fieldVectors[fvi][1] = strataFields.data() + strata;
1432 fieldVectors[fvi + 1][1] = strataFields.data() + strata;
1435 fieldVectorPointersExistingTrue[strata] = fieldVectors.data() + fvi;
1436 fieldVectorPointersExistingFalse[strata] = fieldVectors.data() + fvi + 1;
1442 else if (
existing.used && mapped) {
1443 for (
int i = 0; i < numStrata; i++) {
1447 fieldVectors[fvi].resize(mapStratMapping.size() + 1);
1448 fieldVectors[fvi + 1].resize(mapStratMapping.size() + 1);
1451 for (
size_t j = 0; j < mapStratMapping.size(); j++) {
1452 int bandStrata = strata % mapStratMapping[j].second;
1453 fieldVectors[fvi][j] = mappedStrataFields[j].data() + bandStrata;
1454 fieldVectors[fvi + 1][j] = mappedStrataFields[j].data() + bandStrata;
1455 strata = strata / mapStratMapping[j].second;
1457 fieldVectors[fvi][mapStratMapping.size()] = &fieldExistingTrue;
1458 fieldVectors[fvi + 1][mapStratMapping.size()] = &fieldExistingFalse;
1461 fieldVectorPointersExistingTrue[i] = fieldVectors.data() + fvi;
1462 fieldVectorPointersExistingFalse[i] = fieldVectors.data() + fvi + 1;
1468 else if (!
existing.used && !mapped) {
1469 for (
int strata = 0; strata < numStrata; strata++) {
1470 fieldVectors[fvi].resize(1);
1471 fieldVectors[fvi][0] = strataFields.data() + strata;
1472 fieldVectorPointersNoExisting[strata] = fieldVectors.data() + fvi;
1478 for (
int i = 0; i < numStrata; i++) {
1481 fieldVectors[fvi].resize(mapStratMapping.size());
1482 for (
size_t j = 0; j < mapStratMapping.size(); j++) {
1483 int bandStrata = strata % mapStratMapping[j].second;
1484 fieldVectors[fvi][j] = mappedStrataFields[j].data() + bandStrata;
1485 strata = strata / mapStratMapping[j].second;
1487 fieldVectorPointersNoExisting[i] = fieldVectors.data() + fvi;
1497 for (
int i = 0; i < numStrata; i++) {
1498 std::vector<OGRPoint> samples = existingSamples[i];
1499 for (
const OGRPoint& point : samples) {
1503 samplesAddedPerStrata[i]++;
1506 xCoords.push_back(point.getX());
1507 yCoords.push_back(point.getY());
1511 if (samplesAddedPerStrata[i] >= strataSampleCounts[i]) {
1512 numCompletedStrata++;
1513 numCompletedStrataQueinnec++;
1514 completedStrata[i] =
true;
1515 completedStrataQueinnec[i] =
true;
1520 for (
size_t i = 0; i < numStrata; i++) {
1521 std::vector<OGRPoint> samples = existingSamples[i];
1522 std::shuffle(samples.begin(), samples.end(), rng);
1525 while (samplesAddedPerStrata[i] < strataSampleCounts[i] && j < samples.size()) {
1526 OGRPoint point = samples[j];
1527 double x = point.getX();
1528 double y = point.getY();
1539 samplesAddedPerStrata[i]++;
1542 xCoords.push_back(point.getX());
1543 yCoords.push_back(point.getY());
1550 if (samplesAddedPerStrata[i] == strataSampleCounts[i]) {
1551 numCompletedStrata++;
1552 numCompletedStrataQueinnec++;
1553 completedStrata[i] =
true;
1554 completedStrataQueinnec[i] =
true;
1560 if (method ==
"Queinnec") {
1561 strataIndexVectors = queinnecIndices.
getStrataIndexVectors(samplesAddedPerStrata, strataSampleCounts, rng);
1563 int64_t curStrata = 0;
1564 while (numCompletedStrataQueinnec < numStrata && addedSamples < numSamples) {
1565 if (curStrata == numStrata) {
1568 if (completedStrataQueinnec[curStrata]) {
1573 int64_t sampleCount = strataSampleCounts[curStrata];
1574 int64_t samplesAdded = samplesAddedPerStrata[curStrata];
1575 if (samplesAdded == sampleCount) {
1576 numCompletedStrataQueinnec++;
1577 completedStrataQueinnec[curStrata] =
true;
1578 numCompletedStrata++;
1579 completedStrata[curStrata] =
true;
1584 std::vector<helper::Index> *strataIndexes = strataIndexVectors[curStrata];
1585 size_t nextIndex = nextIndexes[curStrata];
1586 if (strataIndexes->size() == nextIndex) {
1587 numCompletedStrataQueinnec++;
1588 completedStrataQueinnec[curStrata] =
true;
1594 nextIndexes[curStrata]++;
1598 OGRPoint newPoint = OGRPoint(x, y);
1606 helper::addPoint(&newPoint, p_layer, fieldVectorPointersExistingFalse[curStrata]) :
1607 helper::addPoint(&newPoint, p_layer, fieldVectorPointersNoExisting[curStrata]);
1610 samplesAddedPerStrata[curStrata]++;
1613 xCoords.push_back(x);
1614 yCoords.push_back(y);
1623 for (int64_t i = 0; i < numStrata; i++) {
1630 while (numCompletedStrata < numStrata && addedSamples < numSamples) {
1631 if (curStrata == numStrata) {
1634 if (completedStrata[curStrata]) {
1639 int64_t sampleCount = strataSampleCounts[curStrata];
1640 int64_t samplesAdded = samplesAddedPerStrata[curStrata];
1641 if (samplesAdded == sampleCount) {
1642 numCompletedStrata++;
1643 completedStrata[curStrata] =
true;
1648 std::vector<helper::Index> *strataIndexes = strataIndexVectors[curStrata];
1649 size_t nextIndex = nextIndexes[curStrata];
1650 if (strataIndexes->size() == nextIndex) {
1651 numCompletedStrata++;
1652 completedStrata[curStrata] =
true;
1658 nextIndexes[curStrata]++;
1662 OGRPoint newPoint = OGRPoint(x, y);
1670 helper::addPoint(&newPoint, p_layer, fieldVectorPointersExistingFalse[curStrata]) :
1671 helper::addPoint(&newPoint, p_layer, fieldVectorPointersNoExisting[curStrata]);
1675 samplesAddedPerStrata[curStrata]++;
1678 xCoords.push_back(x);
1679 yCoords.push_back(y);
1687 if (filename !=
"") {
1689 p_wrapper->
write(filename);
1691 catch (
const std::exception& e) {
1692 std::cout <<
"Exception thrown trying to write file: " << e.what() << std::endl;
1696 size_t actualSampleCount =
static_cast<size_t>(p_layer->GetFeatureCount());
1697 return {{xCoords, yCoords}, p_wrapper, actualSampleCount};