io/ies.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // SPDX-License-Identifier: BSD-3-Clause | ||
| 2 | /// @file ies.h | ||
| 3 | /// @brief IES LM-63 photometric profiles of luminaires. | ||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "ernie/export.h" | ||
| 7 | |||
| 8 | #include "ernie/util/glm.h" | ||
| 9 | |||
| 10 | #include <filesystem> | ||
| 11 | #include <string_view> | ||
| 12 | #include <vector> | ||
| 13 | |||
| 14 | namespace ernie { | ||
| 15 | |||
| 16 | /// @brief The axis an IES file's angles turn about. | ||
| 17 | /// In the luminaire's frame: x its length and 0 degree plane, y its | ||
| 18 | /// width, z up; it shines down -z. | ||
| 19 | enum class IesType { | ||
| 20 | /// Type C: about the vertical axis z. The vertical angle runs | ||
| 21 | /// from the nadir (0) to the zenith (180); the horizontal angle | ||
| 22 | /// turns around z from x towards y. Most luminaires. | ||
| 23 | C = 1, | ||
| 24 | /// Type B: about the width y (floodlights). The vertical angle | ||
| 25 | /// turns the plane through y, from the nadir towards x; the | ||
| 26 | /// horizontal angle leaves that plane, towards -y; both -90 to | ||
| 27 | /// 90. | ||
| 28 | B = 2, | ||
| 29 | /// Type A: about the length x (automotive lamps). The vertical | ||
| 30 | /// angle turns the plane through x, from the nadir towards y; the | ||
| 31 | /// horizontal angle leaves that plane, towards x. | ||
| 32 | A = 3, | ||
| 33 | }; | ||
| 34 | |||
| 35 | /// @brief How a lamp's output changes as its luminaire tilts. | ||
| 36 | /// From TILT=INCLUDE or a tilt file; for lamps sensitive to burning | ||
| 37 | /// position, such as metal halide. | ||
| 38 | 7 | struct ERNIE_API IesTilt { | |
| 39 | /// Lamp position: 1 vertical, 2 horizontal along x (0 degree | ||
| 40 | /// plane), 3 horizontal along y (90 degree plane); 0 for none. | ||
| 41 | int geometry = 0; | ||
| 42 | /// Tilt angles, in degrees, increasing. | ||
| 43 | std::vector<double> angles; | ||
| 44 | /// Candela multipliers at each angle. | ||
| 45 | std::vector<double> factors; | ||
| 46 | |||
| 47 | /// @brief The luminaire's tilt for the lamp's geometry. | ||
| 48 | /// Vertical lamps: the luminaire z's angle from vertical. | ||
| 49 | /// Horizontal lamps: the lamp axis's elevation. | ||
| 50 | /// @param x The luminaire's x axis in a z-up world (unit). | ||
| 51 | /// @param y The luminaire's y axis (unit). | ||
| 52 | /// @param z The luminaire's z axis (unit). | ||
| 53 | /// @return The tilt, in degrees. | ||
| 54 | double Angle(const glm::dvec3& x, const glm::dvec3& y, const glm::dvec3& z) const; | ||
| 55 | |||
| 56 | /// @brief The multiplier at a tilt. | ||
| 57 | /// Linear between the file's angles, held beyond; data up to 90 | ||
| 58 | /// degrees mirrors past it. | ||
| 59 | /// @param degrees The tilt, in degrees. | ||
| 60 | /// @return The factor; 1 without tilt data. | ||
| 61 | double Factor(double degrees) const; | ||
| 62 | }; | ||
| 63 | |||
| 64 | /// @brief A luminaire's luminous intensity from an IES LM-63 file. | ||
| 65 | /// Files may give a half, quadrant or one plane of a symmetric | ||
| 66 | /// luminaire; `Sample` mirrors them. | ||
| 67 | /// | ||
| 68 | /// References: | ||
| 69 | /// - IES LM-63-19, Approved Method: IES Standard File Format for the | ||
| 70 | /// Electronic Transfer of Photometric Data and Related Information, | ||
| 71 | /// Illuminating Engineering Society, 2019. | ||
| 72 | /// - I. Ashdown, "Parsing the IESNA LM-63 Photometric Data File", | ||
| 73 | /// 1998, http://lumen.iee.put.poznan.pl/kw/iesna.txt | ||
| 74 | /// - G. Ward, Radiance ies2rad, source.cal and tilt.cal (type B | ||
| 75 | /// coordinates and tilt angles), | ||
| 76 | /// https://github.com/NREL/Radiance/tree/master/src/cv | ||
| 77 | struct ERNIE_API IesProfile { | ||
| 78 | /// The photometric type. | ||
| 79 | IesType type = IesType::C; | ||
| 80 | /// Vertical angles, in degrees, increasing. | ||
| 81 | std::vector<double> vertical; | ||
| 82 | /// Horizontal angles, in degrees, increasing. | ||
| 83 | std::vector<double> horizontal; | ||
| 84 | /// Candela, `horizontal.size()` rows of `vertical.size()`, with | ||
| 85 | /// the file's multiplier and ballast factor applied. | ||
| 86 | std::vector<double> candela; | ||
| 87 | /// The tilt data. | ||
| 88 | IesTilt tilt; | ||
| 89 | |||
| 90 | /// @brief Intensity in a direction, bilinear between the file's | ||
| 91 | /// angles and mirrored by its symmetry. | ||
| 92 | /// @param theta Degrees from the nadir (-z). | ||
| 93 | /// @param phi Degrees around the nadir, from x towards y. | ||
| 94 | /// @return Candela; 0 outside the file's angles. | ||
| 95 | double Sample(double theta, double phi) const; | ||
| 96 | |||
| 97 | /// @return The luminous flux over the sphere, in lumens. | ||
| 98 | double Flux() const; | ||
| 99 | |||
| 100 | private: | ||
| 101 | /// Candela at the file's vertical angle `v` and horizontal angle | ||
| 102 | /// `h`, in its coordinates. | ||
| 103 | double Table(double v, double h) const; | ||
| 104 | }; | ||
| 105 | |||
| 106 | /// @brief Parses LM-63 text, versions 1986 to 2019, types A, B, C. | ||
| 107 | /// @param text The file's contents. | ||
| 108 | /// @param directory Where a TILT=<file> is resolved. | ||
| 109 | /// @return The profile with its tilt data. | ||
| 110 | /// @throws std::invalid_argument If the text is not LM-63, has an | ||
| 111 | /// unknown type, or has angles out of order. | ||
| 112 | /// @throws std::runtime_error If a tilt file cannot be read. | ||
| 113 | ERNIE_API IesProfile ParseIes(std::string_view text, const std::filesystem::path& directory = {}); | ||
| 114 | |||
| 115 | /// @brief Reads and parses an IES file; tilt files resolve beside it. | ||
| 116 | /// @param path The file. | ||
| 117 | /// @return The profile. | ||
| 118 | /// @throws std::runtime_error If it cannot be read. | ||
| 119 | ERNIE_API IesProfile ReadIes(const std::filesystem::path& path); | ||
| 120 | |||
| 121 | } // namespace ernie | ||
| 122 |