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..3e36405
--- /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..8192c7f
--- /dev/null
+++ b/Disp/MachiningProjectDisplayee.cs
@@ -0,0 +1,239 @@
+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.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;
+ var workpiece = localProjectService.Workpiece;
+ var machiningEquipment = localProjectService.MachiningEquipment;
+
+ if (RenderingFlagBitArray[(int)RenderingFlag.ClStrip])
+ {
+ localProjectService.ClStrip.IsKeepingDispAlive = true;
+ dst.Add(new AnchoredDisplayee(
+ localProjectService.MachiningEquipment?.Workpiece?.ProgramZeroAnchor,
+ localProjectService.ClStrip));
+ }
+ if (RenderingFlagBitArray[(int)RenderingFlag.Mech])
+ {
+ if (localProjectService.MachiningEquipment != null)
+ {
+ List machAncDisplayees = localProjectService
+ ?.MachiningEquipment?.GetAnchoredDisplayeeList() ?? [];
+ HashSet exclusiveAnchorSet = new([
+ .. localProjectService.Workpiece?.Asmb.GetDescendantAnchors()??[],
+ .. localProjectService.MachiningTool?.GetAsmb().GetDescendantAnchors()??[],
+ .. localProjectService.Fixture?.Asmb.GetDescendantAnchors()??[],
+ ]);
+ 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 (localProjectService.MachiningEquipment != null
+ && localProjectService.MachiningTool != null)
+ dst.Add(new AnchoredDisplayee(
+ localProjectService.MachiningTool?.GetAnchor(),
+ localProjectService.MachiningTool));
+ }
+ if (RenderingFlagBitArray[(int)RenderingFlag.Fixture])
+ {
+ if (localProjectService.MachiningEquipment != null
+ && localProjectService.Fixture != null)
+ dst.Add(new AnchoredDisplayee(
+ localProjectService.Fixture?.GeomAnchor,
+ localProjectService.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)
+ {
+ if (renderingFlagBitArray[(int)RenderingFlag.Mech])
+ return localProjectService?.MachiningEquipment?.GetAnchor();
+ else if (renderingFlagBitArray[(int)RenderingFlag.WorkpieceGeom])
+ return localProjectService.Workpiece?.GetAnchor();
+ else if (renderingFlagBitArray[(int)RenderingFlag.Fixture])
+ return localProjectService.Fixture?.GetAnchor();
+ else if (renderingFlagBitArray[(int)RenderingFlag.Tool])
+ return localProjectService.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?.HasDiff == 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);
+ LocalProjectService?.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}");
+ }
+}
diff --git a/Machining/DemoMillingByCutterLocation.cs b/Machining/DemoMillingByCutterLocation.cs
index e3432be..2f39b17 100644
--- a/Machining/DemoMillingByCutterLocation.cs
+++ b/Machining/DemoMillingByCutterLocation.cs
@@ -12,6 +12,7 @@ using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
+using Sample.Disp;
namespace Sample.Machining
{
diff --git a/Machining/DemoRenderingMachiningProcessAndStripPosSelection.cs b/Machining/DemoRenderingMachiningProcessAndStripPosSelection.cs
index 90ff274..89b644e 100644
--- a/Machining/DemoRenderingMachiningProcessAndStripPosSelection.cs
+++ b/Machining/DemoRenderingMachiningProcessAndStripPosSelection.cs
@@ -6,6 +6,7 @@ using System.Windows;
using Hi.MachiningSteps;
using Hi.HiNcKits;
using Microsoft.Extensions.Logging;
+using Sample.Disp;
namespace Sample.Machining
{