Edge coloring update, circles no longer white

This commit is contained in:
Chlumsky 2024-03-09 22:17:49 +01:00
parent 682381a03c
commit 35f92541c4
6 changed files with 84 additions and 47 deletions

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2016 - 2023 Viktor Chlumsky
Copyright (c) 2016 - 2024 Viktor Chlumsky
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -16,6 +16,13 @@ static void initDistance(MultiDistance &distance) {
distance.b = -DBL_MAX;
}
static void initDistance(MultiAndTrueDistance &distance) {
distance.r = -DBL_MAX;
distance.g = -DBL_MAX;
distance.b = -DBL_MAX;
distance.a = -DBL_MAX;
}
static double resolveDistance(double distance) {
return distance;
}

View File

@ -11,6 +11,15 @@
namespace msdfgen {
/**
* For each position < n, this function will return -1, 0, or 1,
* depending on whether the position is closer to the beginning, middle, or end, respectively.
* It is guaranteed that the output will be balanced in that the total for positions 0 through n-1 will be zero.
*/
static int symmetricalTrichotomy(int position, int n) {
return int(3+2.875*position/(n-1)-1.4375+.5)-3;
}
static bool isCorner(const Vector2 &aDir, const Vector2 &bDir, double crossThreshold) {
return dotProduct(aDir, bDir) <= 0 || fabs(crossProduct(aDir, bDir)) > crossThreshold;
}
@ -26,30 +35,45 @@ static double estimateEdgeLength(const EdgeSegment *edge) {
return len;
}
static void switchColor(EdgeColor &color, unsigned long long &seed, EdgeColor banned = BLACK) {
EdgeColor combined = EdgeColor(color&banned);
if (combined == RED || combined == GREEN || combined == BLUE) {
color = EdgeColor(combined^WHITE);
return;
}
if (color == BLACK || color == WHITE) {
static const EdgeColor start[3] = { CYAN, MAGENTA, YELLOW };
color = start[seed%3];
seed /= 3;
return;
}
int shifted = color<<(1+(seed&1));
color = EdgeColor((shifted|shifted>>3)&WHITE);
static int seedExtract2(unsigned long long &seed) {
int v = int(seed)&1;
seed >>= 1;
return v;
}
static int seedExtract3(unsigned long long &seed) {
int v = int(seed%3);
seed /= 3;
return v;
}
static EdgeColor initColor(unsigned long long &seed) {
static const EdgeColor colors[3] = { CYAN, MAGENTA, YELLOW };
return colors[seedExtract3(seed)];
}
static void switchColor(EdgeColor &color, unsigned long long &seed) {
int shifted = color<<(1+seedExtract2(seed));
color = EdgeColor((shifted|shifted>>3)&WHITE);
}
static void switchColor(EdgeColor &color, unsigned long long &seed, EdgeColor banned) {
EdgeColor combined = EdgeColor(color&banned);
if (combined == RED || combined == GREEN || combined == BLUE)
color = EdgeColor(combined^WHITE);
else
switchColor(color, seed);
}
void edgeColoringSimple(Shape &shape, double angleThreshold, unsigned long long seed) {
double crossThreshold = sin(angleThreshold);
EdgeColor color = initColor(seed);
std::vector<int> corners;
for (std::vector<Contour>::iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) {
// Identify corners
if (contour->edges.empty())
continue;
{ // Identify corners
corners.clear();
if (!contour->edges.empty()) {
Vector2 prevDirection = contour->edges.back()->direction(1);
int index = 0;
for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge, ++index) {
@ -60,19 +84,24 @@ void edgeColoringSimple(Shape &shape, double angleThreshold, unsigned long long
}
// Smooth contour
if (corners.empty())
if (corners.empty()) {
switchColor(color, seed);
for (std::vector<EdgeHolder>::iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge)
(*edge)->color = WHITE;
(*edge)->color = color;
}
// "Teardrop" case
else if (corners.size() == 1) {
EdgeColor colors[3] = { WHITE, WHITE };
switchColor(colors[0], seed);
switchColor(colors[2] = colors[0], seed);
EdgeColor colors[3];
switchColor(color, seed);
colors[0] = color;
colors[1] = WHITE;
switchColor(color, seed);
colors[2] = color;
int corner = corners[0];
if (contour->edges.size() >= 3) {
int m = (int) contour->edges.size();
for (int i = 0; i < m; ++i)
contour->edges[(corner+i)%m]->color = (colors+1)[int(3+2.875*i/(m-1)-1.4375+.5)-3];
contour->edges[(corner+i)%m]->color = colors[1+symmetricalTrichotomy(i, m)];
} else if (contour->edges.size() >= 1) {
// Less than three edge segments for three colors => edges must be split
EdgeSegment *parts[7] = { };
@ -98,7 +127,6 @@ void edgeColoringSimple(Shape &shape, double angleThreshold, unsigned long long
int spline = 0;
int start = corners[0];
int m = (int) contour->edges.size();
EdgeColor color = WHITE;
switchColor(color, seed);
EdgeColor initialColor = color;
for (int i = 0; i < m; ++i) {
@ -123,12 +151,14 @@ struct EdgeColoringInkTrapCorner {
void edgeColoringInkTrap(Shape &shape, double angleThreshold, unsigned long long seed) {
typedef EdgeColoringInkTrapCorner Corner;
double crossThreshold = sin(angleThreshold);
EdgeColor color = initColor(seed);
std::vector<Corner> corners;
for (std::vector<Contour>::iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) {
// Identify corners
if (contour->edges.empty())
continue;
double splineLength = 0;
{ // Identify corners
corners.clear();
if (!contour->edges.empty()) {
Vector2 prevDirection = contour->edges.back()->direction(1);
int index = 0;
for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge, ++index) {
@ -143,19 +173,24 @@ void edgeColoringInkTrap(Shape &shape, double angleThreshold, unsigned long long
}
// Smooth contour
if (corners.empty())
if (corners.empty()) {
switchColor(color, seed);
for (std::vector<EdgeHolder>::iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge)
(*edge)->color = WHITE;
(*edge)->color = color;
}
// "Teardrop" case
else if (corners.size() == 1) {
EdgeColor colors[3] = { WHITE, WHITE };
switchColor(colors[0], seed);
switchColor(colors[2] = colors[0], seed);
EdgeColor colors[3];
switchColor(color, seed);
colors[0] = color;
colors[1] = WHITE;
switchColor(color, seed);
colors[2] = color;
int corner = corners[0].index;
if (contour->edges.size() >= 3) {
int m = (int) contour->edges.size();
for (int i = 0; i < m; ++i)
contour->edges[(corner+i)%m]->color = (colors+1)[int(3+2.875*i/(m-1)-1.4375+.5)-3];
contour->edges[(corner+i)%m]->color = colors[1+symmetricalTrichotomy(i, m)];
} else if (contour->edges.size() >= 1) {
// Less than three edge segments for three colors => edges must be split
EdgeSegment *parts[7] = { };
@ -191,7 +226,6 @@ void edgeColoringInkTrap(Shape &shape, double angleThreshold, unsigned long long
}
}
}
EdgeColor color = WHITE;
EdgeColor initialColor = BLACK;
for (int i = 0; i < cornerCount; ++i) {
if (!corners[i].minor) {
@ -271,23 +305,19 @@ static void colorSecondDegreeGraph(int *coloring, const int *const *edgeMatrix,
color = 1;
break;
case 3:
color = (int) seed&1;
seed >>= 1;
color = seedExtract2(seed); // 0 or 1
break;
case 4:
color = 2;
break;
case 5:
color = ((int) seed+1&1)<<1;
seed >>= 1;
color = (int) !seedExtract2(seed)<<1; // 2 or 0
break;
case 6:
color = ((int) seed&1)+1;
seed >>= 1;
color = seedExtract2(seed)+1; // 1 or 2
break;
case 7:
color = int((seed+i)%3);
seed /= 3;
color = (seedExtract3(seed)+i)%3; // 0 or 1 or 2
break;
}
coloring[i] = color;
@ -394,7 +424,7 @@ void edgeColoringByDistance(Shape &shape, double angleThreshold, unsigned long l
for (int i = 0; i < m; ++i) {
if (i == m/2)
splineStarts.push_back((int) edgeSegments.size());
if (int(3+2.875*i/(m-1)-1.4375+.5)-3)
if (symmetricalTrichotomy(i, m))
edgeSegments.push_back(&*contour->edges[(corner+i)%m]);
else
contour->edges[(corner+i)%m]->color = WHITE;

View File

@ -2,7 +2,7 @@
/*
* MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR - standalone console program
* --------------------------------------------------------------------------
* A utility by Viktor Chlumsky, (c) 2014 - 2023
* A utility by Viktor Chlumsky, (c) 2014 - 2024
*
*/

View File

@ -4,7 +4,7 @@
/*
* MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR
* ---------------------------------------------
* A utility by Viktor Chlumsky, (c) 2014 - 2023
* A utility by Viktor Chlumsky, (c) 2014 - 2024
*
* The extension module provides ways to easily load input and save output using popular formats.
*

View File

@ -4,7 +4,7 @@
/*
* MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR
* ---------------------------------------------
* A utility by Viktor Chlumsky, (c) 2014 - 2023
* A utility by Viktor Chlumsky, (c) 2014 - 2024
*
* The technique used to generate multi-channel distance fields in this code
* has been developed by Viktor Chlumsky in 2014 for his master's thesis,