acadrust 0.6.2

A pure Rust library for reading and writing CAD files in DXF format (ASCII and Binary) and DWG format (Binary).
Documentation
//! AutoCAD Color Index (ACI) to RGB lookup table.
//!
//! The canonical 256-entry mapping used by AutoCAD.  Indices 0 (ByBlock) and
//! 256 (ByLayer) are _not_ real colors; index 7 is white on dark backgrounds
//! and black on light backgrounds, mapped here as (255,255,255).
//!
//! Source: AutoCAD Color Index specification, matching ezdxf / LibreCAD tables.

/// RGB tuple for a single ACI entry.
type Rgb = (u8, u8, u8);

/// The standard 256-entry AutoCAD Color Index table (indices 0–255).
///
/// Index 0 maps to (0,0,0) as a placeholder — real usage treats it as ByBlock.
pub static ACI_COLORS: [Rgb; 256] = [
    // 0: ByBlock placeholder
    (0, 0, 0),
    // 1–9: standard colors
    (255, 0, 0),     // 1  Red
    (255, 255, 0),   // 2  Yellow
    (0, 255, 0),     // 3  Green
    (0, 255, 255),   // 4  Cyan
    (0, 0, 255),     // 5  Blue
    (255, 0, 255),   // 6  Magenta
    (255, 255, 255), // 7  White (or Black depending on background)
    (128, 128, 128), // 8  Dark gray
    (192, 192, 192), // 9  Light gray
    // 10–19
    (255, 0, 0),     // 10
    (255, 127, 127), // 11
    (165, 0, 0),     // 12
    (165, 82, 82),   // 13
    (127, 0, 0),     // 14
    (127, 63, 63),   // 15
    (76, 0, 0),      // 16
    (76, 38, 38),    // 17
    (38, 0, 0),      // 18
    (38, 19, 19),    // 19
    // 20–29
    (255, 63, 0),    // 20
    (255, 159, 127), // 21
    (165, 41, 0),    // 22
    (165, 103, 82),  // 23
    (127, 31, 0),    // 24
    (127, 79, 63),   // 25
    (76, 19, 0),     // 26
    (76, 47, 38),    // 27
    (38, 9, 0),      // 28
    (38, 23, 19),    // 29
    // 30–39
    (255, 127, 0),   // 30
    (255, 191, 127), // 31
    (165, 82, 0),    // 32
    (165, 124, 82),  // 33
    (127, 63, 0),    // 34
    (127, 95, 63),   // 35
    (76, 38, 0),     // 36
    (76, 57, 38),    // 37
    (38, 19, 0),     // 38
    (38, 28, 19),    // 39
    // 40–49
    (255, 191, 0),   // 40
    (255, 223, 127), // 41
    (165, 124, 0),   // 42
    (165, 145, 82),  // 43
    (127, 95, 0),    // 44
    (127, 111, 63),  // 45
    (76, 57, 0),     // 46
    (76, 66, 38),    // 47
    (38, 28, 0),     // 48
    (38, 33, 19),    // 49
    // 50–59
    (255, 255, 0),   // 50
    (255, 255, 127), // 51
    (165, 165, 0),   // 52
    (165, 165, 82),  // 53
    (127, 127, 0),   // 54
    (127, 127, 63),  // 55
    (76, 76, 0),     // 56
    (76, 76, 38),    // 57
    (38, 38, 0),     // 58
    (38, 38, 19),    // 59
    // 60–69
    (191, 255, 0),   // 60
    (223, 255, 127), // 61
    (124, 165, 0),   // 62
    (145, 165, 82),  // 63
    (95, 127, 0),    // 64
    (111, 127, 63),  // 65
    (57, 76, 0),     // 66
    (66, 76, 38),    // 67
    (28, 38, 0),     // 68
    (33, 38, 19),    // 69
    // 70–79
    (127, 255, 0),   // 70
    (191, 255, 127), // 71
    (82, 165, 0),    // 72
    (124, 165, 82),  // 73
    (63, 127, 0),    // 74
    (95, 127, 63),   // 75
    (38, 76, 0),     // 76
    (57, 76, 38),    // 77
    (19, 38, 0),     // 78
    (28, 38, 19),    // 79
    // 80–89
    (63, 255, 0),    // 80
    (159, 255, 127), // 81
    (41, 165, 0),    // 82
    (103, 165, 82),  // 83
    (31, 127, 0),    // 84
    (79, 127, 63),   // 85
    (19, 76, 0),     // 86
    (47, 76, 38),    // 87
    (9, 38, 0),      // 88
    (23, 38, 19),    // 89
    // 90–99
    (0, 255, 0),     // 90
    (127, 255, 127), // 91
    (0, 165, 0),     // 92
    (82, 165, 82),   // 93
    (0, 127, 0),     // 94
    (63, 127, 63),   // 95
    (0, 76, 0),      // 96
    (38, 76, 38),    // 97
    (0, 38, 0),      // 98
    (19, 38, 19),    // 99
    // 100–109
    (0, 255, 63),    // 100
    (127, 255, 159), // 101
    (0, 165, 41),    // 102
    (82, 165, 103),  // 103
    (0, 127, 31),    // 104
    (63, 127, 79),   // 105
    (0, 76, 19),     // 106
    (38, 76, 47),    // 107
    (0, 38, 9),      // 108
    (19, 38, 23),    // 109
    // 110–119
    (0, 255, 127),   // 110
    (127, 255, 191), // 111
    (0, 165, 82),    // 112
    (82, 165, 124),  // 113
    (0, 127, 63),    // 114
    (63, 127, 95),   // 115
    (0, 76, 38),     // 116
    (38, 76, 57),    // 117
    (0, 38, 19),     // 118
    (19, 38, 28),    // 119
    // 120–129
    (0, 255, 191),   // 120
    (127, 255, 223), // 121
    (0, 165, 124),   // 122
    (82, 165, 145),  // 123
    (0, 127, 95),    // 124
    (63, 127, 111),  // 125
    (0, 76, 57),     // 126
    (38, 76, 66),    // 127
    (0, 38, 28),     // 128
    (19, 38, 33),    // 129
    // 130–139
    (0, 255, 255),   // 130
    (127, 255, 255), // 131
    (0, 165, 165),   // 132
    (82, 165, 165),  // 133
    (0, 127, 127),   // 134
    (63, 127, 127),  // 135
    (0, 76, 76),     // 136
    (38, 76, 76),    // 137
    (0, 38, 38),     // 138
    (19, 38, 38),    // 139
    // 140–149
    (0, 191, 255),   // 140
    (127, 223, 255), // 141
    (0, 124, 165),   // 142
    (82, 145, 165),  // 143
    (0, 95, 127),    // 144
    (63, 111, 127),  // 145
    (0, 57, 76),     // 146
    (38, 66, 76),    // 147
    (0, 28, 38),     // 148
    (19, 33, 38),    // 149
    // 150–159
    (0, 127, 255),   // 150
    (127, 191, 255), // 151
    (0, 82, 165),    // 152
    (82, 124, 165),  // 153
    (0, 63, 127),    // 154
    (63, 95, 127),   // 155
    (0, 38, 76),     // 156
    (38, 57, 76),    // 157
    (0, 19, 38),     // 158
    (19, 28, 38),    // 159
    // 160–169
    (0, 63, 255),    // 160
    (127, 159, 255), // 161
    (0, 41, 165),    // 162
    (82, 103, 165),  // 163
    (0, 31, 127),    // 164
    (63, 79, 127),   // 165
    (0, 19, 76),     // 166
    (38, 47, 76),    // 167
    (0, 9, 38),      // 168
    (19, 23, 38),    // 169
    // 170–179
    (0, 0, 255),     // 170
    (127, 127, 255), // 171
    (0, 0, 165),     // 172
    (82, 82, 165),   // 173
    (0, 0, 127),     // 174
    (63, 63, 127),   // 175
    (0, 0, 76),      // 176
    (38, 38, 76),    // 177
    (0, 0, 38),      // 178
    (19, 19, 38),    // 179
    // 180–189
    (63, 0, 255),    // 180
    (159, 127, 255), // 181
    (41, 0, 165),    // 182
    (103, 82, 165),  // 183
    (31, 0, 127),    // 184
    (79, 63, 127),   // 185
    (19, 0, 76),     // 186
    (47, 38, 76),    // 187
    (9, 0, 38),      // 188
    (23, 19, 38),    // 189
    // 190–199
    (127, 0, 255),   // 190
    (191, 127, 255), // 191
    (82, 0, 165),    // 192
    (124, 82, 165),  // 193
    (63, 0, 127),    // 194
    (95, 63, 127),   // 195
    (38, 0, 76),     // 196
    (57, 38, 76),    // 197
    (19, 0, 38),     // 198
    (28, 19, 38),    // 199
    // 200–209
    (191, 0, 255),   // 200
    (223, 127, 255), // 201
    (124, 0, 165),   // 202
    (145, 82, 165),  // 203
    (95, 0, 127),    // 204
    (111, 63, 127),  // 205
    (57, 0, 76),     // 206
    (66, 38, 76),    // 207
    (28, 0, 38),     // 208
    (33, 19, 38),    // 209
    // 210–219
    (255, 0, 255),   // 210
    (255, 127, 255), // 211
    (165, 0, 165),   // 212
    (165, 82, 165),  // 213
    (127, 0, 127),   // 214
    (127, 63, 127),  // 215
    (76, 0, 76),     // 216
    (76, 38, 76),    // 217
    (38, 0, 38),     // 218
    (38, 19, 38),    // 219
    // 220–229
    (255, 0, 191),   // 220
    (255, 127, 223), // 221
    (165, 0, 124),   // 222
    (165, 82, 145),  // 223
    (127, 0, 95),    // 224
    (127, 63, 111),  // 225
    (76, 0, 57),     // 226
    (76, 38, 66),    // 227
    (38, 0, 28),     // 228
    (38, 19, 33),    // 229
    // 230–239
    (255, 0, 127),   // 230
    (255, 127, 191), // 231
    (165, 0, 82),    // 232
    (165, 82, 124),  // 233
    (127, 0, 63),    // 234
    (127, 63, 95),   // 235
    (76, 0, 38),     // 236
    (76, 38, 57),    // 237
    (38, 0, 19),     // 238
    (38, 19, 28),    // 239
    // 240–249
    (255, 0, 63),    // 240
    (255, 127, 159), // 241
    (165, 0, 41),    // 242
    (165, 82, 103),  // 243
    (127, 0, 31),    // 244
    (127, 63, 79),   // 245
    (76, 0, 19),     // 246
    (76, 38, 47),    // 247
    (38, 0, 9),      // 248
    (38, 19, 23),    // 249
    // 250–255: grays
    (51, 51, 51),    // 250
    (91, 91, 91),    // 251
    (132, 132, 132), // 252
    (173, 173, 173), // 253
    (214, 214, 214), // 254
    (255, 255, 255), // 255
];

/// Look up the canonical RGB value for an ACI index (1–255).
///
/// Returns `None` for index 0 (ByBlock) or out-of-range values.
#[inline]
pub fn aci_to_rgb(index: u8) -> Option<(u8, u8, u8)> {
    if index == 0 {
        None
    } else {
        Some(ACI_COLORS[index as usize])
    }
}

/// Find the nearest ACI index (1–255) for an arbitrary RGB color.
///
/// Uses Euclidean distance in RGB space. Ties go to the lower index.
pub fn nearest_aci(r: u8, g: u8, b: u8) -> u8 {
    let mut best_idx: u8 = 7;
    let mut best_dist = u32::MAX;

    for i in 1u16..=255 {
        let (cr, cg, cb) = ACI_COLORS[i as usize];
        let dr = (r as i32) - (cr as i32);
        let dg = (g as i32) - (cg as i32);
        let db = (b as i32) - (cb as i32);
        let dist = (dr * dr + dg * dg + db * db) as u32;
        if dist < best_dist {
            best_dist = dist;
            best_idx = i as u8;
            if dist == 0 {
                break;
            }
        }
    }
    best_idx
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn aci_standard_colors() {
        assert_eq!(aci_to_rgb(1), Some((255, 0, 0))); // Red
        assert_eq!(aci_to_rgb(2), Some((255, 255, 0))); // Yellow
        assert_eq!(aci_to_rgb(3), Some((0, 255, 0))); // Green
        assert_eq!(aci_to_rgb(4), Some((0, 255, 255))); // Cyan
        assert_eq!(aci_to_rgb(5), Some((0, 0, 255))); // Blue
        assert_eq!(aci_to_rgb(6), Some((255, 0, 255))); // Magenta
        assert_eq!(aci_to_rgb(7), Some((255, 255, 255))); // White
    }

    #[test]
    fn aci_byblock_returns_none() {
        assert_eq!(aci_to_rgb(0), None);
    }

    #[test]
    fn nearest_aci_exact_match() {
        assert_eq!(nearest_aci(255, 0, 0), 1); // Red
        assert_eq!(nearest_aci(0, 255, 0), 3); // Green
        assert_eq!(nearest_aci(0, 0, 255), 5); // Blue
        assert_eq!(nearest_aci(255, 255, 0), 2); // Yellow
    }

    #[test]
    fn nearest_aci_approximate() {
        // Near-red should map to red (1) or a red shade
        let idx = nearest_aci(250, 5, 5);
        assert_eq!(idx, 1);
    }

    #[test]
    fn table_length() {
        assert_eq!(ACI_COLORS.len(), 256);
    }

    #[test]
    fn grays_are_correct() {
        assert_eq!(aci_to_rgb(8), Some((128, 128, 128))); // Dark gray
        assert_eq!(aci_to_rgb(9), Some((192, 192, 192))); // Light gray
        assert_eq!(aci_to_rgb(250), Some((51, 51, 51)));
        assert_eq!(aci_to_rgb(255), Some((255, 255, 255)));
    }
}