23
23
from __future__ import annotations
24
24
25
25
import numpy as np
26
-
27
26
from colour .colorimetry import (
28
27
MultiSpectralDistributions ,
29
28
SpectralDistribution ,
38
37
Literal ,
39
38
NDArrayFloat ,
40
39
)
40
+ from colour .models .cie_xyy import XYZ_to_xy
41
41
from colour .utilities import CACHE_REGISTRY , validate_method , zeros
42
42
from colour .volume import is_within_mesh_volume
43
43
@@ -386,14 +386,20 @@ def is_within_visible_spectrum(
386
386
** kwargs : Any ,
387
387
) -> NDArrayFloat :
388
388
"""
389
- Return whether given *CIE XYZ* tristimulus values are within the visible
390
- spectrum volume, i.e. *Rösch-MacAdam* colour solid, for given colour
391
- matching functions and illuminant.
389
+ Return whether given *CIE XYZ* tristimulus values or *CIE xy* chromaticity
390
+ values are within the visible spectrum volume, i.e. *Rösch-MacAdam* colour
391
+ solid, for given colour matching functions and illuminant.
392
+
393
+ For the brightness invariant *CIE xy* check, the limit is determined by the
394
+ spectral locus and "line of purples" depending on the precision of the
395
+ spectral arguments.
392
396
393
397
Parameters
394
398
----------
395
399
XYZ
396
- *CIE XYZ* tristimulus values.
400
+ *CIE XYZ* or xy tristimulus values. xy chromaticity mode will be
401
+ selected if the size of the last dimension is 2. i.e. if XYZ.shape[-1]
402
+ == 2
397
403
cmfs
398
404
Standard observer colour matching functions, default to the
399
405
*CIE 1931 2 Degree Standard Observer*.
@@ -432,6 +438,16 @@ def is_within_visible_spectrum(
432
438
array([ True, False], dtype=bool)
433
439
"""
434
440
441
+ XYZ = np .asarray (XYZ )
442
+ if XYZ .shape [- 1 ] == 2 :
443
+ return _is_within_visible_xy (
444
+ XYZ ,
445
+ cmfs = cmfs ,
446
+ illuminant = illuminant ,
447
+ tolerance = tolerance ,
448
+ ** kwargs ,
449
+ )
450
+
435
451
cmfs , illuminant = handle_spectral_arguments (
436
452
cmfs ,
437
453
illuminant ,
@@ -449,3 +465,76 @@ def is_within_visible_spectrum(
449
465
)
450
466
451
467
return is_within_mesh_volume (XYZ , vertices , tolerance )
468
+
469
+
470
+ def _is_within_visible_xy (
471
+ xy : ArrayLike ,
472
+ cmfs : MultiSpectralDistributions | None = None ,
473
+ illuminant : SpectralDistribution | None = None ,
474
+ tolerance : float = 100 * EPSILON ,
475
+ ** kwargs : Any ,
476
+ ) -> NDArrayFloat :
477
+ """
478
+ Return whether given *CIE XYZ* tristimulus values are within the visible
479
+ spectrum volume, i.e. *Rösch-MacAdam* colour solid, for given colour
480
+ matching functions and illuminant.
481
+
482
+ Parameters
483
+ ----------
484
+ XYZ
485
+ *CIE XYZ* tristimulus values.
486
+ cmfs
487
+ Standard observer colour matching functions, default to the
488
+ *CIE 1931 2 Degree Standard Observer*.
489
+ illuminant
490
+ Illuminant spectral distribution, default to *CIE Illuminant E*.
491
+ tolerance
492
+ Tolerance allowed in the inside-triangle check.
493
+
494
+ Other Parameters
495
+ ----------------
496
+ kwargs
497
+ {:func:`colour.msds_to_XYZ`},
498
+ See the documentation of the previously listed definition.
499
+
500
+ Returns
501
+ -------
502
+ :class:`numpy.ndarray`
503
+ Are *CIE XYZ* tristimulus values within the visible spectrum volume,
504
+ i.e. *Rösch-MacAdam* colour solid.
505
+
506
+ Notes
507
+ -----
508
+ +------------+-----------------------+---------------+
509
+ | **Domain** | **Scale - Reference** | **Scale - 1** |
510
+ +============+=======================+===============+
511
+ | ``XYZ`` | [0, 1] | [0, 1] |
512
+ +------------+-----------------------+---------------+
513
+
514
+ Examples
515
+ --------
516
+ >>> import numpy as np
517
+ >>> is_within_visible_spectrum(np.array([0.33,0.33]))
518
+ array(True, dtype=bool)
519
+ >>> a = np.array([[.33,.33], [.1,.1]])
520
+ >>> is_within_visible_spectrum(a)
521
+ array([ True, False], dtype=bool)
522
+ """
523
+
524
+ cmfs , illuminant = handle_spectral_arguments (
525
+ cmfs ,
526
+ illuminant ,
527
+ "CIE 1931 2 Degree Standard Observer" ,
528
+ "E" ,
529
+ SPECTRAL_SHAPE_OUTER_SURFACE_XYZ ,
530
+ )
531
+
532
+ key = (hash (cmfs ), hash (illuminant ), str (kwargs ))
533
+ vertices = _CACHE_OUTER_SURFACE_XYZ_POINTS .get (key )
534
+
535
+ if vertices is None :
536
+ _CACHE_OUTER_SURFACE_XYZ_POINTS [key ] = vertices = XYZ_to_xy (
537
+ cmfs .values
538
+ )
539
+
540
+ return is_within_mesh_volume (xy , vertices , tolerance )
0 commit comments