This source file includes following definitions.
- _cmsAtan2
- ToSpherical
- ToCartesian
- QuantizeToSector
- LineOf2Points
- GetPointOfLine
- ClosestLineToLine
- cmsGBDAlloc
- cmsGBDFree
- GetPoint
- cmsGDBAddPoint
- cmsGDBCheckPoint
- FindNearSectors
- InterpolateMissingSector
- cmsGDBCompute
- cmsGBDdumpVRML
#include "lcms2_internal.h"
#define SECTORS 16
typedef struct {
cmsFloat64Number r;
cmsFloat64Number alpha;
cmsFloat64Number theta;
} cmsSpherical;
typedef enum {
GP_EMPTY,
GP_SPECIFIED,
GP_MODELED
} GDBPointType;
typedef struct {
GDBPointType Type;
cmsSpherical p;
} cmsGDBPoint;
typedef struct {
cmsContext ContextID;
cmsGDBPoint Gamut[SECTORS][SECTORS];
} cmsGDB;
typedef struct {
cmsVEC3 a;
cmsVEC3 u;
} cmsLine;
typedef struct {
cmsVEC3 b;
cmsVEC3 v;
cmsVEC3 w;
} cmsPlane;
static
cmsFloat64Number _cmsAtan2(cmsFloat64Number y, cmsFloat64Number x)
{
cmsFloat64Number a;
if (x == 0.0 && y == 0.0) return 0;
a = (atan2(y, x) * 180.0) / M_PI;
while (a < 0) {
a += 360;
}
return a;
}
static
void ToSpherical(cmsSpherical* sp, const cmsVEC3* v)
{
cmsFloat64Number L, a, b;
L = v ->n[VX];
a = v ->n[VY];
b = v ->n[VZ];
sp ->r = sqrt( L*L + a*a + b*b );
if (sp ->r == 0) {
sp ->alpha = sp ->theta = 0;
return;
}
sp ->alpha = _cmsAtan2(a, b);
sp ->theta = _cmsAtan2(sqrt(a*a + b*b), L);
}
static
void ToCartesian(cmsVEC3* v, const cmsSpherical* sp)
{
cmsFloat64Number sin_alpha;
cmsFloat64Number cos_alpha;
cmsFloat64Number sin_theta;
cmsFloat64Number cos_theta;
cmsFloat64Number L, a, b;
sin_alpha = sin((M_PI * sp ->alpha) / 180.0);
cos_alpha = cos((M_PI * sp ->alpha) / 180.0);
sin_theta = sin((M_PI * sp ->theta) / 180.0);
cos_theta = cos((M_PI * sp ->theta) / 180.0);
a = sp ->r * sin_theta * sin_alpha;
b = sp ->r * sin_theta * cos_alpha;
L = sp ->r * cos_theta;
v ->n[VX] = L;
v ->n[VY] = a;
v ->n[VZ] = b;
}
static
void QuantizeToSector(const cmsSpherical* sp, int* alpha, int* theta)
{
*alpha = (int) floor(((sp->alpha * (SECTORS)) / 360.0) );
*theta = (int) floor(((sp->theta * (SECTORS)) / 180.0) );
if (*alpha >= SECTORS)
*alpha = SECTORS-1;
if (*theta >= SECTORS)
*theta = SECTORS-1;
}
static
void LineOf2Points(cmsLine* line, cmsVEC3* a, cmsVEC3* b)
{
_cmsVEC3init(&line ->a, a ->n[VX], a ->n[VY], a ->n[VZ]);
_cmsVEC3init(&line ->u, b ->n[VX] - a ->n[VX],
b ->n[VY] - a ->n[VY],
b ->n[VZ] - a ->n[VZ]);
}
static
void GetPointOfLine(cmsVEC3* p, const cmsLine* line, cmsFloat64Number t)
{
p ->n[VX] = line ->a.n[VX] + t * line->u.n[VX];
p ->n[VY] = line ->a.n[VY] + t * line->u.n[VY];
p ->n[VZ] = line ->a.n[VZ] + t * line->u.n[VZ];
}
static
cmsBool ClosestLineToLine(cmsVEC3* r, const cmsLine* line1, const cmsLine* line2)
{
cmsFloat64Number a, b, c, d, e, D;
cmsFloat64Number sc, sN, sD;
cmsFloat64Number tc, tN, tD;
cmsVEC3 w0;
_cmsVEC3minus(&w0, &line1 ->a, &line2 ->a);
a = _cmsVEC3dot(&line1 ->u, &line1 ->u);
b = _cmsVEC3dot(&line1 ->u, &line2 ->u);
c = _cmsVEC3dot(&line2 ->u, &line2 ->u);
d = _cmsVEC3dot(&line1 ->u, &w0);
e = _cmsVEC3dot(&line2 ->u, &w0);
D = a*c - b * b;
sD = tD = D;
if (D < MATRIX_DET_TOLERANCE) {
sN = 0.0;
sD = 1.0;
tN = e;
tD = c;
}
else {
sN = (b*e - c*d);
tN = (a*e - b*d);
if (sN < 0.0) {
sN = 0.0;
tN = e;
tD = c;
}
else if (sN > sD) {
sN = sD;
tN = e + b;
tD = c;
}
}
if (tN < 0.0) {
tN = 0.0;
if (-d < 0.0)
sN = 0.0;
else if (-d > a)
sN = sD;
else {
sN = -d;
sD = a;
}
}
else if (tN > tD) {
tN = tD;
if ((-d + b) < 0.0)
sN = 0;
else if ((-d + b) > a)
sN = sD;
else {
sN = (-d + b);
sD = a;
}
}
sc = (fabs(sN) < MATRIX_DET_TOLERANCE ? 0.0 : sN / sD);
tc = (fabs(tN) < MATRIX_DET_TOLERANCE ? 0.0 : tN / tD);
GetPointOfLine(r, line1, sc);
return TRUE;
}
cmsHANDLE CMSEXPORT cmsGBDAlloc(cmsContext ContextID)
{
cmsGDB* gbd = (cmsGDB*) _cmsMallocZero(ContextID, sizeof(cmsGDB));
if (gbd == NULL) return NULL;
gbd -> ContextID = ContextID;
return (cmsHANDLE) gbd;
}
void CMSEXPORT cmsGBDFree(cmsHANDLE hGBD)
{
cmsGDB* gbd = (cmsGDB*) hGBD;
if (hGBD != NULL)
_cmsFree(gbd->ContextID, (void*) gbd);
}
static
cmsGDBPoint* GetPoint(cmsGDB* gbd, const cmsCIELab* Lab, cmsSpherical* sp)
{
cmsVEC3 v;
int alpha, theta;
_cmsAssert(gbd != NULL);
_cmsAssert(Lab != NULL);
_cmsAssert(sp != NULL);
_cmsVEC3init(&v, Lab ->L - 50.0, Lab ->a, Lab ->b);
ToSpherical(sp, &v);
if (sp ->r < 0 || sp ->alpha < 0 || sp->theta < 0) {
cmsSignalError(gbd ->ContextID, cmsERROR_RANGE, "spherical value out of range");
return NULL;
}
QuantizeToSector(sp, &alpha, &theta);
if (alpha < 0 || theta < 0 || alpha >= SECTORS || theta >= SECTORS) {
cmsSignalError(gbd ->ContextID, cmsERROR_RANGE, " quadrant out of range");
return NULL;
}
return &gbd ->Gamut[theta][alpha];
}
cmsBool CMSEXPORT cmsGDBAddPoint(cmsHANDLE hGBD, const cmsCIELab* Lab)
{
cmsGDB* gbd = (cmsGDB*) hGBD;
cmsGDBPoint* ptr;
cmsSpherical sp;
ptr = GetPoint(gbd, Lab, &sp);
if (ptr == NULL) return FALSE;
if (ptr ->Type == GP_EMPTY) {
ptr -> Type = GP_SPECIFIED;
ptr -> p = sp;
}
else {
if (sp.r > ptr -> p.r) {
ptr -> Type = GP_SPECIFIED;
ptr -> p = sp;
}
}
return TRUE;
}
cmsBool CMSEXPORT cmsGDBCheckPoint(cmsHANDLE hGBD, const cmsCIELab* Lab)
{
cmsGDB* gbd = (cmsGDB*) hGBD;
cmsGDBPoint* ptr;
cmsSpherical sp;
ptr = GetPoint(gbd, Lab, &sp);
if (ptr == NULL) return FALSE;
if (ptr ->Type == GP_EMPTY) return FALSE;
return (sp.r <= ptr -> p.r);
}
static
const struct _spiral {
int AdvX, AdvY;
} Spiral[] = { {0, -1}, {+1, -1}, {+1, 0}, {+1, +1}, {0, +1}, {-1, +1},
{-1, 0}, {-1, -1}, {-1, -2}, {0, -2}, {+1, -2}, {+2, -2},
{+2, -1}, {+2, 0}, {+2, +1}, {+2, +2}, {+1, +2}, {0, +2},
{-1, +2}, {-2, +2}, {-2, +1}, {-2, 0}, {-2, -1}, {-2, -2} };
#define NSTEPS (sizeof(Spiral) / sizeof(struct _spiral))
static
int FindNearSectors(cmsGDB* gbd, int alpha, int theta, cmsGDBPoint* Close[])
{
int nSectors = 0;
int a, t;
cmsUInt32Number i;
cmsGDBPoint* pt;
for (i=0; i < NSTEPS; i++) {
a = alpha + Spiral[i].AdvX;
t = theta + Spiral[i].AdvY;
a %= SECTORS;
t %= SECTORS;
if (a < 0) a = SECTORS + a;
if (t < 0) t = SECTORS + t;
pt = &gbd ->Gamut[t][a];
if (pt -> Type != GP_EMPTY) {
Close[nSectors++] = pt;
}
}
return nSectors;
}
static
cmsBool InterpolateMissingSector(cmsGDB* gbd, int alpha, int theta)
{
cmsSpherical sp;
cmsVEC3 Lab;
cmsVEC3 Centre;
cmsLine ray;
int nCloseSectors;
cmsGDBPoint* Close[NSTEPS + 1];
cmsSpherical closel, templ;
cmsLine edge;
int k, m;
if (gbd ->Gamut[theta][alpha].Type != GP_EMPTY) return TRUE;
nCloseSectors = FindNearSectors(gbd, alpha, theta, Close);
sp.alpha = (cmsFloat64Number) ((alpha + 0.5) * 360.0) / (SECTORS);
sp.theta = (cmsFloat64Number) ((theta + 0.5) * 180.0) / (SECTORS);
sp.r = 50.0;
ToCartesian(&Lab, &sp);
_cmsVEC3init(&Centre, 50.0, 0, 0);
LineOf2Points(&ray, &Lab, &Centre);
closel.r = 0.0;
closel.alpha = 0;
closel.theta = 0;
for (k=0; k < nCloseSectors; k++) {
for(m = k+1; m < nCloseSectors; m++) {
cmsVEC3 temp, a1, a2;
ToCartesian(&a1, &Close[k]->p);
ToCartesian(&a2, &Close[m]->p);
LineOf2Points(&edge, &a1, &a2);
ClosestLineToLine(&temp, &ray, &edge);
ToSpherical(&templ, &temp);
if ( templ.r > closel.r &&
templ.theta >= (theta*180.0/SECTORS) &&
templ.theta <= ((theta+1)*180.0/SECTORS) &&
templ.alpha >= (alpha*360.0/SECTORS) &&
templ.alpha <= ((alpha+1)*360.0/SECTORS)) {
closel = templ;
}
}
}
gbd ->Gamut[theta][alpha].p = closel;
gbd ->Gamut[theta][alpha].Type = GP_MODELED;
return TRUE;
}
cmsBool CMSEXPORT cmsGDBCompute(cmsHANDLE hGBD, cmsUInt32Number dwFlags)
{
int alpha, theta;
cmsGDB* gbd = (cmsGDB*) hGBD;
_cmsAssert(hGBD != NULL);
for (alpha = 0; alpha < SECTORS; alpha++) {
if (!InterpolateMissingSector(gbd, alpha, 0)) return FALSE;
}
for (alpha = 0; alpha < SECTORS; alpha++) {
if (!InterpolateMissingSector(gbd, alpha, SECTORS-1)) return FALSE;
}
for (theta = 1; theta < SECTORS; theta++) {
for (alpha = 0; alpha < SECTORS; alpha++) {
if (!InterpolateMissingSector(gbd, alpha, theta)) return FALSE;
}
}
return TRUE;
cmsUNUSED_PARAMETER(dwFlags);
}
#if 0
cmsBool cmsGBDdumpVRML(cmsHANDLE hGBD, const char* fname)
{
FILE* fp;
int i, j;
cmsGDB* gbd = (cmsGDB*) hGBD;
cmsGDBPoint* pt;
fp = fopen (fname, "wt");
if (fp == NULL)
return FALSE;
fprintf (fp, "#VRML V2.0 utf8\n");
fprintf (fp, "DEF CamTest Group {\n");
fprintf (fp, "\tchildren [\n");
fprintf (fp, "\t\tDEF Cameras Group {\n");
fprintf (fp, "\t\t\tchildren [\n");
fprintf (fp, "\t\t\t\tDEF DefaultView Viewpoint {\n");
fprintf (fp, "\t\t\t\t\tposition 0 0 340\n");
fprintf (fp, "\t\t\t\t\torientation 0 0 1 0\n");
fprintf (fp, "\t\t\t\t\tdescription \"default view\"\n");
fprintf (fp, "\t\t\t\t}\n");
fprintf (fp, "\t\t\t]\n");
fprintf (fp, "\t\t},\n");
fprintf (fp, "\t]\n");
fprintf (fp, "}\n");
fprintf (fp, "Background {\n");
fprintf (fp, "\tskyColor [\n");
fprintf (fp, "\t\t.5 .5 .5\n");
fprintf (fp, "\t]\n");
fprintf (fp, "}\n");
fprintf (fp, "Transform {\n");
fprintf (fp, "\tscale .3 .3 .3\n");
fprintf (fp, "\tchildren [\n");
fprintf (fp, "\t\tShape {\n");
fprintf (fp, "\t\t\tappearance Appearance {\n");
fprintf (fp, "\t\t\t\tmaterial Material {\n");
fprintf (fp, "\t\t\t\t\tdiffuseColor 0 0.8 0\n");
fprintf (fp, "\t\t\t\t\temissiveColor 1.0 1.0 1.0\n");
fprintf (fp, "\t\t\t\t\tshininess 0.8\n");
fprintf (fp, "\t\t\t\t}\n");
fprintf (fp, "\t\t\t}\n");
fprintf (fp, "\t\t\tgeometry IndexedLineSet {\n");
fprintf (fp, "\t\t\t\tcoord Coordinate {\n");
fprintf (fp, "\t\t\t\t\tpoint [\n");
fprintf (fp, "\t\t\t\t\t0.0 0.0 0.0,\n");
fprintf (fp, "\t\t\t\t\t%f 0.0 0.0,\n", 255.0);
fprintf (fp, "\t\t\t\t\t0.0 %f 0.0,\n", 255.0);
fprintf (fp, "\t\t\t\t\t0.0 0.0 %f]\n", 255.0);
fprintf (fp, "\t\t\t\t}\n");
fprintf (fp, "\t\t\t\tcoordIndex [\n");
fprintf (fp, "\t\t\t\t\t0, 1, -1\n");
fprintf (fp, "\t\t\t\t\t0, 2, -1\n");
fprintf (fp, "\t\t\t\t\t0, 3, -1]\n");
fprintf (fp, "\t\t\t}\n");
fprintf (fp, "\t\t}\n");
fprintf (fp, "\t\tShape {\n");
fprintf (fp, "\t\t\tappearance Appearance {\n");
fprintf (fp, "\t\t\t\tmaterial Material {\n");
fprintf (fp, "\t\t\t\t\tdiffuseColor 0 0.8 0\n");
fprintf (fp, "\t\t\t\t\temissiveColor 1 1 1\n");
fprintf (fp, "\t\t\t\t\tshininess 0.8\n");
fprintf (fp, "\t\t\t\t}\n");
fprintf (fp, "\t\t\t}\n");
fprintf (fp, "\t\t\tgeometry PointSet {\n");
fprintf (fp, "\t\t\t\tcoord Coordinate {\n");
fprintf (fp, "\t\t\t\t\tpoint [\n");
for (i=0; i < SECTORS; i++)
for (j=0; j < SECTORS; j++) {
cmsVEC3 v;
pt = &gbd ->Gamut[i][j];
ToCartesian(&v, &pt ->p);
fprintf (fp, "\t\t\t\t\t%g %g %g", v.n[0]+50, v.n[1], v.n[2]);
if ((j == SECTORS - 1) && (i == SECTORS - 1))
fprintf (fp, "]\n");
else
fprintf (fp, ",\n");
}
fprintf (fp, "\t\t\t\t}\n");
fprintf (fp, "\t\t\t\tcolor Color {\n");
fprintf (fp, "\t\t\t\t\tcolor [\n");
for (i=0; i < SECTORS; i++)
for (j=0; j < SECTORS; j++) {
cmsVEC3 v;
pt = &gbd ->Gamut[i][j];
ToCartesian(&v, &pt ->p);
if (pt ->Type == GP_EMPTY)
fprintf (fp, "\t\t\t\t\t%g %g %g", 0.0, 0.0, 0.0);
else
if (pt ->Type == GP_MODELED)
fprintf (fp, "\t\t\t\t\t%g %g %g", 1.0, .5, .5);
else {
fprintf (fp, "\t\t\t\t\t%g %g %g", 1.0, 1.0, 1.0);
}
if ((j == SECTORS - 1) && (i == SECTORS - 1))
fprintf (fp, "]\n");
else
fprintf (fp, ",\n");
}
fprintf (fp, "\t\t\t}\n");
fprintf (fp, "\t\t\t}\n");
fprintf (fp, "\t\t}\n");
fprintf (fp, "\t]\n");
fprintf (fp, "}\n");
fclose (fp);
return TRUE;
}
#endif