diff --git a/Disp/DemoCylindroid.cs b/Disp/DemoCylindroid.cs
new file mode 100644
index 0000000..8d843b3
--- /dev/null
+++ b/Disp/DemoCylindroid.cs
@@ -0,0 +1,53 @@
+using Hi.Disp;
+using Hi.Geom;
+using System;
+
+namespace Sample.Disp
+{
+ ///
+ /// Demonstrates the creation and visualization of objects.
+ /// Includes examples of building a programmatically with
+ /// points and serializing/deserializing via XML.
+ ///
+ ///
+ /// ### Source Code
+ /// [!code-csharp[SampleCode](~/../Hi.Sample/Disp/DemoCylindroid.cs)]
+ ///
+ public static class DemoCylindroid
+ {
+ internal static void BuildCylindorid()
+ {
+ Cylindroid cylindroid = new Cylindroid(
+ new PairZr(0, 1),
+ new PairZr(1, 1),
+ new PairZr(1, 2),
+ new PairZr(2, 2),
+ new PairZr(8, 3));
+
+ DispEngine.Init();
+ DemoUtil.Present("BuildCylindorid", cylindroid.ToFaceDrawing());
+ }
+
+ internal static void TestCylindoridXml()
+ {
+ Cylindroid cylindroid = new Cylindroid(
+ new PairZr(0, 1),
+ new PairZr(1, 1),
+ new PairZr(1, 2),
+ new PairZr(2, 2),
+ new PairZr(4, 3));
+ var xmlElement = cylindroid.MakeXmlSource(null, null, true);
+ Console.WriteLine("XML:" + xmlElement);
+
+ cylindroid = new Cylindroid(xmlElement);
+ DispEngine.Init();
+ DemoUtil.Present("BuildCylindorid", cylindroid.ToFaceDrawing());
+ }
+
+ static void Main()
+ {
+ BuildCylindorid();
+ //TestCylindoridXml();
+ }
+ }
+}
diff --git a/Disp/DemoDiscreteRgb.cs b/Disp/DemoDiscreteRgb.cs
new file mode 100644
index 0000000..7ed8b02
--- /dev/null
+++ b/Disp/DemoDiscreteRgb.cs
@@ -0,0 +1,45 @@
+using Hi.Disp;
+using Hi.Disp.Flag;
+using Hi.Geom;
+using Hi.Coloring;
+
+namespace Sample.Disp
+{
+ ///
+ /// Demonstrates the use of discrete RGB colors for rendering multiple objects.
+ /// Shows how to apply different colors to similar geometric shapes using the
+ /// method from class.
+ ///
+ ///
+ /// ### Source Code
+ /// [!code-csharp[SampleCode](~/../Hi.Sample/Disp/DemoDiscreteRgb.cs)]
+ ///
+ public class DemoDiscreteRgb : IDisplayee
+ {
+ ///
+ public void Display(Bind bind)
+ {
+ bind.Rgb = ColorUtil.GetDiscreteRGB_Env();
+ new Box3d(0, 0, 0, 1, 1, 1).ToDraw_Face().Display(bind);
+
+ bind.Rgb = ColorUtil.GetDiscreteRGB_Env();
+ new Box3d(1, 0, 0, 2, 1, 1).ToDraw_Face().Display(bind);
+
+ bind.Rgb = ColorUtil.GetDiscreteRGB_Env();
+ new Box3d(2, 0, 0, 3, 1, 1).ToDraw_Face().Display(bind);
+ }
+ ///
+ public void ExpandToBox3d(Box3d dst)
+ {
+ dst.Expand(new Vec3d(0, 0, 0));
+ dst.Expand(new Vec3d(3, 1, 1));
+ }
+
+ static void Main()
+ {
+ DemoUtil.Present("Demo Discrete I",
+ new DispList(new CoordinateDrawing(), new DemoDiscreteRgb()));
+ }
+
+ }
+}
diff --git a/Disp/DemoDrawing.cs b/Disp/DemoDrawing.cs
new file mode 100644
index 0000000..e2f1f34
--- /dev/null
+++ b/Disp/DemoDrawing.cs
@@ -0,0 +1,201 @@
+using Hi.Geom;
+using Hi.Disp;
+using System.Collections.Generic;
+using Hi.Disp.Treat;
+using Hi.Coloring;
+
+namespace Sample.Disp
+{
+ ///
+ /// Demonstrates various drawing techniques using the HiAPI graphics system.
+ /// Provides examples of primitive drawing, attribute specification, and rendering options.
+ /// Includes methods for drawing lines, points, triangles, and other geometric primitives.
+ ///
+ ///
+ /// ### Source Code
+ /// [!code-csharp[SampleCode](~/../Hi.Sample/Disp/DemoDrawing.cs)]
+ ///
+ public static class DemoDrawing
+ {
+ ///
+ /// Demonstrates simple line drawing using raw vertex coordinates.
+ /// Creates a basic line strip from three vertices and displays it using DemoUtil.
+ ///
+ public static void FreeDrawing()
+ {
+ #region DocSite.FreeDrawing
+ double[] vs =
+ {0,0,0
+ ,1,0,0
+ ,0,0,1};
+ DemoUtil.Present("EasyDraw"
+ , new Drawing(vs, Stamp.V, GL.GL_LINE_STRIP));
+ #endregion
+ }
+
+ ///
+ /// Demonstrates various types of line drawing techniques.
+ /// Shows how to create points, line strips, line strips with normals, and colored line strips.
+ /// Illustrates different ways to specify vertex attributes like position, color, and normal.
+ ///
+ public static void DrawLines()
+ {
+ List ps;
+ double[] vs;
+ int n = 10; //vertex num
+
+ ////create drawPoints
+ ps = new List(n);
+ for (int i = 0; i < n; i++)
+ ps.Add(new Vec3d(i, 0, 0));
+ vs = new double[ps.Count * 3];
+ for (int i = 0; i < ps.Count; i++)
+ {
+ vs[3 * i] = ps[i].x;
+ vs[3 * i + 1] = ps[i].y;
+ vs[3 * i + 2] = ps[i].z;
+ }
+
+ //V means Vertex
+ Drawing drawPoints = new Drawing(vs, Stamp.V, GL.GL_POINTS);
+
+ ////create drawLineStrip
+ vs = new double[ps.Count * 3];
+ for (int i = 0; i < ps.Count; i++)
+ {
+ vs[3 * i] = i;
+ vs[3 * i + 1] = 0;
+ vs[3 * i + 2] = 1;
+ }
+ Drawing drawLineStrip = new Drawing(vs, Stamp.V, GL.GL_LINE_STRIP);
+
+ ////create drawLineStripWithNormal
+ //the content of vs is Nx,Ny,Nz,Vx,Vy,Vz, Nx,Ny,Nz,Vx,Vy,Vz, ...
+ vs = new double[n * 6];
+ for (int i = 0; i < n; i++)
+ {
+ //nx,ny,nz
+ vs[6 * i] = 1;
+ vs[6 * i + 1] = 0;
+ vs[6 * i + 2] = 0;
+ //x,y,z
+ vs[6 * i + 3] = i;
+ vs[6 * i + 4] = 0;
+ vs[6 * i + 5] = 2;
+ }
+ //V means Vertex; N means Normal
+ Drawing drawLineStripWithNormal =
+ new Drawing(vs, Stamp.NV, GL.GL_LINE_STRIP);
+
+ ////create drawColorLines
+ vs = new double[n * 6];
+ for (int i = 0; i < n; i++)
+ {
+ //the rgb values set casually.
+ //r,g,b
+ vs[6 * i] = i % 3 / 2D;
+ vs[6 * i + 1] = i % 5 / 4D;
+ vs[6 * i + 2] = i % 7 / 6D;
+ //x,y,z
+ vs[6 * i + 3] = i;
+ vs[6 * i + 4] = 0;
+ vs[6 * i + 5] = 3;
+ }
+ //V means Vertex; C means Color
+ Drawing drawLineStripWithColor = new Drawing(vs, Stamp.CV, GL.GL_LINE_STRIP);
+
+ DemoUtil.Present("DrawLines",
+ new DispList(drawPoints, drawLineStrip
+ , drawLineStripWithNormal, drawLineStripWithColor));
+ }
+
+ ///
+ /// Demonstrates drawing triangles using OpenGL primitives.
+ /// Shows how to create colored triangles (CV) and colored triangles with normals (CNV).
+ /// Illustrates packing of vertex attributes (color, normal, position) into arrays for rendering.
+ ///
+ public static void DrawTrianglesByPrimitives()
+ {
+ int n = 10;// triangle num
+ double[] vs;
+
+ ////create drawTrisCV
+ //each triangle has 3 point; each point has r,g,b,x,y,z, totally 6 doubles.
+ vs = new double[n * 3 * 6];
+ for (int i = 0, k = 0; i < n; i++)
+ {
+ //the rgb values set as casual.
+ Vec3d rgb = ColorUtil.GetDiscreteRgb(i);
+ Tri3d tri = new Tri3d(new Vec3d(i, 0, 0), new Vec3d(i + 1, 0, 0), new Vec3d(i + 0.5, 0, 1));
+ for (int j = 0; j < 3; j++)
+ {
+ vs[k++] = rgb.x;
+ vs[k++] = rgb.y;
+ vs[k++] = rgb.z;
+ vs[k++] = tri.ps[j].x;
+ vs[k++] = tri.ps[j].y;
+ vs[k++] = tri.ps[j].z;
+ }
+ }
+ //V means Vertex; C means Color
+ Drawing drawTrisCV = new Drawing(vs, Stamp.CV, GL.GL_TRIANGLES);
+
+ ////create drawTrisCNV
+ /////each triangle has 3 point; each point has r,g,b,nx,ny,nz,x,y,z, totally 6 doubles.
+ vs = new double[n * 3 * 9];
+ for (int i = 0, k = 0; i < n; i++)
+ {
+ //the rgb values set as casual.
+ Vec3d rgb = ColorUtil.GetDiscreteRgb(i);
+ Tri3d tri = new Tri3d(new Vec3d(i, 0, 3), new Vec3d(i + 1, 0, 3), new Vec3d(i + 0.5, 0, 4));
+ Vec3d nn = tri.GetNormal();
+ for (int j = 0; j < 3; j++)
+ {
+ vs[k++] = rgb.x;
+ vs[k++] = rgb.y;
+ vs[k++] = rgb.z;
+ vs[k++] = nn.x;
+ vs[k++] = nn.y;
+ vs[k++] = nn.z;
+ vs[k++] = tri.ps[j].x;
+ vs[k++] = tri.ps[j].y;
+ vs[k++] = tri.ps[j].z;
+ }
+ }
+ //V means Vertex; C means Color; N means Normal
+ Drawing drawTrisCNV = new Drawing(vs, Stamp.CNV, GL.GL_TRIANGLES);
+
+ //the color of colorTrisDraw is not influence by outer color setting.
+ DemoUtil.Present("DrawTrianglesByPrimitives",
+ new DispList(new RgbTreat(1, 0, 0), drawTrisCV, drawTrisCNV));
+ }
+
+ ///
+ /// Demonstrates drawing 3D triangles using the Tri3d helper class.
+ /// Creates a series of triangles and renders them as both face (filled) and line (wireframe) drawings.
+ /// Shows how to apply different colors to faces and lines of the same geometry.
+ ///
+ public static void DrawTri3d()
+ {
+ int n = 10;
+ List tris = new List(n);
+ for (int i = 0; i < n; i++)
+ tris.Add(new Tri3d(new Vec3d(i, 0, 0), new Vec3d(i + 1, 0, 0), new Vec3d(i + 0.5, 0, 1)));
+
+ Drawing faceDraw = tris.GetFaceDrawing();
+ Drawing linesDraw = tris.ToLineDrawing();
+
+ DemoUtil.Present("DrawTri3d",
+ new DispList(new RgbTreat(0, 0, 1), linesDraw
+ , new RgbTreat(1, 0, 0), faceDraw));
+ }
+
+ static void Main()
+ {
+ //FreeDrawing();
+ //DrawLines();
+ //DrawTrianglesByPrimitives();
+ DrawTri3d();
+ }
+ }
+}
diff --git a/Disp/DemoPick1.cs b/Disp/DemoPick1.cs
new file mode 100644
index 0000000..daa5789
--- /dev/null
+++ b/Disp/DemoPick1.cs
@@ -0,0 +1,52 @@
+using Hi.Geom;
+using Hi.Disp;
+using Hi.Native;
+
+namespace Sample.Disp
+{
+ ///
+ /// Demonstrates basic object picking with mouse interaction in the HiAPI system.
+ /// Shows how to create a pickable 3D object that responds to mouse events by changing its appearance.
+ /// Implements the Pickable base class to enable mouse event handling.
+ ///
+ ///
+ /// ### Source Code
+ /// [!code-csharp[SampleCode](~/../Hi.Sample/Disp/DemoPick1.cs)]
+ ///
+ public class DemoPick1 : Pickable, IDisplayee
+ {
+ bool isMouseOver = false;
+ ///
+ public void Display(Bind bind)
+ {
+ bind.PickID = PickingID;
+ bind.Rgb = new Vec3d(isMouseOver ? 0 : 1, 1, 1);
+ new Box3d(0, 0, 0, 1, 1, 1).DisplayFace(bind);
+ bind.PickID = 0;
+ }
+ ///
+ public void ExpandToBox3d(Box3d dst)
+ {
+ dst.Expand(new Vec3d(0, 0, 0));
+ dst.Expand(new Vec3d(1, 1, 1));
+ }
+ ///
+ public override void OnMouseEnter(ui_event_type e, DispEngine dispEngine)
+ {
+ isMouseOver = true;
+ }
+ ///
+ public override void OnMouseLeave(ui_event_type e, DispEngine dispEngine)
+ {
+ isMouseOver = false;
+ }
+ ///
+ /// Entry point for the DemoPick1 example.
+ /// Creates and displays a simple pickable object that changes color on mouse hover.
+ ///
+ static void Main()
+ {
+ DemoUtil.Present("DemoPick1", new DemoPick1());
+ }
+ }
+}
diff --git a/Disp/DemoPick2.cs b/Disp/DemoPick2.cs
new file mode 100644
index 0000000..f969a8d
--- /dev/null
+++ b/Disp/DemoPick2.cs
@@ -0,0 +1,78 @@
+using Hi.Geom;
+using Hi.Disp;
+using System;
+using Hi.Coloring;
+
+namespace Sample.Disp
+{
+ ///
+ /// Demonstrates advanced object picking with multiple pickable objects.
+ /// Shows how to create and manage multiple pickable objects with different visual appearances.
+ /// Implements proper resource cleanup through the IDisposable interface.
+ ///
+ ///
+ /// ### Source Code
+ /// [!code-csharp[SampleCode](~/../Hi.Sample/Disp/DemoPick2.cs)]
+ ///
+ public class DemoPick2 : IDisplayee, IDisposable
+ {
+ readonly Pickable pickableA = new ShowEventPickable { Tag = "A" };
+ readonly Pickable pickableB = new ShowEventPickable { Tag = "B" };
+ readonly Pickable pickableC = new ShowEventPickable { Tag = "C" };
+ ///
+ public void Display(Bind bind)
+ {
+ bind.PickID = pickableA.PickingID;
+ bind.Rgb = ColorUtil.GetDiscreteRgb(1);
+ new Box3d(0, 0, 0, 1, 1, 1).DisplayFace(bind);
+
+ bind.PickID = pickableB.PickingID;
+ bind.Rgb = ColorUtil.GetDiscreteRgb(2);
+ new Box3d(0, 0, 1, 1, 1, 2).DisplayFace(bind);
+
+ bind.PickID = pickableC.PickingID;
+ bind.Rgb = ColorUtil.GetDiscreteRgb(3);
+ new Box3d(0, 0, 2, 1, 1, 3).DisplayFace(bind);
+
+ bind.PickID = 0;
+ }
+ ///
+ public void ExpandToBox3d(Box3d dst)
+ {
+ dst.Expand(new Vec3d(0, 0, 0));
+ dst.Expand(new Vec3d(1, 1, 3));
+ }
+ #region IDisposable Support
+ private bool disposedValue = false; // To detect redundant calls
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!disposedValue)
+ {
+ if (disposing)
+ {
+ pickableA.Dispose();
+ pickableB.Dispose();
+ pickableC.Dispose();
+ }
+ disposedValue = true;
+ }
+ }
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+ #endregion
+
+ ///
+ /// Entry point for the DemoPick2 example.
+ /// Creates and displays multiple pickable objects with distinct colors and positions.
+ /// Demonstrates separation of picking behavior from visual representation.
+ ///
+ static void Main()
+ {
+ DemoUtil.Present("DemoPick2", new DemoPick2());
+ }
+ }
+}
diff --git a/Disp/DemoPickable.cs b/Disp/DemoPickable.cs
new file mode 100644
index 0000000..8f70df4
--- /dev/null
+++ b/Disp/DemoPickable.cs
@@ -0,0 +1,58 @@
+using Hi.Disp;
+using Hi.Geom;
+using System;
+
+namespace Sample.Disp;
+
+///
+/// Demonstrates creation of pickable 3D geometry at the primitive level.
+/// Shows how to assign picking IDs directly to geometry vertices and create interactive triangles.
+/// Uses a lower-level approach than the Pickable base class for more precise control.
+///
+///
+/// ### Source Code
+/// [!code-csharp[SampleCode](~/../Hi.Sample/Disp/DemoPickable.cs)]
+///
+public class DemoPickable : IDisplayee
+{
+ private readonly Drawing draw;
+ private readonly ShowEventPickable pickable;
+
+ ///
+ /// Initializes a new instance of DemoPickable.
+ /// Creates a pickable triangle with a specific picking ID for user interaction.
+ ///
+ public DemoPickable()
+ {
+ pickable = new ShowEventPickable();
+ double pid = pickable.PickingID;
+ double[] vs = new double[] {
+ //pickID, x,y,z
+ pid, 0,0.1,0.1,
+ pid, 0.1,0,0,
+ pid, 0.1,0,0.1
+ };
+ draw = new Drawing(vs, Stamp.PV, GL.GL_TRIANGLES);
+ }
+ ///
+ public void Display(Bind bind)
+ {
+ draw.Display(bind);
+ }
+ ///
+ public void ExpandToBox3d(Box3d dst)
+ {
+ draw.ExpandToBox3d(dst);
+ }
+
+ ///
+ /// Entry point for the DemoPickable example.
+ /// Creates and displays a pickable triangle that can respond to mouse events.
+ /// Demonstrates integration of picking functionality with geometric primitives.
+ ///
+ [STAThread]
+ public static void Main()
+ {
+ DemoUtil.Present("DemoPickable", new DemoPickable());
+ }
+}
diff --git a/Disp/DemoSatellite.cs b/Disp/DemoSatellite.cs
new file mode 100644
index 0000000..e72b7a1
--- /dev/null
+++ b/Disp/DemoSatellite.cs
@@ -0,0 +1,55 @@
+using Hi.Geom;
+using Hi.Disp;
+
+namespace Sample.Disp
+{
+ ///
+ /// Demonstrates a simple solar system animation using interface.
+ /// Shows how to create a hierarchical transform structure with sun, earth and moon using
+ /// matrices and model matrix stack transformations.
+ ///
+ ///
+ /// ### Source Code
+ /// [!code-csharp[SampleCode](~/../Hi.Sample/Disp/DemoSatellite.cs)]
+ ///
+ public class DemoSatellite : IDisplayee
+ {
+ Drawing sun;
+ Drawing earth;
+ Drawing moon;
+ double angle_earth;
+ double angle_moon;
+ DemoSatellite()
+ {
+ sun = Box3d.CenterUnitBox.ScaleFromCenter(4).ToDraw_Face();
+ earth = Box3d.CenterUnitBox.ScaleFromCenter(2).ToDraw_Face();
+ moon = Box3d.CenterUnitBox.ToDraw_Face();
+ }
+ ///
+ public void Display(Bind bind)
+ {
+ sun.Display(bind);
+ bind.ModelMatStack.Push();
+ bind.ModelMatStack.Mul(new Mat4d(new AxisAngle4d(new Vec3d(0, 0, 1), angle_earth += 0.03)));
+ bind.ModelMatStack.Mul(new Mat4d(new Vec3d(12, 0, 0)));
+ earth.Display(bind);
+ bind.ModelMatStack.Push();
+ bind.ModelMatStack.Mul(new Mat4d(new AxisAngle4d(new Vec3d(0, 0, 1), angle_moon += 0.02)));
+ bind.ModelMatStack.Mul(new Mat4d(new Vec3d(4, 0, 0)));
+ moon.Display(bind);
+ bind.ModelMatStack.Pop();
+ bind.ModelMatStack.Pop();
+ }
+ ///
+ public void ExpandToBox3d(Box3d dst)
+ {
+ dst.Expand(new Vec3d(-14, -14, -2));
+ dst.Expand(new Vec3d(14, 14, 2));
+ }
+
+ static void Main()
+ {
+ DemoUtil.Present("DemoSatellite", new DemoSatellite());
+ }
+ }
+}
diff --git a/Disp/DemoUtil.cs b/Disp/DemoUtil.cs
new file mode 100644
index 0000000..46c23c4
--- /dev/null
+++ b/Disp/DemoUtil.cs
@@ -0,0 +1,45 @@
+using Hi.Disp;
+using Hi.Geom;
+using Hi.HiNcKits;
+using Microsoft.Extensions.Logging;
+using System;
+
+namespace Sample.Disp;
+
+///
+/// Runs a display sample to the point where its is ready to be rendered.
+/// HiAPI ships no rendering canvas, so the samples in this project stop at the handover: they
+/// compose the displayee and report it, and the application hands that same object to a canvas of
+/// its own. See the Building Your Own Rendering Canvas guide for the canvas side.
+///
+///
+/// ### Source Code
+/// [!code-csharp[SampleCode](~/../Hi.Sample/Disp/DemoUtil.cs)]
+///
+public static class DemoUtil
+{
+ ///
+ /// Initializes the application, reports the displayee's extent, and shuts down again —
+ /// the headless equivalent of opening a window on it.
+ ///
+ /// A name for the sample, used in the console output.
+ /// The object a rendering canvas would display.
+ public static void Present(string title, IDisplayee displayee)
+ {
+ if (displayee is null) throw new ArgumentNullException(nameof(displayee));
+
+ using var loggerFactory = LoggerFactory.Create(b => b.AddConsole());
+ LocalApp.AppBegin(loggerFactory.CreateLogger("Hi.Sample"));
+ try
+ {
+ Box3d box = new Box3d();
+ displayee.ExpandToBox3d(box);
+ Console.WriteLine($"{title}: {displayee.GetType().Name} bounding {box}");
+ Console.WriteLine("Assign it to your canvas' DispEngine.Displayee to see it.");
+ }
+ finally
+ {
+ LocalApp.AppEnd();
+ }
+ }
+}
diff --git a/Disp/HeidenhainCoordinateEntryDisplayee.cs b/Disp/HeidenhainCoordinateEntryDisplayee.cs
new file mode 100644
index 0000000..7e747b1
--- /dev/null
+++ b/Disp/HeidenhainCoordinateEntryDisplayee.cs
@@ -0,0 +1,119 @@
+using Hi.Disp.Flag;
+using Hi.Disp;
+using Hi.Machining.MachiningEquipmentUtils;
+using Hi.Mech.Topo;
+using Hi.Numerical;
+using Hi.Numerical.NcArgs;
+using System.Collections;
+using System;
+using Hi.Geom;
+using System.Linq;
+
+namespace Sample.Disp
+{
+ ///
+ /// Displayee for Heidenhain coordinate entry visualization.
+ ///
+ public class HeidenhainCoordinateEntryDisplayee : IAnchoredDisplayee
+ {
+ ///
+ /// Gets or sets whether to show Heidenhain datum preset information.
+ ///
+ public bool ShowHeidenhainDatumPreset { get; set; } = true;
+ ///
+ /// Gets or sets whether to show Heidenhain datum shift information.
+ ///
+ public bool ShowHeidenhainDatumShift { get; set; } = true;
+ ///
+ /// Gets or sets the function that provides the NcEnv instance.
+ ///
+ public Func NcEnvFunc { get; set; }
+ ///
+ /// Gets or sets the function that provides the machining equipment.
+ ///
+ public Func MillingEquipmentFunc { get; set; }
+ HardNcEnv NcEnv => NcEnvFunc?.Invoke();
+ ///
+ /// Gets or sets the Heidenhain Cycle Def 247 Q339 value.
+ ///
+ public int HeidenhainCycleDef247Q339 { get; set; }
+ ///
+ /// Gets or sets the Heidenhain Cycle Def 7 arguments.
+ ///
+ public HeidenhainCycleDef7Arg HeidenhainCycleDef7Arg { get; set; }
+
+ ///
+ /// Initializes a new instance.
+ ///
+ /// The function that provides the NcEnv instance.
+ /// The function that provides the machining equipment.
+ public HeidenhainCoordinateEntryDisplayee(Func ncEnvFunc, Func millingEquipmentSource)
+ {
+ NcEnvFunc = ncEnvFunc;
+ MillingEquipmentFunc = millingEquipmentSource;
+ }
+ ///
+ public void Display(Bind bind)
+ {
+ HardNcEnv ncEnv = NcEnv;
+ if (ncEnv == null || NcEnv.CncBrand != CncBrand.Heidenhain)
+ return;
+
+ ////Console.WriteLine($"B: {CoordinateIndex}; {coordinateMove}");
+ Vec3d mcXyz_AttacherAtTableBuckleZero = MillingEquipmentFunc?.Invoke()
+ ?.GetMachinePositionAtTableBuckleZero();
+ if (mcXyz_AttacherAtTableBuckleZero == null)
+ return;
+
+ Vec3d coordinateMove;
+ string text;
+ if (HeidenhainCycleDef247Q339 == 0 && HeidenhainCycleDef7Arg == null)
+ return;
+ coordinateMove = NcFlagUtil.GetHeidenhainCoordinateOffset(
+ HeidenhainCycleDef247Q339, HeidenhainCycleDef7Arg, ncEnv);
+ //Console.WriteLine($"HeidenhainCycleDef7Arg: {HeidenhainCycleDef7Arg==null}");
+ string datumPresetText = null;
+ if (HeidenhainCycleDef247Q339 != 0 && ShowHeidenhainDatumPreset)
+ datumPresetText = $"Datum Preset Q339={HeidenhainCycleDef247Q339}";
+ string datumShiftText = null;
+ if (HeidenhainCycleDef7Arg != null && ShowHeidenhainDatumShift)
+ datumShiftText = $"Datum Shift: {HeidenhainCycleDef7Arg?.ToString() ?? "None"}";
+ text = string.Join(", ",
+ (new string[] { datumPresetText, datumShiftText }).
+ Where(v => v != null));
+ //text = $"Datum Preset Q339={HeidenhainCycleDef247Q339}, Datum Shift: #1";
+ //Console.WriteLine($"text: [{text}]");
+
+ bind.ModelMatStack.Push();
+ bind.ModelMatStack.Trans(coordinateMove - mcXyz_AttacherAtTableBuckleZero);
+ CoordinateDrawing.Display(bind, text);
+ bind.ModelMatStack.Pop();
+ }
+ ///
+ public void ExpandToBox3d(Box3d dst)
+ {
+ HardNcEnv ncEnv = NcEnv;
+ if (ncEnv == null || NcEnv.CncBrand != CncBrand.Heidenhain)
+ return;
+
+ Vec3d mcXyz_AttacherAtTableBuckleZero = MillingEquipmentFunc?.Invoke()
+ ?.GetMachinePositionAtTableBuckleZero();
+ if (mcXyz_AttacherAtTableBuckleZero == null)
+ return;
+ Vec3d coordinateMove;
+ if (HeidenhainCycleDef247Q339 == 0 && HeidenhainCycleDef7Arg == null)
+ return;
+ coordinateMove = NcFlagUtil.GetHeidenhainCoordinateOffset(
+ HeidenhainCycleDef247Q339, HeidenhainCycleDef7Arg, ncEnv);
+
+
+ dst.Expand(-mcXyz_AttacherAtTableBuckleZero + coordinateMove);
+ }
+ ///
+ public Anchor GetAnchor()
+ {
+ return MillingEquipmentFunc?.Invoke()?.GetMachiningChain()
+ ?.GetTableBuckle()?.GetAnchor();
+ }
+ }
+}
diff --git a/Disp/IsoCoordinateEntryDisplayee.cs b/Disp/IsoCoordinateEntryDisplayee.cs
new file mode 100644
index 0000000..b1d6bf4
--- /dev/null
+++ b/Disp/IsoCoordinateEntryDisplayee.cs
@@ -0,0 +1,90 @@
+using Hi.Disp;
+using Hi.Disp.Flag;
+using Hi.Geom;
+using Hi.Machining.MachiningEquipmentUtils;
+using Hi.Mech.Topo;
+using Hi.Numerical;
+using System;
+
+namespace Sample.Disp;
+
+///
+/// Displayee for ISO coordinate entry visualization.
+///
+public class IsoCoordinateEntryDisplayee : IAnchoredDisplayee
+{
+ ///
+ /// Gets or sets the ISO coordinate key (e.g. "G54", "G59.2").
+ ///
+ public string IsoCoordinateId { get; set; } = "G54";
+ ///
+ /// Gets or sets the function that provides the NcEnv instance.
+ ///
+ public Func NcEnvFunc { get; set; }
+
+ ///
+ /// Gets or sets the function that provides the machining equipment.
+ ///
+ public Func MillingEquipmentFunc { get; set; }
+ HardNcEnv NcEnv => NcEnvFunc?.Invoke();
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The function that provides the NcEnv instance.
+ /// The function that provides the machining equipment.
+ public IsoCoordinateEntryDisplayee(Func ncEnvFunc,
+ Func millingEquipmentSource)
+ {
+ NcEnvFunc = ncEnvFunc;
+ MillingEquipmentFunc = millingEquipmentSource;
+ }
+ ///
+ public void Display(Bind bind)
+ {
+ HardNcEnv ncEnv = NcEnv;
+ if (ncEnv == null)
+ return;
+
+ Vec3d coordinateMove;
+ string text;
+
+ if (ncEnv.IsoCoordinateTable?.TryGetValue(
+ IsoCoordinateId, out coordinateMove) != true
+ || coordinateMove == null)
+ return;
+ if (coordinateMove == null)
+ return;
+ text = IsoCoordinateId ?? "";
+
+ Vec3d attacherPos = MillingEquipmentFunc?.Invoke()
+ ?.GetIsoCoordinatePosition(coordinateMove);
+
+ bind.ModelMatStack.Push();
+ bind.ModelMatStack.Trans(attacherPos);
+ CoordinateDrawing.Display(bind, text);
+ bind.ModelMatStack.Pop();
+ }
+ ///
+ public void ExpandToBox3d(Box3d dst)
+ {
+ HardNcEnv ncEnv = NcEnv;
+ if (ncEnv == null)
+ return;
+ Vec3d coordinateMove;
+ if (ncEnv.IsoCoordinateTable?.TryGetValue(IsoCoordinateId, out coordinateMove) != true
+ || coordinateMove == null)
+ return;
+
+ Vec3d attacherPos = MillingEquipmentFunc?.Invoke()
+ ?.GetIsoCoordinatePosition(coordinateMove);
+ if (attacherPos == null)
+ return;
+ dst.Expand(attacherPos);
+ }
+ ///
+ /// Table Buckle if existed; otherwise, return null.
+ public Anchor GetAnchor()
+ {
+ return MillingEquipmentFunc?.Invoke()?.GetMachiningChain()?.GetAnchor();
+ }
+}
diff --git a/Disp/MachiningProjectDisplayee.cs b/Disp/MachiningProjectDisplayee.cs
new file mode 100644
index 0000000..a5805a2
--- /dev/null
+++ b/Disp/MachiningProjectDisplayee.cs
@@ -0,0 +1,250 @@
+using Hi.Coloring;
+using Hi.MachiningProcs;
+using Hi.Common;
+using Hi.Disp;
+using Hi.Disp.Flag;
+using Hi.Mech.Topo;
+using System.Collections.Generic;
+using System.Collections;
+using Hi.Geom;
+using System.Linq;
+using Hi.NcMech.Solids;
+using Hi.Numerical;
+using System;
+
+namespace Sample.Disp;
+
+///
+/// Represents a displayable wrapper for a machining project.
+///
+public class MachiningProjectDisplayee : IDisplayee, IGetAnchor
+{
+ ///
+ /// Gets the current milling course from the host function.
+ ///
+ public MachiningProject MachiningProject => LocalProjectService.MachiningProject;
+ ///
+ /// Gets or sets the function that provides the machining project.
+ ///
+ public LocalProjectService LocalProjectService { get; set; }
+
+ /////
+ ///// Initializes a new instance of the class.
+ /////
+ ///// The machining project to display.
+ ///// The bit array controlling rendering flags.
+ //public MachiningProjectDisplayee(MachiningProject machiningProject,
+ // BitArray renderingFlagBitArray)
+ // {
+ // RenderingFlagBitArray = renderingFlagBitArray;
+ // }
+
+ ///
+ /// Initializes a new instance of the class with default rendering flags.
+ ///
+ public MachiningProjectDisplayee(LocalProjectService localProjectService)
+ { LocalProjectService = localProjectService; }
+
+ ///
+ /// Gets or sets the bit array that controls which elements are rendered.
+ ///
+ public BitArray RenderingFlagBitArray { get; set; } = new BitArray(EnumUtil.GetEnumBitArrayCap())
+ {
+ [(int)RenderingFlag.DimensionBar] = true,
+ [(int)RenderingFlag.WorkpieceGeom] = true,
+ [(int)RenderingFlag.Fixture] = true,
+ [(int)RenderingFlag.ClStrip] = true,
+ //[(int)RenderingFlag.Mech] = true,
+ };
+ IsoCoordinateEntryDisplayee isoCoordinateEntryDisplayee;
+ ///
+ /// Gets the ISO coordinate entry displayee for ISO-based coordinate systems.
+ ///
+ public IsoCoordinateEntryDisplayee IsoCoordinateEntryDisplayee =>
+ isoCoordinateEntryDisplayee ??= new IsoCoordinateEntryDisplayee(
+ () => MachiningProject.NcEnv,
+ () => LocalProjectService.MachiningEquipment);
+ HeidenhainCoordinateEntryDisplayee heidenhainCoordinateEntryDisplayee;
+ ///
+ /// Gets the Heidenhain coordinate entry displayee for Heidenhain-based coordinate systems.
+ ///
+ public HeidenhainCoordinateEntryDisplayee HeidenhainCoordinateEntryDisplayee =>
+ heidenhainCoordinateEntryDisplayee ??= new HeidenhainCoordinateEntryDisplayee(
+ () => MachiningProject.NcEnv,
+ () => LocalProjectService.MachiningEquipment);
+
+ ///
+ /// Gets a list of anchored displayees based on current rendering flags.
+ ///
+ /// A list of anchored displayees for rendering
+ List GetAnchoredDisplayeeList()
+ {
+ List dst = new List();
+ MachiningProject machiningProject = MachiningProject;
+ if (machiningProject == null)
+ return dst;
+
+ LocalProjectService localProjectService = LocalProjectService;
+ HardNcEnv ncEnv = machiningProject.NcEnv;
+ //the execution scene draws the RUNTIME face throughout (equipment
+ //split: the service facades expose the authored setup face instead)
+ var machiningEquipment = localProjectService.MachiningEquipment;
+ var workpiece = machiningEquipment?.Workpiece;
+
+ if (RenderingFlagBitArray[(int)RenderingFlag.ClStrip])
+ {
+ localProjectService.ClStrip.IsKeepingDispAlive = true;
+ dst.Add(new AnchoredDisplayee(
+ workpiece?.ProgramZeroAnchor,
+ localProjectService.ClStrip));
+ }
+ if (RenderingFlagBitArray[(int)RenderingFlag.Mech])
+ {
+ if (machiningEquipment != null)
+ {
+ List machAncDisplayees =
+ machiningEquipment.GetAnchoredDisplayeeList() ?? [];
+ HashSet exclusiveAnchorSet = new([
+ .. workpiece?.Asmb.DescendantAnchors()??[],
+ .. machiningEquipment.MachiningTool?.GetAsmb().DescendantAnchors()??[],
+ .. machiningEquipment.Fixture?.Asmb.DescendantAnchors()??[],
+ ]);
+ dst.AddRange(machAncDisplayees.Where(ad =>
+ !exclusiveAnchorSet.Contains(ad.GetAnchor())));
+ }
+ }
+ if (RenderingFlagBitArray[(int)RenderingFlag.WorkpieceGeom])
+ {
+ if (workpiece != null)
+ dst.AddRange(localProjectService.WorkpieceService
+ .GetAnchoredDisplayeeList());
+ }
+ if (RenderingFlagBitArray[(int)RenderingFlag.Tool])
+ {
+ if (machiningEquipment?.MachiningTool != null)
+ dst.Add(new AnchoredDisplayee(
+ machiningEquipment.MachiningTool?.GetAnchor(),
+ machiningEquipment.MachiningTool));
+ }
+ if (RenderingFlagBitArray[(int)RenderingFlag.Fixture])
+ {
+ if (machiningEquipment?.Fixture != null)
+ dst.Add(new AnchoredDisplayee(
+ machiningEquipment.Fixture.GetAnchor(),
+ machiningEquipment.Fixture));
+ }
+ if (RenderingFlagBitArray[(int)RenderingFlag.ProgramZero])
+ {
+ if (workpiece != null)
+ dst.Add(workpiece.ProgramZeroAnchor);
+ }
+ if (RenderingFlagBitArray[(int)RenderingFlag.IsoCoordinate])
+ {
+ dst.Add(IsoCoordinateEntryDisplayee);
+ }
+ if (RenderingFlagBitArray[(int)RenderingFlag.HeidenhainCoordinate]
+ && ncEnv.CncBrand == CncBrand.Heidenhain)
+ {
+ dst.Add(HeidenhainCoordinateEntryDisplayee);
+ }
+ return dst;
+ }
+ ///
+ /// Gets the root anchor for the display hierarchy based on current rendering flags.
+ ///
+ /// The root anchor to use for rendering
+ internal static Anchor GetRootAnchor(
+ LocalProjectService localProjectService, BitArray renderingFlagBitArray)
+ {
+ //runtime face throughout: this roots the execution scene
+ var machiningEquipment = localProjectService?.MachiningEquipment;
+ if (renderingFlagBitArray[(int)RenderingFlag.Mech])
+ return machiningEquipment?.GetAnchor();
+ else if (renderingFlagBitArray[(int)RenderingFlag.WorkpieceGeom])
+ return machiningEquipment?.Workpiece?.GetAnchor();
+ else if (renderingFlagBitArray[(int)RenderingFlag.Fixture])
+ return machiningEquipment?.Fixture?.GetAnchor();
+ else if (renderingFlagBitArray[(int)RenderingFlag.Tool])
+ return machiningEquipment?.MachiningTool?.GetAnchor();
+ else
+ return null;
+ }
+ ///
+ public Anchor GetAnchor() => GetRootAnchor(LocalProjectService, RenderingFlagBitArray);
+ ///
+ public void Display(Bind bind)
+ {
+ //Console.WriteLine($"RB: {string.Join(',', Enumerable.Range(0,
+ // RenderingFlagBitArray.Length).Select(RenderingFlagBitArray.Get))}");
+
+ //ClStrip pos has to be update by ClStrip.
+ if (RenderingFlagBitArray[(int)RenderingFlag.WorkpieceGeom]
+ && !RenderingFlagBitArray[(int)RenderingFlag.ClStrip]
+ && LocalProjectService?.ClStrip.CallRefreshDrawing == true)
+ LocalProjectService?.ClStrip.RefreshDrawingInRendering(false);
+
+ bind.PushCoveringPixelMode();
+ double offsetHOnCover = 0;
+ if (RenderingFlagBitArray[(int)RenderingFlag.DimensionBar])
+ {
+ bind.ModelMatStack.Push();
+ bind.ModelMatStack.Trans(0, offsetHOnCover, 0);
+ DimensionBar.Display(bind, "mm");
+ bind.ModelMatStack.Pop();
+ offsetHOnCover += DimensionBar.OffsetH;
+ }
+ if (RenderingFlagBitArray[(int)RenderingFlag.ColorScaleBar]
+ && MachiningProject?.MillingGuide?.DictionaryColorGuide?.SelectedColorGuide
+ is IGetRangeColorRule getRangeColorRule)
+ {
+ var rangeColorRule = getRangeColorRule.GetRangeColorRule();
+ if (rangeColorRule != null)
+ {
+ bind.ModelMatStack.Push();
+ bind.ModelMatStack.Trans(0, offsetHOnCover, 0);
+
+ ColorScaleBar.Display(bind,
+ rangeColorRule.Floor, rangeColorRule.Ceiling,
+ rangeColorRule.GetRgb, "L.", "");
+ bind.ModelMatStack.Pop();
+ offsetHOnCover += ColorScaleBar.OffsetH;
+ }
+ }
+ if (LocalProjectService?.WorkpieceService?.HasDiffOverlay == true)
+ {
+ bind.ModelMatStack.Push();
+ bind.ModelMatStack.Trans(0, offsetHOnCover, 0);
+
+ var rangeColorRule = LocalProjectService.WorkpieceService.DiffRangeColorRule;
+ ColorScaleBar.Display(bind,
+ rangeColorRule.Floor, rangeColorRule.Ceiling,
+ rangeColorRule.GetRgb, "Df.", "");
+ bind.ModelMatStack.Pop();
+ offsetHOnCover += ColorScaleBar.OffsetH;
+ }
+ bind.ModelMatStack.Pop();
+
+ bind.PushColorByRgb(1, 1, 1);
+ var machiningEquipment = LocalProjectService?.MachiningEquipment;
+ //Collision red is per-scenario state owned by the execution equipment
+ //(never stored on the shared Solid geometry): scope it to this scene
+ //so the setup topology never paints it.
+ using (CollisionRedScope.Enter(
+ machiningEquipment == null ? null : machiningEquipment.IsCollisionRed))
+ {
+ machiningEquipment?.GetAsmb()?.Display(bind,
+ GetAnchor(),
+ GetAnchoredDisplayeeList().ToArray());
+ }
+ bind.PopColor();
+ }
+ ///
+ public void ExpandToBox3d(Box3d dst)
+ {
+ //Console.WriteLine($"dst.A: {dst}");
+ LocalProjectService?.MachiningEquipment?.GetAsmb()?.ExpandToBox3d(dst,
+ GetAnchor(),
+ GetAnchoredDisplayeeList().ToArray());
+ //Console.WriteLine($"dst.B: {dst}");
+ }
+}