mirror of https://github.com/Chlumsky/msdfgen.git
Edge coloring update, circles no longer white
This commit is contained in:
parent
682381a03c
commit
35f92541c4
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
2
main.cpp
2
main.cpp
|
|
@ -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
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue