Files
Rozpisky/Rozpisky/Rendering/AciPaleta.cs
T
marekandClaude Opus 5 d66aec5299 Barvy: zachovat ACI index a ByLayer po celé cestě DXF → model → DXF
Šablona i všech 9 log jsou zapsané výhradně indexovanými barvami AutoCADu
(group 62) – true color v nich není ani jednou. Kreslicí rozhraní přitom
neslo jen `int rgb`, takže se index i ByLayer ztratily už při čtení a export
zapisoval všechno jako natvrdo RGB (group 420). Výkres v CADu pak přestal
reagovat na tabulku barev a barva hladiny se rozpadla na kopie na entitách.

`IProfileRenderer.Layer(name, rgb, mm)` se mění na `Stav(in KresliciStav)`.
Stav nese barvu i s původem (`Barva`: ACI index / true color / ByLayer /
ByBlock), typ čáry, tloušťku a celý popis hladiny (`HladinaStav`) – hladina
se ve výstupu staví z tabulky hladin, ne z první entity, která na ní
přistála. Rámeček `!!NOPRINT` proto zůstane netisknutelný.

Paleta ACI je vlastní (`AciPaleta`), ne z ACadSharp: ta se od AutoCADu liší
u 33 indexů, mimo jiné u 8 (použitý v šabloně) a u posledního indexu většiny
desítek odstínů, kde vrací barvu ze sousední skupiny – 29 a 39 tam dokonce
dostanou tutéž barvu. Rozsah 10–249 se dopočítává, ne vypisuje.

Co ověřují nové testy (93 zelených):
- paleta proti AutoCADu i proti ACadSharp, se seznamem známých odchylek,
- rozřešení ByLayer/ByBlock, tloušťky a typu čáry,
- kolečko šablona → export → načtení: žádná entita není true color, indexy
  odpovídají zdroji, ByLayer zůstane ByLayer, hladiny mají barvu i příznak
  tisku ze zdrojové tabulky.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 12:13:32 +02:00

99 lines
4.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
namespace Rozpisky.Rendering;
/// <summary>
/// Paleta indexovaných barev AutoCADu (ACI 0255). Index je to, co nese DXF group 62; na RGB se
/// překládá až při rasterizaci (náhled, PNG, PDF) do DXF se zapisuje zpátky jako <b>číslo</b>,
/// takže se cestou tam a zpět nic neztratí.
/// <para>Rozsah 10249 je dopočítaný, ne vypsaný: 24 odstínů po 15° × 5 jasů, každý ve variantě
/// sytá / poloviční sytost. Krajní hodnoty (09, 250255) jsou tabulkou, protože do schématu
/// nezapadají.</para>
/// <para><b>Proč ne <c>ACadSharp.Color.GetIndexRGB</c>:</b> ta se od AutoCADu liší u indexů
/// 8 a 9 (o dva stupně šedi), u 250254 a u posledního indexu každé skupiny odstínů (19, 29, …,
/// 249) tam vrací hodnotu ze sousední skupiny, takže např. 29 a 39 dostanou stejnou barvu.
/// Index 8 je přitom v <c>Rozpiska.dxf</c> použitý. Viz <c>AciPaletaTesty</c>.</para>
/// </summary>
public static class AciPaleta
{
/// <summary>ACI 09. Index 0 (ByBlock) a 7 se kreslí podle pozadí tady černá / bílá.</summary>
private static readonly int[] Zakladni =
{
0x000000, // 0 ByBlock, samostatně se nekreslí
0xFF0000, 0xFFFF00, 0x00FF00, 0x00FFFF, 0x0000FF, 0xFF00FF, 0xFFFFFF,
0x414141, // 8 tmavá šedá (ACadSharp tu má 0x808080)
0x808080, // 9 šedá (ACadSharp tu má 0xC0C0C0)
};
/// <summary>ACI 250255 šedý klín zakončený bílou.</summary>
private static readonly int[] Sede = { 0x333333, 0x505050, 0x696969, 0x828282, 0xBEBEBE, 0xFFFFFF };
/// <summary>Jas pro pozici v desetici: pětice 100 / 65 / 50 / 30 / 15 %, každá dvakrát
/// (sudá pozice = plná sytost, lichá = poloviční).</summary>
private static readonly int[] Jasy = { 0xFF, 0xFF, 0xA5, 0xA5, 0x7F, 0x7F, 0x4C, 0x4C, 0x26, 0x26 };
/// <summary>RGB 0xRRGGBB pro daný ACI index. Mimo rozsah 0255 → černá.</summary>
public static int Rgb(int index)
{
if (index is < 0 or > 255) return 0x000000;
if (index <= 9) return Zakladni[index];
if (index >= 250) return Sede[index - 250];
return Odstin(index);
}
/// <summary>Nejbližší ACI index k RGB (pro cizí soubory zapsané v true color). Prohledává
/// 1255 podle eukleidovské vzdálenosti v RGB hrubé, ale pro převod stačí.</summary>
public static byte NejblizsiIndex(int rgb)
{
int r = (rgb >> 16) & 0xFF, g = (rgb >> 8) & 0xFF, b = rgb & 0xFF;
byte nej = 7;
long nejVzdalenost = long.MaxValue;
for (int i = 1; i <= 255; i++)
{
int c = Rgb(i);
long dr = r - ((c >> 16) & 0xFF), dg = g - ((c >> 8) & 0xFF), db = b - (c & 0xFF);
long d = dr * dr + dg * dg + db * db;
if (d >= nejVzdalenost) continue;
nejVzdalenost = d;
nej = (byte)i;
if (d == 0) break;
}
return nej;
}
/// <summary>Barva odstínové části palety (10249): odstín podle desítky, jas a sytost
/// podle pozice v ní. Lichá pozice = tatáž barva smíchaná do poloviny s jasem
/// (odbarvená), proto <c>c + (jas c) / 2</c>.</summary>
private static int Odstin(int index)
{
int skupina = (index - 10) / 10; // 023 → úhel odstínu 0°, 15°, … 345°
int pozice = (index - 10) % 10; // 09 → jas a sytost
int jas = Jasy[pozice];
var (r, g, b) = Hsv(skupina * 15.0, jas);
if ((pozice & 1) == 1)
{
r += (jas - r) / 2;
g += (jas - g) / 2;
b += (jas - b) / 2;
}
return (r << 16) | (g << 8) | b;
}
/// <summary>Plně sytá barva daného odstínu a jasu (HSV se saturací 1). Dělení na šestiny
/// kruhu; v každé roste jeden kanál a klesá jiný. Ořezává se dolů, jako to dělá AutoCAD.</summary>
private static (int R, int G, int B) Hsv(double uhelDeg, int jas)
{
int sestina = (int)(uhelDeg / 60);
double podil = uhelDeg / 60 - sestina;
int rostouci = (int)(jas * podil);
int klesajici = (int)(jas * (1 - podil));
return sestina switch
{
0 => (jas, rostouci, 0),
1 => (klesajici, jas, 0),
2 => (0, jas, rostouci),
3 => (0, klesajici, jas),
4 => (rostouci, 0, jas),
_ => (jas, 0, klesajici),
};
}
}