Skip to content

Commit 9005205

Browse files
seto77claude
andcommitted
Add v4.927: ITC Vol.A symmetry diagrams and hex-setting axis fix
- Preserve SeriesNumber through Canonicalize / TryCreateCenteredOperation so ApplyMatrix keeps using hex-basis matrices for trigonal/hexagonal groups (fixes spurious 1/3-IT screws and missing pure 2-folds in R32 and other R-/hex-set space groups). - Add 6-arg SymmetryOperation constructor with default-arg seriesNumber. - Add in-plane 4-fold / -4 axis arrow heads and group drafts by order so cubic in-plane axes coexist correctly with 2/2_1 axes. - Cubic systems get +20px outer margin so in-plane parallelograms do not overflow the cell. - Harden line-cell clipping (TryClipLineThroughUnitCell) against degenerate directions parallel to a cell axis. - Drop trailing x/y/z variable in general-position height labels for non-cubic systems. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent caa4987 commit 9005205

6 files changed

Lines changed: 310 additions & 142 deletions

File tree

Crystallography.Controls/Crystal/SymmetryDiagramCommon.cs

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -141,14 +141,20 @@ protected static CellLayout ComputeCellLayout(Size canvas, Symmetry sym, Project
141141
double cosA = Math.Cos(rad), sinA = Math.Sin(rad);
142142
var (hLen, vLen) = GetCellLengths(sym, projAxis);
143143
// (260502Cl) 上下左右で余白を独立に取る。
144-
float availW = Math.Max(8f, canvas.Width - CellMarginLeft - CellMarginRight);
145-
float availH = Math.Max(8f, canvas.Height - CellMarginTop - CellMarginBottom);
144+
// (260503Cl) 立方晶系では in-plane 4 回軸の平行四辺形などがセル外側に張り出すため、上下左右の余白を +20 加算。
145+
float extra = sym.CrystalSystemNumber == 7 ? 20f : 0f;
146+
float ml = CellMarginLeft + extra;
147+
float mr = CellMarginRight + extra;
148+
float mt = CellMarginTop + extra;
149+
float mb = CellMarginBottom + extra;
150+
float availW = Math.Max(8f, canvas.Width - ml - mr);
151+
float availH = Math.Max(8f, canvas.Height - mt - mb);
146152
double scale = Math.Min(availW / (hLen + Math.Abs(cosA) * vLen), availH / (sinA * vLen));
147153
float horzLen = (float)(hLen * scale), vertLen = (float)(vLen * scale);
148154
float bboxW = (float)((hLen + Math.Abs(cosA) * vLen) * scale);
149155
float bboxH = (float)(sinA * vLen * scale);
150-
float ox = CellMarginLeft + (availW - bboxW) / 2f + (cosA < 0 ? -(float)cosA * vertLen : 0);
151-
float oy = CellMarginTop + (availH - bboxH) / 2f;
156+
float ox = ml + (availW - bboxW) / 2f + (cosA < 0 ? -(float)cosA * vertLen : 0);
157+
float oy = mt + (availH - bboxH) / 2f;
152158
return new(new PointF(ox, oy), new PointF(horzLen, 0f), new PointF((float)cosA * vertLen, (float)sinA * vertLen));
153159
}
154160

@@ -206,25 +212,39 @@ protected static string TZToFraction(double t)
206212
return $"{t:0.00}";
207213
}
208214

209-
/// <summary>(sx,sy) を通り (dSx,dSy) 方向の直線をセル [0,1]² でクリップ。</summary>
210-
protected static (PointF? Start, PointF? End) SpanLineThroughCell(CellLayout c, double sx, double sy, double dSx, double dSy)
215+
/// <summary>(260504Ch) (sx,sy) を通り (dSx,dSy) 方向の直線をセル [0,1]² の媒介変数区間でクリップ。
216+
/// 旧実装はセル外で辺と平行な直線を tMin=1 にするだけで、tMax が無限大のままなら有効扱いになることがあった。</summary>
217+
protected static bool TryClipLineThroughUnitCell(double sx, double sy, double dSx, double dSy,
218+
out double tMin, out double tMax)
211219
{
212-
double tMin = double.NegativeInfinity, tMax = double.PositiveInfinity;
213-
UpdateInterval(sx, dSx, ref tMin, ref tMax);
214-
UpdateInterval(sy, dSy, ref tMin, ref tMax);
215-
if (tMin > tMax) return (null, null);
216-
return (c.ToScreen(sx + tMin * dSx, sy + tMin * dSy), c.ToScreen(sx + tMax * dSx, sy + tMax * dSy));
220+
tMin = double.NegativeInfinity;
221+
tMax = double.PositiveInfinity;
222+
if (Math.Abs(dSx) < 1e-12 && Math.Abs(dSy) < 1e-12) return false; // (260504Ch) 退化方向では ±Infinity*0 に落とさない。
223+
return ClipCoordinate(sx, dSx, ref tMin, ref tMax)
224+
&& ClipCoordinate(sy, dSy, ref tMin, ref tMax)
225+
&& tMin <= tMax + 1e-12;
217226

218-
static void UpdateInterval(double s, double d, ref double tMin, ref double tMax)
227+
static bool ClipCoordinate(double s, double d, ref double tMin, ref double tMax)
219228
{
220-
if (Math.Abs(d) < 1e-9) { if (s < 0 || s > 1) tMin = 1; return; }
229+
const double eps = 1e-9;
230+
if (Math.Abs(d) < eps)
231+
return s >= -eps && s <= 1 + eps;
221232
double t1 = -s / d, t2 = (1 - s) / d;
222233
if (t1 > t2) (t1, t2) = (t2, t1);
223234
if (t1 > tMin) tMin = t1;
224235
if (t2 < tMax) tMax = t2;
236+
return true;
225237
}
226238
}
227239

240+
/// <summary>(sx,sy) を通り (dSx,dSy) 方向の直線をセル [0,1]² でクリップ。</summary>
241+
protected static (PointF? Start, PointF? End) SpanLineThroughCell(CellLayout c, double sx, double sy, double dSx, double dSy)
242+
{
243+
if (!TryClipLineThroughUnitCell(sx, sy, dSx, dSy, out double tMin, out double tMax))
244+
return (null, null);
245+
return (c.ToScreen(sx + tMin * dSx, sy + tMin * dSy), c.ToScreen(sx + tMax * dSx, sy + tMax * dSy));
246+
}
247+
228248
protected static Bitmap NewBitmap(Size size, out Graphics g)
229249
{
230250
var bmp = new Bitmap(Math.Max(size.Width, 16), Math.Max(size.Height, 16));
@@ -242,16 +262,8 @@ protected static bool TryGetSym(int seriesNumber, out Symmetry sym, out int reso
242262
{
243263
sym = default; msg = null; resolvedSeriesNumber = seriesNumber;
244264
if (seriesNumber <= 0 || seriesNumber >= SymmetryStatic.TotalSpaceGroupNumber) return false;
245-
sym = SymmetryStatic.Symmetries[seriesNumber];
246-
if (sym.SpaceGroupHMStr != null && sym.SpaceGroupHMStr.EndsWith("Rho"))
247-
for (int i = 1; i < SymmetryStatic.TotalSpaceGroupNumber; i++)
248-
{
249-
var alt = SymmetryStatic.Symmetries[i];
250-
if (alt.SpaceGroupNumber == sym.SpaceGroupNumber && alt.SpaceGroupHMStr is { } s && s.EndsWith("Hex"))
251-
{
252-
sym = alt; resolvedSeriesNumber = i; break;
253-
}
254-
}
265+
resolvedSeriesNumber = SymmetryElementsTable.ResolveRhoToHex(seriesNumber); // (260504Ch) Rho→Hex 解決を対称要素テーブルと共有。
266+
sym = SymmetryStatic.Symmetries[resolvedSeriesNumber];
255267
if (sym.CrystalSystemNumber is not (1 or 2 or 3 or 4 or 5 or 6 or 7))
256268
{
257269
msg = $"({sym.CrystalSystemStr} not yet supported)";

0 commit comments

Comments
 (0)