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::string filename,
1181 std::string tempFolder)
1185 double mindist_sq = mindist * mindist;
1186 bool useMindist = mindist != 0;
1190 bool mapped = mapStratMapping.size() != 0;
1192 std::mutex bandMutex;
1193 std::mutex rngMutex;
1194 std::mutex accessMutex;
1203 band.
nan = band.
p_band->GetNoDataValue();
1210 GDALDriver *p_driver = GetGDALDriverManager()->GetDriverByName(
"MEM");
1212 throw std::runtime_error(
"unable to create output sample dataset driver.");
1214 GDALDataset *p_samples = p_driver->Create(
"", 0, 0, 0, GDT_Unknown,
nullptr);
1216 throw std::runtime_error(
"unable to create output dataset with driver.");
1220 OGRLayer *p_layer = p_samples->CreateLayer(
"samples", p_wrapper->
getSRS(), wkbPoint,
nullptr);
1222 throw std::runtime_error(
"unable to create output dataset layer.");
1226 OGRFieldDefn strataField(band.
p_band->GetDescription(), OFTInteger);
1227 OGRErr err = p_layer->CreateField(&strataField);
1229 throw std::runtime_error(
"cannot create field for strata name.");
1233 for (
size_t i = 0; i < mapStratMapping.size(); i++) {
1234 OGRFieldDefn strataField(mapStratMapping[i].first.c_str(), OFTInteger);
1235 OGRErr err = p_layer->CreateField(&strataField);
1237 throw std::runtime_error(
"cannot create create field for strata name.");
1254 std::vector<double> xCoords, yCoords;
1255 std::vector<std::vector<OGRPoint>> existingSamples(numStrata);
1270 xso::xoshiro_4x64_plus rng;
1300 std::vector<int64_t> strataSampleCounts;
1301 if (method ==
"random") {
1302 switch (band.
type) {
1305 existing, indices, existingSamples,
1306 multiplier, rng, allocation, optim,
1307 weights, width, height);
1311 existing, indices, existingSamples,
1312 multiplier, rng, allocation, optim,
1313 weights, width, height);
1317 existing, indices, existingSamples,
1318 multiplier, rng, allocation, optim,
1319 weights, width, height);
1324 switch (band.
type) {
1327 indices, queinnecIndices, fw, existingSamples,
1328 multiplier, queinnecMultiplier, rng, allocation,
1329 optim, weights, width, height);
1333 indices, queinnecIndices, fw, existingSamples,
1334 multiplier, queinnecMultiplier, rng, allocation,
1335 optim, weights, width, height);
1339 indices, queinnecIndices, fw, existingSamples,
1340 multiplier, queinnecMultiplier, rng, allocation,
1341 optim, weights, width, height);
1346 std::vector<std::vector<helper::Index> *> strataIndexVectors;
1347 std::vector<size_t> nextIndexes(numStrata, 0);
1349 std::vector<bool> completedStrata(numStrata,
false);
1350 std::vector<bool> completedStrataQueinnec(numStrata,
false);
1351 std::vector<int64_t> samplesAddedPerStrata(numStrata, 0);
1352 int64_t numCompletedStrata = 0;
1353 int64_t numCompletedStrataQueinnec = 0;
1354 int64_t curStrata = 0;
1355 int64_t addedSamples = 0;
1393 std::vector<helper::Field> strataFields(mapped ? 0 : numStrata);
1394 std::vector<std::vector<helper::Field>> mappedStrataFields(mapped ? mapStratMapping.size() : 0);
1396 strataFields.resize(numStrata);
1397 for (
int i = 0; i < numStrata; i++) {
1398 strataFields[i].fname = std::string(band.
p_band->GetDescription());
1399 strataFields[i].fval = i;
1403 for (
size_t i = 0; i < mapStratMapping.size(); i++) {
1404 mappedStrataFields[i].resize(mapStratMapping[i].second);
1406 mappedStrataFields[i][
strat].fname = mapStratMapping[i].first;
1412 int fieldVectorCount =
existing.used ? numStrata * 2 : numStrata;
1413 std::vector<std::vector<helper::Field *>> fieldVectors(fieldVectorCount);
1416 std::vector<std::vector<helper::Field *> *> fieldVectorPointersExistingTrue(
existing.used ? numStrata : 0);
1417 std::vector<std::vector<helper::Field *> *> fieldVectorPointersExistingFalse(
existing.used ? numStrata : 0);
1418 std::vector<std::vector<helper::Field *> *> fieldVectorPointersNoExisting(
existing.used ? 0 : numStrata);
1421 for (
int strata = 0; strata < numStrata; strata++) {
1423 fieldVectors[fvi].resize(2);
1424 fieldVectors[fvi + 1].resize(2);
1427 fieldVectors[fvi][0] = &fieldExistingTrue;
1428 fieldVectors[fvi + 1][0] = &fieldExistingFalse;
1429 fieldVectors[fvi][1] = strataFields.data() + strata;
1430 fieldVectors[fvi + 1][1] = strataFields.data() + strata;
1433 fieldVectorPointersExistingTrue[strata] = fieldVectors.data() + fvi;
1434 fieldVectorPointersExistingFalse[strata] = fieldVectors.data() + fvi + 1;
1440 else if (
existing.used && mapped) {
1441 for (
int i = 0; i < numStrata; i++) {
1445 fieldVectors[fvi].resize(mapStratMapping.size() + 1);
1446 fieldVectors[fvi + 1].resize(mapStratMapping.size() + 1);
1449 for (
size_t j = 0; j < mapStratMapping.size(); j++) {
1450 int bandStrata = strata % mapStratMapping[j].second;
1451 fieldVectors[fvi][j] = mappedStrataFields[j].data() + bandStrata;
1452 fieldVectors[fvi + 1][j] = mappedStrataFields[j].data() + bandStrata;
1453 strata = strata / mapStratMapping[j].second;
1455 fieldVectors[fvi][mapStratMapping.size()] = &fieldExistingTrue;
1456 fieldVectors[fvi + 1][mapStratMapping.size()] = &fieldExistingFalse;
1459 fieldVectorPointersExistingTrue[i] = fieldVectors.data() + fvi;
1460 fieldVectorPointersExistingFalse[i] = fieldVectors.data() + fvi + 1;
1466 else if (!
existing.used && !mapped) {
1467 for (
int strata = 0; strata < numStrata; strata++) {
1468 fieldVectors[fvi].resize(1);
1469 fieldVectors[fvi][0] = strataFields.data() + strata;
1470 fieldVectorPointersNoExisting[strata] = fieldVectors.data() + fvi;
1476 for (
int i = 0; i < numStrata; i++) {
1479 fieldVectors[fvi].resize(mapStratMapping.size());
1480 for (
size_t j = 0; j < mapStratMapping.size(); j++) {
1481 int bandStrata = strata % mapStratMapping[j].second;
1482 fieldVectors[fvi][j] = mappedStrataFields[j].data() + bandStrata;
1483 strata = strata / mapStratMapping[j].second;
1485 fieldVectorPointersNoExisting[i] = fieldVectors.data() + fvi;
1495 for (
int i = 0; i < numStrata; i++) {
1496 std::vector<OGRPoint> samples = existingSamples[i];
1497 for (
const OGRPoint& point : samples) {
1501 samplesAddedPerStrata[i]++;
1504 xCoords.push_back(point.getX());
1505 yCoords.push_back(point.getY());
1509 if (samplesAddedPerStrata[i] >= strataSampleCounts[i]) {
1510 numCompletedStrata++;
1511 numCompletedStrataQueinnec++;
1512 completedStrata[i] =
true;
1513 completedStrataQueinnec[i] =
true;
1518 for (
size_t i = 0; i < numStrata; i++) {
1519 std::vector<OGRPoint> samples = existingSamples[i];
1520 std::shuffle(samples.begin(), samples.end(), rng);
1523 while (samplesAddedPerStrata[i] < strataSampleCounts[i] && j < samples.size()) {
1524 OGRPoint point = samples[j];
1525 double x = point.getX();
1526 double y = point.getY();
1537 samplesAddedPerStrata[i]++;
1540 xCoords.push_back(point.getX());
1541 yCoords.push_back(point.getY());
1548 if (samplesAddedPerStrata[i] == strataSampleCounts[i]) {
1549 numCompletedStrata++;
1550 numCompletedStrataQueinnec++;
1551 completedStrata[i] =
true;
1552 completedStrataQueinnec[i] =
true;
1558 if (method ==
"Queinnec") {
1559 strataIndexVectors = queinnecIndices.
getStrataIndexVectors(samplesAddedPerStrata, strataSampleCounts, rng);
1561 int64_t curStrata = 0;
1562 while (numCompletedStrataQueinnec < numStrata && addedSamples < numSamples) {
1563 if (curStrata == numStrata) {
1566 if (completedStrataQueinnec[curStrata]) {
1571 int64_t sampleCount = strataSampleCounts[curStrata];
1572 int64_t samplesAdded = samplesAddedPerStrata[curStrata];
1573 if (samplesAdded == sampleCount) {
1574 numCompletedStrataQueinnec++;
1575 completedStrataQueinnec[curStrata] =
true;
1576 numCompletedStrata++;
1577 completedStrata[curStrata] =
true;
1582 std::vector<helper::Index> *strataIndexes = strataIndexVectors[curStrata];
1583 size_t nextIndex = nextIndexes[curStrata];
1584 if (strataIndexes->size() == nextIndex) {
1585 numCompletedStrataQueinnec++;
1586 completedStrataQueinnec[curStrata] =
true;
1592 nextIndexes[curStrata]++;
1596 OGRPoint newPoint = OGRPoint(x, y);
1604 helper::addPoint(&newPoint, p_layer, fieldVectorPointersExistingFalse[curStrata]) :
1605 helper::addPoint(&newPoint, p_layer, fieldVectorPointersNoExisting[curStrata]);
1608 samplesAddedPerStrata[curStrata]++;
1611 xCoords.push_back(x);
1612 yCoords.push_back(y);
1621 for (int64_t i = 0; i < numStrata; i++) {
1628 while (numCompletedStrata < numStrata && addedSamples < numSamples) {
1629 if (curStrata == numStrata) {
1632 if (completedStrata[curStrata]) {
1637 int64_t sampleCount = strataSampleCounts[curStrata];
1638 int64_t samplesAdded = samplesAddedPerStrata[curStrata];
1639 if (samplesAdded == sampleCount) {
1640 numCompletedStrata++;
1641 completedStrata[curStrata] =
true;
1646 std::vector<helper::Index> *strataIndexes = strataIndexVectors[curStrata];
1647 size_t nextIndex = nextIndexes[curStrata];
1648 if (strataIndexes->size() == nextIndex) {
1649 numCompletedStrata++;
1650 completedStrata[curStrata] =
true;
1656 nextIndexes[curStrata]++;
1660 OGRPoint newPoint = OGRPoint(x, y);
1668 helper::addPoint(&newPoint, p_layer, fieldVectorPointersExistingFalse[curStrata]) :
1669 helper::addPoint(&newPoint, p_layer, fieldVectorPointersNoExisting[curStrata]);
1673 samplesAddedPerStrata[curStrata]++;
1676 xCoords.push_back(x);
1677 yCoords.push_back(y);
1685 if (filename !=
"") {
1687 p_wrapper->
write(filename);
1689 catch (
const std::exception& e) {
1690 std::cout <<
"Exception thrown trying to write file: " << e.what() << std::endl;
1694 size_t actualSampleCount =
static_cast<size_t>(p_layer->GetFeatureCount());
1695 return {{xCoords, yCoords}, p_wrapper, actualSampleCount};