Skip to content

ENH: Add new color palettes for IPF Colors based on the Nolze & Hielscher color mapping#44

Open
imikejackson wants to merge 16 commits intoBlueQuartzSoftware:developfrom
imikejackson:topic/color_palettes
Open

ENH: Add new color palettes for IPF Colors based on the Nolze & Hielscher color mapping#44
imikejackson wants to merge 16 commits intoBlueQuartzSoftware:developfrom
imikejackson:topic/color_palettes

Conversation

@imikejackson
Copy link
Copy Markdown
Collaborator

No description provided.

imikejackson and others added 16 commits April 9, 2026 19:28
Header-only utility in ebsdlib::color namespace providing hslToRgb,
hslToHsv, and rgbToBytes functions, with Catch2 unit tests covering
primary colors, achromatic cases, and round-trip value bounds.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…gies

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… for all 11 Laue groups

Implements sector geometry definitions (boundary normals, vertices,
barycenter) and normalized polar coordinate computation (radius, azimuth)
for all 11 Laue groups. Each sector is defined by half-space boundary
normals with factory methods for cubicHigh (m-3m), cubicLow (m-3),
hexagonalHigh (6/mmm), hexagonalLow (6/m), tetragonalHigh (4/mmm),
tetragonalLow (4/m), trigonalHigh (-3m), trigonalLow (-3),
orthorhombic (mmm), monoclinic (2/m), and triclinic (-1). Includes
8 Catch2 unit tests covering vertex geometry, polar coordinates,
isInside checks, barycenter validity, and azimuthal correction.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduces TSLColorKey implementing IColorKey with the traditional
TSL/HKL IPF color algorithm refactored from LaueOps::computeIPFColor().
Adds unit tests covering corner colors, grid validity, regression
values, polymorphic usage, and the default angle limits override.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds NolzeHielscherColorKey that maps crystal directions to RGB colors
via the perceptually improved scheme from Nolze & Hielscher (2016).
Uses polar coordinates from FundamentalSectorGeometry, maps azimuthal
angle to hue, radial distance to lightness via nonlinear function
(center=white, boundary=saturated), and derives saturation from lightness.
Includes static helpers for hue speed, lightness, and saturation functions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add setColorKey/getColorKey methods to LaueOps and delegate IPF color
computation to the configured IColorKey strategy in computeIPFColor().
The default color key is TSLColorKey, preserving full backward
compatibility. Integration tests verify default TSL behavior, switching
to NolzeHielscher, and backward-compatible IPF color output.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…scher color key

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…/m, 4/m, 2/m)

Add dual white/black center coloring for "extended" mode Laue groups per
Nolze-Hielscher paper Section 2.6. Directions in the supergroup sector get
white-center mapping (L: 1.0->0.5), directions outside get black-center
mapping (L: 0.0->0.5), meeting continuously at fully saturated boundaries.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds TEST_CASE blocks for ImpossibleMode_Triclinic and ImpossibleMode_TrigonalLow
verifying that direction2Color produces valid [0,1] RGB output for the impossible
coloring path and that the sector barycenter maps to near-white, consistent with
the paper's compromise (a) for -1 and -3 Laue groups.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…legends

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The radius-to-lightness mapping was inverted: center (r=0) was mapping
to the equator of the color sphere (fully saturated) instead of the
pole (white/gray). Fixed to map center->1.0 (white) and boundary->0.5
(saturated), matching the Nolze-Hielscher paper's intent.

Also replaced the paper's simple lightness formula with a gray gradient
blending approach that produces a compact white center with rich,
saturated colors covering most of the sector area.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two fixes to match the MTEX reference output:

1. Added Gaussian CDF-based hue correction that expands compressed
   yellow, cyan, and magenta hue regions. Uses three Gaussian bumps
   at R(0), G(1/3), B(2/3) positions with width parameter 200,
   precomputed as a CDF lookup table in the constructor.

2. Applied power curve (r^0.35) to the radius before lightness mapping
   to compress the white center and expand the saturated color region.
   This brings mean saturation from 0.218 to 0.513 (MTEX reference: 0.521).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implements the azimuthal angle correction from the paper (Appendix A.1)
that was previously left as an identity mapping. The correction:

1. Samples the boundary distance d(rho) at 1000 angles around the
   barycenter using the same great-circle intersection algorithm
2. Weights the angular distribution by d(rho) so that directions
   where the boundary is farther away get more hue space
3. Normalizes within each vertex sector so each vertex gets an
   equal share of the hue circle (2*pi / nVertices)
4. Builds a cumulative lookup table for fast interpolation

This smooths the visible seam lines that appeared where the
"nearest boundary" switches between different boundary normals,
producing continuous color gradients matching the MTEX reference.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The sharp color transition lines ("gray bands") radiating from the center
were caused by the radius computation producing non-monotonic values
along radial paths. When the "closest boundary" switched between
different boundary normals, the radius would dip, creating visible seams.

Fixed by adopting the orix/MTEX polar coordinate algorithm:
- Uses angle(-v, bp) / angle(-center, bp) instead of
  angle(center, h) / angle(center, bp)
- Cross product order: v.cross(center) then gcN.cross(normal)
- Convention: radius=1 at center (white), radius=0 at boundary (saturated)
- This produces monotonically varying radius along any radial path,
  eliminating the gray band artifacts

Updated NolzeHielscherColorKey to use the new convention:
- White center: r = 0.5 + radius/2 maps [1,0] -> [1.0, 0.5]
- No power curve needed since the orix formula already distributes
  colors well

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implements the Decorator pattern: GriddedColorKey wraps any IColorKey
with grid-based flat shading. Colors are precomputed at regular angular
intervals (default 1 degree, matching MTEX) and looked up via nearest-
grid-point snapping. This produces flat-colored patches that hide C1
discontinuities in the underlying color function.

Adds LegendRenderMode enum and setLegendRenderMode() convenience method
to LaueOps for switching between PerPixel (EbsdLib default) and
GridInterpolated (MTEX-style) rendering.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant