converting into a class, preparation for multithreading

main
Sascha Nitsch 2024-02-25 18:52:55 +01:00
parent 95c6add2c5
commit f53d989793
1 changed files with 426 additions and 381 deletions

445
main.cpp
View File

@ -18,19 +18,17 @@
#include <sys/time.h> #include <sys/time.h>
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
#include "inttypes.h"
// which basic nail placement algorithms should be used // which basic nail placement algorithms should be used
// #define grid // #define grid
// #define multicircle #define multicircle
#define circle // #define circle
/// the actual weight function to calculate how off we are to the target class Main {
/// \param value current value private:
/// \param target desired target /// last position (number of nail)
/// \retval distance to target int16_t m_lastPosition = 0;
inline int64_t weightFunction(int16_t value, int16_t target) {
return (value - target) * (value - target);
}
/// definition of a point for our dwarn line vector /// definition of a point for our dwarn line vector
struct Point { struct Point {
@ -44,9 +42,39 @@ struct Point {
/// typedef for a list of points tha make a line /// typedef for a list of points tha make a line
typedef std::vector<Point> td_pointsInLine; typedef std::vector<Point> td_pointsInLine;
/// the line from src to dst, key = (src << 16) + dst /// the line from src to dst, key = (src << 16) + dst
typedef std::unordered_map<uint32_t, td_pointsInLine> td_linesFromSource; typedef std::unordered_map<uint32_t, td_pointsInLine> td_linesFromSource;
/// our line storage
td_linesFromSource m_linesFromSource;
/// internal image width
uint16_t m_imgWidth;
/// current state of image
int16_t* m_currentState;
/// desired target state
uint8_t* m_targetState;
/// penalty duplication factor
float m_duplicateFactor;
uint16_t *m_usedpaths;
int16_t m_numberOfNails;
/// the actual weight function to calculate how off we are to the target
/// \param value current value
/// \param target desired target
/// \retval distance to target
inline int64_t weightFunction(int16_t value, int16_t target) {
return (value - target) * (value - target);
}
/// swaps two numbers /// swaps two numbers
/// \param a first number /// \param a first number
/// \param b second number /// \param b second number
@ -65,6 +93,7 @@ inline float fPartOfNumber(float x) {
} }
return x - (floor(x) + 1); return x - (floor(x) + 1);
} }
/// add given point to vector if col is > 0 /// add given point to vector if col is > 0
/// \param pil pointer to vector /// \param pil pointer to vector
/// \param x x coordinate /// \param x x coordinate
@ -134,140 +163,83 @@ td_pointsInLine drawAALine(int16_t x0 , int16_t y0 , int16_t x1 , int16_t y1, ui
return pil; return pil;
} }
/// \brief main entry point float checkLine(int16_t target) {
/// \param argc number of command line arguments /// the diff on current lastPosition -> target
/// \param argv command line arguments int64_t testDiff = 0;
int main(int argc, char* argv[]) { uint16_t src = std::min(m_lastPosition, target);
if (argc != 8) { uint16_t dst = std::max(m_lastPosition, target);
printf("usage: %s <image name> <resolution x> <resolution y> <number of nails> <max number of iterations> <penalty for duplicate path usage> <lineColor>\n", argv[0]); td_linesFromSource::const_iterator lttIter = m_linesFromSource.find((src << 16) + dst);
return 1; /*if (lttIter == m_linesFromSource.end()) {
printf("itt fail %i %i\n", src, dst);
abort();
}*/
// calculate difference to target
// for each point
td_pointsInLine::const_iterator pilIter = lttIter->second.begin();
while (pilIter != lttIter->second.end()) {
uint16_t x = (*pilIter).x;
uint16_t y = (*pilIter).y;
uint8_t sub = (*pilIter).color;
uint32_t index = y * m_imgWidth + x;
int16_t cur = m_currentState[index];
int16_t goal = m_targetState[index];
// subtract previous error
testDiff -= weightFunction(cur, goal);
cur -= sub;
// add new error
testDiff += weightFunction(cur, goal);
++pilIter;
}
float duplicatePenalty = (m_duplicateFactor != 1) ?
pow(m_duplicateFactor, m_usedpaths[std::min(m_lastPosition, target)* m_numberOfNails + std::max(m_lastPosition, target)])
: 1;
return testDiff * duplicatePenalty;
} }
// copy command line data to easier to use variables
const char* imageName = argv[1];
uint16_t resolutionX = atoi(argv[2]);
uint16_t resolutionY = atoi(argv[3]);
uint16_t numberOfNails = atoi(argv[4]);
uint16_t maxIter = atoi(argv[5]);
float duplicateFactor = atof(argv[6]);
uint8_t lineColor = atoi(argv[7]);
// our line storage
td_linesFromSource linesFromSource;
public:
/// \brief main function
/// \param resolutionX X resolution of internal image
/// \param resolutionY Y resolution of internal image
/// \param nail vector with nail positions
/// \param maxIter maximal number of iterations to run
/// \param duplicateFactor duplication penality factor
/// \param lineColor line color to use
int run(const char* imageName, Magick::Image* img, uint16_t resolutionX, uint16_t resolutionY, int16_t requestedNumberOfNails, std::vector<uint32_t> nails, uint16_t maxIter, float duplicateFactor, uint8_t lineColor) {
m_duplicateFactor = duplicateFactor;
int16_t numberOfNails = nails.size();
printf("res: %ix%i nails: %i maxIter: %i duplicatePenalty %.1f color: %i\n", resolutionX, resolutionY, numberOfNails, maxIter, duplicateFactor, lineColor); printf("res: %ix%i nails: %i maxIter: %i duplicatePenalty %.1f color: %i\n", resolutionX, resolutionY, numberOfNails, maxIter, duplicateFactor, lineColor);
/// nail positions (x << 16) + y
std::vector<uint32_t> nails;
// for time measurement // for time measurement
struct timeval tv1, tv2; struct timeval tv1, tv2;
gettimeofday(&tv1, NULL); gettimeofday(&tv1, NULL);
// initialize image magick, load image and resize to target coordinates
Magick::InitializeMagick(NULL);
Magick::Image img(imageName);
if (img.depth() != 8) {
printf("only 8 bit images supported\n");
return 1;
}
img.sample(Magick::Geometry(resolutionX, resolutionY));
// fix potential size differences between requested and delivered size
uint16_t realWidth = img.columns();
uint16_t realHeight = img.rows();
// position nails
#ifdef circle
for (uint16_t i = 0; i < numberOfNails; ++i) {
float x = sin(2.0 * M_PI * i / numberOfNails) * (realWidth-1) / 2.0 + realWidth / 2.0;
float y = cos(2.0 * M_PI * i / numberOfNails) * (realHeight-1) / 2.0 + realHeight / 2.0;
nails.push_back((static_cast<uint32_t>(floor(x)) << 16) + static_cast<uint16_t>(floor(y)));
}
#endif
#ifdef multicircle
uint16_t count = numberOfNails/1.5;
for (uint16_t i = 0; i < count; ++i) {
float x = sin(2.0 * M_PI * i / count) * (realWidth-1) / 2.0 + realWidth / 2.0;
float y = cos(2.0 * M_PI * i / count) * (realHeight-1) / 2.0 + realHeight / 2.0;
nails.push_back((static_cast<uint32_t>(floor(x)) << 16) + static_cast<uint16_t>(floor(y)));
}
uint16_t width = realWidth/1.2 -1;
uint16_t height = realHeight/1.2 -1;
count = numberOfNails/1.5;
for (uint16_t i = 0; i < count; ++i) {
float x = sin(2.0 * M_PI * i / count) * (width-1) / 2.0 + realWidth / 2.0;
float y = cos(2.0 * M_PI * i / count) * (height-1) / 2.0 + realHeight / 2.0;
nails.push_back((static_cast<uint32_t>(floor(x)) << 16) + static_cast<uint16_t>(floor(y)));
}
width = realWidth/1.5 -1;
height = realHeight/1.5 -1;
count = numberOfNails/2;
for (uint16_t i = 0; i < count; ++i) {
float x = sin(2.0 * M_PI * i / count) * (width-1) / 2.0 + realWidth / 2.0;
float y = cos(2.0 * M_PI * i / count) * (height-1) / 2.0 + realHeight / 2.0;
nails.push_back((static_cast<uint32_t>(floor(x)) << 16) + static_cast<uint16_t>(floor(y)));
}
width = realWidth/2 -1;
height = realHeight/2 -1;
count = numberOfNails/3;
for (uint16_t i = 0; i < count; ++i) {
float x = sin(2.0 * M_PI * i / count) * (width-1) / 2.0 + realWidth / 2.0;
float y = cos(2.0 * M_PI * i / count) * (height-1) / 2.0 + realHeight / 2.0;
nails.push_back((static_cast<uint32_t>(floor(x)) << 16) + static_cast<uint16_t>(floor(y)));
}
width = realWidth/3 -1;
height = realHeight/3 -1;
count = numberOfNails/4;
for (uint16_t i = 0; i < count; ++i) {
float x = sin(2.0 * M_PI * i / count) * (width-1) / 2.0 + realWidth / 2.0;
float y = cos(2.0 * M_PI * i / count) * (height-1) / 2.0 + realHeight / 2.0;
nails.push_back((static_cast<uint32_t>(floor(x)) << 16) + static_cast<uint16_t>(floor(y)));
}
width = realWidth/5 -1;
height = realHeight/5 -1;
count = numberOfNails/6;
for (uint16_t i = 0; i < count; ++i) {
float x = sin(2.0 * M_PI * i / count) * (width-1) / 2.0 + realWidth / 2.0;
float y = cos(2.0 * M_PI * i / count) * (height-1) / 2.0 + realHeight / 2.0;
nails.push_back((static_cast<uint32_t>(floor(x)) << 16) + static_cast<uint16_t>(floor(y)));
}
nails.push_back((static_cast<uint32_t>(floor(realWidth / 2.0)) << 16) + static_cast<uint16_t>(floor(realHeight / 2.0)));
#endif
#ifdef grid
uint8_t sq_pins = sqrt(numberOfNails);
float distX = static_cast<float>(realWidth - 1) / (sq_pins - 1);
float distY = static_cast<float>(realHeight - 1) / (sq_pins - 1);
for (uint16_t y = 0; y < sq_pins; ++y) {
for (uint16_t x = 0; x < sq_pins; ++x) {
nails.push_back((static_cast<uint32_t>(floor(distX * x)) << 16) + static_cast<uint16_t>(floor(distY * y)));
}
}
#endif
// number of nails might have been changed above or loaded (in the future)
numberOfNails = nails.size();
printf("num %i\n", numberOfNails);
for (uint16_t src = 0; src < numberOfNails; ++src) { for (uint16_t src = 0; src < numberOfNails; ++src) {
for (uint16_t dst = src + 1; dst < numberOfNails; ++dst) { for (uint16_t dst = src + 1; dst < numberOfNails; ++dst) {
td_pointsInLine pointsInLine = drawAALine(nails[src] >> 16, nails[src] & 0xFFFF, nails[dst] >> 16, nails[dst] & 0xFFFF, lineColor); td_pointsInLine pointsInLine = drawAALine(nails[src] >> 16, nails[src] & 0xFFFF, nails[dst] >> 16, nails[dst] & 0xFFFF, lineColor);
linesFromSource.insert(std::make_pair((src << 16) + dst, pointsInLine)); m_linesFromSource.insert(std::make_pair((src << 16) + dst, pointsInLine));
} }
} }
uint32_t channels = img.channels(); uint32_t channels = img->channels();
printf("target image %i x %i x %i\n", realWidth, realHeight, channels); m_imgWidth = img->columns();
MagickCore::Quantum *pixels = img.getPixels(0, 0, realWidth, realHeight); uint16_t imgHeight = img->rows();
uint8_t* targetState = reinterpret_cast<uint8_t*>(malloc(realWidth * realHeight));
printf("target image %i x %i x %i\n", m_imgWidth, imgHeight, channels);
MagickCore::Quantum *pixels = img->getPixels(0, 0, m_imgWidth, imgHeight);
m_targetState = reinterpret_cast<uint8_t*>(malloc(m_imgWidth * imgHeight));
if (channels == 1) { // monochrome image if (channels == 1) { // monochrome image
for (uint32_t i = 0; i < realWidth * realHeight; ++i) { for (uint32_t i = 0; i < m_imgWidth * imgHeight; ++i) {
targetState[i] = pixels[i] >> 8; m_targetState[i] = pixels[i] >> 8;
} }
} else if (channels == 2) { // color + alpha? } else if (channels == 2) { // color + alpha?
for (uint32_t i = 0; i < realWidth * realHeight; ++i) { for (uint32_t i = 0; i < m_imgWidth * imgHeight; ++i) {
targetState[i] = pixels[i << 1] >> 8; m_targetState[i] = pixels[i << 1] >> 8;
} }
} else { // RGB or RGBA } else { // RGB or RGBA
for (uint32_t i = 0; i < realWidth * realHeight; ++i) { for (uint32_t i = 0; i < m_imgWidth * imgHeight; ++i) {
targetState[i] = ((pixels[i*channels] + pixels[i*channels + 1] + pixels[i*channels + 2]) / 3) >> 8; m_targetState[i] = ((pixels[i*channels] + pixels[i*channels + 1] + pixels[i*channels + 2]) / 3) >> 8;
} }
} }
#ifdef DEBUGIMG #ifdef DEBUGIMG
@ -281,21 +253,22 @@ int main(int argc, char* argv[]) {
std::vector<uint16_t> path; std::vector<uint16_t> path;
// add start position // add start position
path.push_back(0); path.push_back(0);
m_numberOfNails = numberOfNails;
// a lookup of used paths to count repeats // a lookup of used paths to count repeats
uint16_t usedpaths[numberOfNails][numberOfNails]; m_usedpaths = reinterpret_cast<uint16_t*>(malloc(numberOfNails * numberOfNails * sizeof(uint16_t)));
bzero(usedpaths, numberOfNails * numberOfNails * 2); bzero(m_usedpaths, numberOfNails * numberOfNails * sizeof(uint16_t));
/// last thread end position /// last thread end position
int16_t lastPosition = 0; m_lastPosition = 0;
/// storage for the current state (all previous drawn threads) /// storage for the current state (all previous drawn threads)
int16_t* currentState = reinterpret_cast<int16_t*>(malloc(realWidth * realHeight * 2)); m_currentState = reinterpret_cast<int16_t*>(malloc(m_imgWidth * imgHeight * 2));
/// temp storage to save (current) best version, will be continously updated /// temp storage to save (current) best version, will be continously updated
int16_t* bestState = reinterpret_cast<int16_t*>(malloc(realWidth * realHeight * 2)); int16_t* bestState = reinterpret_cast<int16_t*>(malloc(m_imgWidth * imgHeight * 2));
// clear states // clear states
uint32_t widthXheight = realWidth * realHeight; uint32_t widthXheight = m_imgWidth * imgHeight;
for (uint32_t i = 0; i < widthXheight; ++i) { for (uint32_t i = 0; i < widthXheight; ++i) {
currentState[i] = 255; m_currentState[i] = 255;
bestState[i] = 255; bestState[i] = 255;
} }
// current iteration // current iteration
@ -309,7 +282,7 @@ int main(int argc, char* argv[]) {
// calculate inital difference // calculate inital difference
for (uint32_t i = 0; i < widthXheight; ++i) { for (uint32_t i = 0; i < widthXheight; ++i) {
totalDiff += weightFunction(255, targetState[i]); totalDiff += weightFunction(255, m_targetState[i]);
} }
printf("start %li\n", totalDiff); printf("start %li\n", totalDiff);
while ((iter < maxIter) && jumps*2 < numberOfNails) { while ((iter < maxIter) && jumps*2 < numberOfNails) {
@ -326,90 +299,52 @@ int main(int argc, char* argv[]) {
} }
#endif #endif
/// current best difference /// current best difference
int64_t realBestDiff = INT64_MAX; int64_t bestDiff = INT64_MAX;
/// compensated diff includes penality when reusing paths /// compensated diff includes penality when reusing paths
int64_t compensatedBestDiff = INT64_MAX; int64_t compensatedBestDiff = INT64_MAX;
int16_t bestTarget = -1; int16_t bestTarget = -1;
// printf("source %i\n", lastPosition); fflush(stdout); // printf("source %i\n", m_lastPosition); fflush(stdout);
for (int16_t target = 0; target < numberOfNails; ++target) { for (int16_t target = 0; target < numberOfNails; ++target) {
if (target == lastPosition) continue; if (target == m_lastPosition) continue;
/// the diff on current lastPosition -> target int64_t diff = checkLine(target);
int64_t testDiff = 0; if (diff < bestDiff) {
uint16_t src = std::min(lastPosition, target); bestTarget = target;
uint16_t dst = std::max(lastPosition, target); bestDiff = diff;
td_linesFromSource::const_iterator lttIter = linesFromSource.find((src << 16) + dst);
// calculate difference to target
// for each point
td_pointsInLine::const_iterator pilIter = lttIter->second.begin();
while (pilIter != lttIter->second.end()) {
uint16_t x = (*pilIter).x;
uint16_t y = (*pilIter).y;
uint8_t sub = (*pilIter).color;
uint32_t index = y * realWidth + x;
int16_t cur = currentState[index];
int16_t goal = targetState[index];
// subtract previous error
testDiff -= weightFunction(cur, goal);
cur -= sub;
// add new error
testDiff += weightFunction(cur, goal);
++pilIter;
}
float duplicatePenalty = (duplicateFactor != 1) ?
pow(duplicateFactor, usedpaths[std::min(lastPosition, target)][std::max(lastPosition, target)])
: 1;
if ((testDiff / duplicatePenalty) < compensatedBestDiff) {
// printf(" new best %i - %i(%i,%i) %li d %li\n", lastPosition, target, pos[target]>>16, pos[target]&0xffff, testDiff, totalDiff - testDiff);
compensatedBestDiff = testDiff * duplicatePenalty;
realBestDiff = testDiff;
// a new best
if (bestTarget != -1) {
// printf("undo %i:%i\n", lastPosition, bestTarget);
// undo previous best
uint16_t tmpSrc = std::min(lastPosition, bestTarget);
uint16_t tmpDst = std::max(lastPosition, bestTarget);
td_linesFromSource::const_iterator tmpLfsIter = linesFromSource.find((tmpSrc << 16) + tmpDst);
td_pointsInLine::const_iterator pilIter = tmpLfsIter->second.begin();
while (pilIter != tmpLfsIter->second.end()) {
uint16_t x = (*pilIter).x;
uint16_t y = (*pilIter).y;
uint32_t index = y * realWidth + x;
int16_t cur = currentState[index];
bestState[index] = cur;
++pilIter;
} }
} }
// printf("bestTarget %i diff %li\n", bestTarget, bestDiff);
if (bestDiff < 0) {
// apply current best // apply current best
td_linesFromSource::const_iterator lttIter = m_linesFromSource.find((std::min(m_lastPosition, bestTarget) << 16) + std::max(m_lastPosition, bestTarget));
/*if (lttIter == m_linesFromSource.end()) {
printf("iter fail %i %i\n", m_lastPosition, bestTarget);
abort();
}*/
td_pointsInLine::const_iterator pilIter = lttIter->second.begin(); td_pointsInLine::const_iterator pilIter = lttIter->second.begin();
while (pilIter != lttIter->second.end()) { while (pilIter != lttIter->second.end()) {
uint16_t x = (*pilIter).x; uint16_t x = (*pilIter).x;
uint16_t y = (*pilIter).y; uint16_t y = (*pilIter).y;
int16_t sub = (*pilIter).color; int16_t sub = (*pilIter).color;
uint32_t index = y * realWidth + x; uint32_t index = y * m_imgWidth + x;
int16_t cur = currentState[index]; int16_t cur = m_currentState[index];
cur -= sub; cur -= sub;
bestState[index] = cur; bestState[index] = cur;
++pilIter; ++pilIter;
} }
bestTarget = target; } else {
}
}
if (realBestDiff >= 0) {
// we got worse, jump to random place to continue // we got worse, jump to random place to continue
// printf("j %3i %3i -> %3i(%4i, %4i) bestDiff %8li (%li) iter %i path %i\n", jumps, lastPosition, bestTarget, pos[bestTarget] >> 16, pos[bestTarget] & 0xFFFF, realBestDiff, totalDiff - realBestDiff, iter, usedpaths[std::min(lastPosition, bestTarget)][std::max(lastPosition, bestTarget)]); // printf("j %3i %3i -> %3i(%4i, %4i) bestDiff %8li (%li) iter %i path %i\n", jumps, lastPosition, bestTarget, pos[bestTarget] >> 16, pos[bestTarget] & 0xFFFF, realBestDiff, totalDiff - realBestDiff, iter, m_usedpaths[std::min(m_lastPosition, bestTarget)* m_numberOfNails + std::max(m_lastPosition, bestTarget)]]);
if (jumps) { // undo last jump, was not working anyway if (jumps) { // undo last jump, was not working anyway
--usedPins[lastPosition]; --usedPins[m_lastPosition];
path.pop_back(); path.pop_back();
} }
// select next target randomly (kind of, intentially producing the same numbers) // select next target randomly (kind of, intentially producing the same numbers)
bestTarget = random() % numberOfNails; bestTarget = random() % numberOfNails;
path.push_back(bestTarget); path.push_back(bestTarget);
lastPosition = bestTarget; m_lastPosition = bestTarget;
++usedPins[bestTarget]; ++usedPins[bestTarget];
++jumps; ++jumps;
--iter; --iter;
// fix bestState, easier to copy over than manually reversing. should only happen a few times anyway
memcpy(bestState, currentState, widthXheight * 2);
continue; continue;
} }
/// reset jump counter (faster to always set) /// reset jump counter (faster to always set)
@ -419,27 +354,26 @@ int main(int argc, char* argv[]) {
break; break;
} }
// update path map // update path map
++usedpaths[std::min(lastPosition, bestTarget)][std::max(lastPosition, bestTarget)]; ++m_usedpaths[std::min(m_lastPosition, bestTarget)* m_numberOfNails + std::max(m_lastPosition, bestTarget)];
// add new stop // add new stop
path.push_back(bestTarget); path.push_back(bestTarget);
// update used pins // update used pins
++usedPins[bestTarget]; ++usedPins[bestTarget];
// progress report // progress report
if (iter % 100 == 0) { if (iter % 100 == 0) {
printf("best %4i -> %4i(%4i, %4i) diff %9li (%12li) iter %5i path %i\n", lastPosition, bestTarget, nails[bestTarget] >> 16, nails[bestTarget] & 0xFFFF, compensatedBestDiff, totalDiff + realBestDiff, iter, usedpaths[std::min(lastPosition, bestTarget)][std::max(lastPosition, bestTarget)]); printf("best %4i -> %4i(%4i, %4i) diff %9li (%12li) iter %5i path %i\n", m_lastPosition, bestTarget, nails[bestTarget] >> 16, nails[bestTarget] & 0xFFFF, compensatedBestDiff, totalDiff + bestDiff, iter, m_usedpaths[std::min(m_lastPosition, bestTarget) * m_numberOfNails + std::max(m_lastPosition, bestTarget)]);
} }
// set new start position // set new start position
lastPosition = bestTarget; m_lastPosition = bestTarget;
// update diff // update diff
totalDiff += realBestDiff; totalDiff += bestDiff;
// update current state from best map // update current state from best map
memcpy(currentState, bestState, widthXheight * 2); memcpy(m_currentState, bestState, widthXheight * 2);
} }
printf("size %li\n", path.size()); printf("size %li\n", path.size());
// we are done, create output svg // we are done, create output svg
FILE* fh = fopen("map.svg", "wb"); FILE* fh = fopen("map.svg", "wb");
fprintf(fh, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 %i %i\">\n<rect width=\"%i\" height=\"%i\" fill=\"#ffffff\" />\n<g style=\"fill:none;stroke:#000000;stroke-opacity:%.2f;stroke-width:1\">\n", realWidth, realHeight, realWidth, realHeight, lineColor / 255.0); fprintf(fh, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 %i %i\">\n<rect width=\"%i\" height=\"%i\" fill=\"#ffffff\" />\n<g style=\"fill:none;stroke:#000000;stroke-opacity:%.2f;stroke-width:1\">\n", m_imgWidth, imgHeight, m_imgWidth, imgHeight, lineColor / 255.0);
uint32_t counter = 0; uint32_t counter = 0;
for (uint16_t i : path) { for (uint16_t i : path) {
if ((counter & 255) == 0) { if ((counter & 255) == 0) {
@ -458,14 +392,125 @@ int main(int argc, char* argv[]) {
gettimeofday(&tv2, NULL); gettimeofday(&tv2, NULL);
float timeNeeded = (tv2.tv_sec - tv1.tv_sec) + (tv2.tv_usec - tv1.tv_usec) / 1000000.0; float timeNeeded = (tv2.tv_sec - tv1.tv_sec) + (tv2.tv_usec - tv1.tv_usec) / 1000000.0;
fprintf(fh, "</g>\n"); fprintf(fh, "</g>\n");
fprintf(fh, "<text x=\"30\" y=\"10\" style=\"font-weight:bold;font-size:60px;font-family:'DejaVu Serif'\"><tspan x=\"30\" y=\"70\">%s %s %i %i</tspan><tspan x=\"70\" y=\"150\"> %i %i %.2f %i</tspan><tspan x=\"30\" y=\"%i\">%i nails, %li paths, %.1f sec</tspan></text>", argv[0], imageName, resolutionX, resolutionY, atoi(argv[4]), maxIter, duplicateFactor, lineColor, realHeight - 30, numberOfNails, path.size(), timeNeeded); fprintf(fh, "<text x=\"30\" y=\"10\" style=\"font-weight:bold;font-size:60px;font-family:'DejaVu Serif'\"><tspan x=\"30\" y=\"70\">%s %i %i</tspan><tspan x=\"70\" y=\"150\"> %i %i %.2f %i</tspan><tspan x=\"30\" y=\"%i\">%i nails, %li paths, %.1f sec</tspan></text>", imageName, resolutionX, resolutionY, requestedNumberOfNails, maxIter, duplicateFactor, lineColor, imgHeight - 30, numberOfNails, path.size(), timeNeeded);
fprintf(fh, "</svg>"); fprintf(fh, "</svg>");
fclose(fh); fclose(fh);
// cleanup // cleanup
free(targetState); free(m_targetState);
free(bestState); free(bestState);
free(currentState); free(m_currentState);
free(m_usedpaths);
path.clear(); path.clear();
linesFromSource.clear(); m_linesFromSource.clear();
Magick::TerminateMagick(); return 0;
}
};
/// \brief main entry point
/// \param argc number of command line arguments
/// \param argv command line arguments
int main(int argc, char* argv[]) {
if (argc != 8) {
printf("usage: %s <image name> <resolution x> <resolution y> <number of nails> <max number of iterations> <penalty for duplicate path usage> <lineColor>\n", argv[0]);
return 1;
}
// copy command line data to easier to use variables
const char* imageName = argv[1];
uint16_t resolutionX = atoi(argv[2]);
uint16_t resolutionY = atoi(argv[3]);
uint16_t numberOfNails = atoi(argv[4]);
uint16_t maxIter = atoi(argv[5]);
float duplicateFactor = atof(argv[6]);
uint8_t lineColor = atoi(argv[7]);
/// nail positions (x << 16) + y
std::vector<uint32_t> nails;
// initialize image magick, load image and resize to target coordinates
Magick::InitializeMagick(NULL);
Magick::Image img(imageName);
if (img.depth() != 8) {
printf("only 8 bit images supported\n");
return 1;
}
img.sample(Magick::Geometry(resolutionX, resolutionY));
// fix potential size differences between requested and delivered size
uint16_t imgWidth = img.columns();
uint16_t imgHeight = img.rows();
// position nails
#ifdef circle
for (uint16_t i = 0; i < numberOfNails; ++i) {
float x = sin(2.0 * M_PI * i / numberOfNails) * (imgWidth-1) / 2.0 + imgWidth / 2.0;
float y = cos(2.0 * M_PI * i / numberOfNails) * (imgHeight-1) / 2.0 + imgHeight / 2.0;
nails.push_back((static_cast<uint32_t>(floor(x)) << 16) + static_cast<uint16_t>(floor(y)));
}
#endif
#ifdef multicircle
uint16_t count = numberOfNails/1.5;
for (uint16_t i = 0; i < count; ++i) {
float x = sin(2.0 * M_PI * i / count) * (imgWidth-1) / 2.0 + imgWidth / 2.0;
float y = cos(2.0 * M_PI * i / count) * (imgHeight-1) / 2.0 + imgHeight / 2.0;
nails.push_back((static_cast<uint32_t>(floor(x)) << 16) + static_cast<uint16_t>(floor(y)));
}
uint16_t width = imgWidth / 1.2 - 1;
uint16_t height = imgHeight / 1.2 - 1;
count = numberOfNails/1.5;
for (uint16_t i = 0; i < count; ++i) {
float x = sin(2.0 * M_PI * i / count) * (width-1) / 2.0 + imgWidth / 2.0;
float y = cos(2.0 * M_PI * i / count) * (height-1) / 2.0 + imgHeight / 2.0;
nails.push_back((static_cast<uint32_t>(floor(x)) << 16) + static_cast<uint16_t>(floor(y)));
}
width = imgWidth / 1.5 - 1;
height = imgHeight / 1.5 - 1;
count = numberOfNails/2;
for (uint16_t i = 0; i < count; ++i) {
float x = sin(2.0 * M_PI * i / count) * (width-1) / 2.0 + imgWidth / 2.0;
float y = cos(2.0 * M_PI * i / count) * (height-1) / 2.0 + imgHeight / 2.0;
nails.push_back((static_cast<uint32_t>(floor(x)) << 16) + static_cast<uint16_t>(floor(y)));
}
width = imgWidth / 2 - 1;
height = imgHeight / 2 - 1;
count = numberOfNails/3;
for (uint16_t i = 0; i < count; ++i) {
float x = sin(2.0 * M_PI * i / count) * (width-1) / 2.0 + imgWidth / 2.0;
float y = cos(2.0 * M_PI * i / count) * (height-1) / 2.0 + imgHeight / 2.0;
nails.push_back((static_cast<uint32_t>(floor(x)) << 16) + static_cast<uint16_t>(floor(y)));
}
width = imgWidth / 3 - 1;
height = imgHeight / 3 - 1;
count = numberOfNails/4;
for (uint16_t i = 0; i < count; ++i) {
float x = sin(2.0 * M_PI * i / count) * (width-1) / 2.0 + imgWidth / 2.0;
float y = cos(2.0 * M_PI * i / count) * (height-1) / 2.0 + imgHeight / 2.0;
nails.push_back((static_cast<uint32_t>(floor(x)) << 16) + static_cast<uint16_t>(floor(y)));
}
width = imgWidth / 5 - 1;
height = imgHeight / 5 - 1;
count = numberOfNails / 6;
for (uint16_t i = 0; i < count; ++i) {
float x = sin(2.0 * M_PI * i / count) * (width-1) / 2.0 + imgWidth / 2.0;
float y = cos(2.0 * M_PI * i / count) * (height-1) / 2.0 + imgHeight / 2.0;
nails.push_back((static_cast<uint32_t>(floor(x)) << 16) + static_cast<uint16_t>(floor(y)));
}
nails.push_back((static_cast<uint32_t>(floor(imgWidth / 2.0)) << 16) + static_cast<uint16_t>(floor(imgHeight / 2.0)));
#endif
#ifdef grid
uint8_t sq_pins = sqrt(numberOfNails);
float distX = static_cast<float>(imgWidth - 1) / (sq_pins - 1);
float distY = static_cast<float>(imgHeight - 1) / (sq_pins - 1);
for (uint16_t y = 0; y < sq_pins; ++y) {
for (uint16_t x = 0; x < sq_pins; ++x) {
nails.push_back((static_cast<uint32_t>(floor(distX * x)) << 16) + static_cast<uint16_t>(floor(distY * y)));
}
}
#endif
Main m;
m.run(imageName, &img, resolutionX, resolutionY, numberOfNails, nails, maxIter, duplicateFactor, lineColor);
Magick::TerminateMagick();
} }