This commit is contained in:
iambossTC 2025-04-06 19:55:34 +08:00
commit 1065c86824
8 changed files with 804 additions and 0 deletions

268
.gitignore vendored Normal file
View File

@ -0,0 +1,268 @@
!*.lib
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
project.fragment.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
#*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
!hasp*.exe
!hasp*.dll
!HiLock.dll
!Aladdin*.dll

10
AssemblyInfo.cs Normal file
View File

@ -0,0 +1,10 @@
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]

394
Disp/RenderingCanvas.cs Normal file
View File

@ -0,0 +1,394 @@
using Hi.Disp;
using Hi.Native;
using Hi.PanelModels;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Collections.Generic;
using Hi.Geom;
namespace Hi.Wpf.Disp
{
#region WPF Rendering Canvas
public class RenderingCanvas : UserControl, IDisposable
{
#region Core_Properties
/// <summary>
/// The DispEngine instance that handles rendering and user interactions
/// </summary>
public DispEngine DispEngine { get; } = new DispEngine();
/// <summary>
/// Internal container for rendering content
/// </summary>
private UserControl DisplayerPane { get; }
/// <summary>
/// Dictionary to store touch point information
/// </summary>
private Dictionary<int, Point> TouchingPointsMap { get; } = new Dictionary<int, Point>();
/// <summary>
/// Dictionary to store previous positions of touch points
/// </summary>
private Dictionary<int, Point> PreviousTouchingPointsMap { get; } = new Dictionary<int, Point>();
#endregion
#region Initialization
/// <summary>
/// Initializes a new instance of the RenderingCanvas
/// </summary>
public RenderingCanvas()
{
DispEngine.BackgroundColor = new Vec3d(0.1, 0.1, 0.5);
DispEngine.BackgroundOpacity = 0.1;
// Configure the main control properties
HorizontalAlignment = HorizontalAlignment.Stretch;
VerticalAlignment = VerticalAlignment.Stretch;
Focusable = true;
KeyboardNavigation.SetDirectionalNavigation(this, KeyboardNavigationMode.Cycle);
DataContextChanged += CanvasDataContextChanged;
// Create and configure the display pane
DisplayerPane = new UserControl();
DisplayerPane.HorizontalAlignment = HorizontalAlignment.Stretch;
DisplayerPane.VerticalAlignment = VerticalAlignment.Stretch;
DisplayerPane.Focusable = true;
DisplayerPane.IsTabStop = true;
// Connect event handlers for user input and window events
DisplayerPane.SizeChanged += RenderingCanvas_SizeChanged;
DisplayerPane.MouseMove += RenderingCanvas_MouseMove;
DisplayerPane.MouseDown += RenderingCanvas_MouseDown;
DisplayerPane.MouseUp += RenderingCanvas_MouseUp;
DisplayerPane.MouseWheel += RenderingCanvas_MouseWheel;
DisplayerPane.KeyDown += RenderingCanvas_KeyDown;
DisplayerPane.KeyUp += RenderingCanvas_KeyUp;
DisplayerPane.Loaded += RenderingCanvas_Loaded;
DisplayerPane.Unloaded += RenderingCanvas_Unloaded;
DisplayerPane.IsVisibleChanged += DisplayerPane_IsVisibleChanged;
// Add touch event handlers
DisplayerPane.TouchDown += RenderingCanvas_TouchDown;
DisplayerPane.TouchMove += RenderingCanvas_TouchMove;
DisplayerPane.TouchUp += RenderingCanvas_TouchUp;
// Enable touch support
this.IsManipulationEnabled = true;
// Add the display pane to this control's content
Content = DisplayerPane;
}
#endregion
#region Touch_Events
/// <summary>
/// Handles the touch down event
/// </summary>
private void RenderingCanvas_TouchDown(object sender, TouchEventArgs e)
{
// Add touch point to dictionary
Point touchPoint = e.GetTouchPoint(DisplayerPane).Position;
DispEngine.TouchDown(e.TouchDevice.Id,
(int)touchPoint.X, (int)touchPoint.Y);
// Ensure control gets focus
DisplayerPane.Focus();
e.TouchDevice.Capture(DisplayerPane);
e.Handled = true;
}
/// <summary>
/// Handles the touch move event
/// </summary>
private void RenderingCanvas_TouchMove(object sender, TouchEventArgs e)
{
Point touchPoint = e.GetTouchPoint(DisplayerPane).Position;
DispEngine.TouchMove(e.TouchDevice.Id,
(int)touchPoint.X, (int)touchPoint.Y);
e.Handled = true;
}
/// <summary>
/// Handles the touch up event
/// </summary>
private void RenderingCanvas_TouchUp(object sender, TouchEventArgs e)
{
DispEngine.TouchUp(e.TouchDevice.Id);
e.Handled = true;
}
#endregion
#region Window_Events
/// <summary>
/// Handles window state changes (maximize, minimize, etc.)
/// </summary>
private unsafe void RenderingCanvas_StateChanged(object sender, EventArgs e)
{
switch ((sender as Window).WindowState)
{
case WindowState.Maximized:
DispEngine.IsVisible = true;
break;
case WindowState.Minimized:
DispEngine.IsVisible = false;
break;
case WindowState.Normal:
DispEngine.IsVisible = true;
break;
}
}
/// <summary>
/// Handles data context changes
/// </summary>
private unsafe void CanvasDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
DispEngine pre = e.OldValue as DispEngine;
DispEngine cur = e.NewValue as DispEngine;
//child's binding event is triggered after IsVisible event and Load event.
if (pre != null) //this section will never occur if the datacontext not set twice.
{
pre.Terminate();
pre.ImageRequestAfterBufferSwapped -= RenderingCanvas_BufferSwapped;
}
if (cur != null)
{
cur.ImageRequestAfterBufferSwapped += RenderingCanvas_BufferSwapped;
cur.Start((int)DisplayerPane.RenderSize.Width, (int)DisplayerPane.RenderSize.Height);
cur.IsVisible = IsVisible;
}
}
/// <summary>
/// Reference to the current window containing this control
/// </summary>
private Window currentWindow;
/// <summary>
/// Gets or sets the current window, connecting or disconnecting state change events
/// </summary>
Window CurrentWindow
{
get => currentWindow; set
{
if (currentWindow != null)
currentWindow.StateChanged -= RenderingCanvas_StateChanged;
currentWindow = value;
if (currentWindow != null)
currentWindow.StateChanged += RenderingCanvas_StateChanged;
}
}
/// <summary>
/// Handles the loaded event
/// </summary>
private unsafe void RenderingCanvas_Loaded(object sender, RoutedEventArgs e)
{
// Get the window containing this control
CurrentWindow = Window.GetWindow(this);
// Set up DispEngine rendering
DispEngine.ImageRequestAfterBufferSwapped -= RenderingCanvas_BufferSwapped;
DispEngine.ImageRequestAfterBufferSwapped += RenderingCanvas_BufferSwapped;
DispEngine.Start((int)DisplayerPane.RenderSize.Width, (int)DisplayerPane.RenderSize.Height);
DispEngine.IsVisible = IsVisible;
}
/// <summary>
/// Handles the unloaded event
/// </summary>
private unsafe void RenderingCanvas_Unloaded(object sender, RoutedEventArgs e)
{
DispEngine.IsVisible = IsVisible;
DispEngine.ImageRequestAfterBufferSwapped -= RenderingCanvas_BufferSwapped;
CurrentWindow = null;
}
#endregion
#region DispEngine_Rendering
/// <summary>
/// Handles the buffer swapped event from DispEngine
/// </summary>
private unsafe void RenderingCanvas_BufferSwapped(byte* data, int w, int h)
{
if (data == null)
return;
// Copy pixel data from DispEngine
int n = w * h * 4;
byte[] arr = new byte[n];
for (int i = 0; i < n; i++)
arr[i] = data[i];
// Update UI on the UI thread
DisplayerPane.Dispatcher.InvokeAsync(() =>
{
BitmapSource bitmap = BitmapSource.Create(w, h, 1, 1, PixelFormats.Bgra32, null, arr, w * 4);
DisplayerPane.Background = new ImageBrush(bitmap);
});
}
/// <summary>
/// Handles the size changed event
/// </summary>
private void RenderingCanvas_SizeChanged(object sender, SizeChangedEventArgs e)
{
// Notify DispEngine of size changes
DispEngine.Resize((int)DisplayerPane.RenderSize.Width, (int)DisplayerPane.RenderSize.Height);
}
/// <summary>
/// Handles visibility changes
/// </summary>
private unsafe void DisplayerPane_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
// Update visibility state in DispEngine
DispEngine.IsVisible = IsVisible;
}
#endregion
#region Keyboard_Events
/// <summary>
/// Handles the key up event
/// </summary>
private void RenderingCanvas_KeyUp(object sender, KeyEventArgs e)
{
DispEngine.KeyUp((long)e.Key);
}
/// <summary>
/// Handles the key down event
/// </summary>
private void RenderingCanvas_KeyDown(object sender, KeyEventArgs e)
{
DispEngine.KeyDown((long)e.Key);
// Map specific keys for view transformation
long key = (long)e.Key;
if (key == (long)Key.RightShift)
key = (long)Key.LeftShift;
DispEngine.KeyDownTransform(key, new key_table__transform_view_by_key_pressing_t()
{
HOME = (long)Key.Home,
PAGE_UP = (long)Key.PageUp,
PAGE_DOWN = (long)Key.PageDown,
F1 = (long)Key.F1,
F2 = (long)Key.F2,
F3 = (long)Key.F3,
F4 = (long)Key.F4,
SHIFT = (long)Key.LeftShift,
ARROW_LEFT = (long)Key.Left,
ARROW_RIGHT = (long)Key.Right,
ARROW_DOWN = (long)Key.Down,
ARROW_UP = (long)Key.Up
});
}
#endregion
#region Mouse_Events
/// <summary>
/// Helper method to get mouse button mask
/// </summary>
internal static HiMouseButtonMask GetMouseButtonMask(MouseDevice device)
{
HiMouseButtonMask mouseButtonMask = 0;
mouseButtonMask.SetLeftPressed(device.LeftButton == MouseButtonState.Pressed);
mouseButtonMask.SetMiddlePressed(device.MiddleButton == MouseButtonState.Pressed);
mouseButtonMask.SetRightPressed(device.RightButton == MouseButtonState.Pressed);
mouseButtonMask.SetXButton1Pressed(device.XButton1 == MouseButtonState.Pressed);
mouseButtonMask.SetXButton2Pressed(device.XButton2 == MouseButtonState.Pressed);
return mouseButtonMask;
}
/// <summary>
/// Handles the mouse wheel event
/// </summary>
private void RenderingCanvas_MouseWheel(object sender, MouseWheelEventArgs e)
{
// Handle mouse wheel for zoom operations
DispEngine.MouseWheel(0, e.Delta / 120);
DispEngine.MouseWheelTransform(0, e.Delta / 120);
}
/// <summary>
/// Handles the mouse up event
/// </summary>
private void RenderingCanvas_MouseUp(object sender, MouseButtonEventArgs e)
{
// Handle mouse button release
DispEngine.MouseButtonUp((long)e.ChangedButton);
(sender as UIElement)?.ReleaseMouseCapture();
}
/// <summary>
/// Handles the mouse down event
/// </summary>
private void RenderingCanvas_MouseDown(object sender, MouseButtonEventArgs e)
{
// Handle mouse button press
DispEngine.MouseButtonDown((long)e.ChangedButton);
DisplayerPane.Focus();
(sender as UIElement)?.CaptureMouse();
}
/// <summary>
/// Handles the mouse move event
/// </summary>
private void RenderingCanvas_MouseMove(object sender, MouseEventArgs e)
{
// Update mouse position and handle drag transforms
Point p = e.GetPosition(DisplayerPane);
DispEngine.MouseMove((int)p.X, (int)p.Y);
DispEngine.MouseDragTransform((int)p.X, (int)p.Y,
new mouse_button_table__transform_view_by_mouse_drag_t()
{
LEFT_BUTTON = (long)MouseButton.Left,
RIGHT_BUTTON = (long)MouseButton.Right
});
}
#endregion
#region Cleanup
/// <summary>
/// Flag to track disposed state
/// </summary>
private bool disposedValue;
/// <summary>
/// Disposes managed resources
/// </summary>
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
// Dispose the DispEngine to free resources
DispEngine.Dispose();
}
disposedValue = true;
}
}
/// <summary>
/// Public dispose method to free resources
/// </summary>
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
#endregion
}
#endregion
}

63
Disp/RenderingWindow.cs Normal file
View File

@ -0,0 +1,63 @@
using Hi.Disp;
using Hi.Licenses;
using System;
using System.Windows;
using System.Windows.Media;
namespace Hi.Wpf.Disp
{
/// <summary>
/// Window for 3D rendering.
/// </summary>
public class RenderingWindow : Window, IGetDispEngine
{
public RenderingCanvas RenderingCanvas => Content as RenderingCanvas;
/// <summary>
/// Ctor.
/// </summary>
public RenderingWindow()
{
Title = nameof(RenderingWindow);
Height = 450;
Width = 800;
StateChanged += RenderingWind_StateChanged;
Content = new RenderingCanvas()
{
BorderThickness = new Thickness(1),
BorderBrush = Brushes.Black
};
}
private void RenderingWind_StateChanged(object sender, EventArgs e)
{
RenderingCanvas.DispEngine.IsVisible = WindowState != WindowState.Minimized;
}
/// <inheritdoc/>
public DispEngine GetDispEngine() => RenderingCanvas.DispEngine;
/// <summary>
/// Run a simple <see cref="RenderingWindow"/> application with given <paramref name="displayees"/>.
/// </summary>
/// <param name="title">Title</param>
/// <param name="displayees">displayees</param>
/// <returns>return value of <see cref="Application"/>.<see cref="Application.Run(Window)"/></returns>
public static int RunApplication(string title, params IDisplayee[] displayees)
{
License.LogInAll();
DispEngine.Init();
Application app = new Application
{
ShutdownMode = ShutdownMode.OnMainWindowClose
};
app.Exit += (o, e) =>
{
DispEngine.FinishDisp();
License.LogOutAll();
};
RenderingWindow window = new RenderingWindow() { Title = title };
window.RenderingCanvas.DispEngine.Displayee = new DispList(displayees);
window.RenderingCanvas.DispEngine.SetViewToHomeView();
return app.Run(window);
}
}
}

40
Hi.Wpf.csproj Normal file
View File

@ -0,0 +1,40 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0-windows</TargetFramework>
<Platforms>x64</Platforms>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<AssemblyName>Hi.Wpf</AssemblyName>
<RootNamespace>$(AssemblyName)</RootNamespace>
<Description>
HiAPI samples for windows platform.
</Description>
<Configurations>Debug;Release</Configurations>
<VersionBuild>3</VersionBuild>
<VersionPrefix>1.4.$(VersionBuild)</VersionPrefix>
<Product>$(AssemblyName)</Product>
<ApplicationIcon>techcoordinate.ico</ApplicationIcon>
<Copyright>Copyright 2022 Tech Coordinate Co., Ltd.</Copyright>
<Company>Tech Coordinate Co., Ltd.</Company>
<Authors>Tech Coordinate Co., Ltd.</Authors>
<OutputPath>bin\$(Platform).$(Configuration)\</OutputPath>
<StartupObject>Hi.Wpf.Program</StartupObject>
</PropertyGroup>
<ItemGroup Condition="'$(Configuration)'=='Debug'">
<ProjectReference Include="..\HiDisp\HiDisp.csproj" />
</ItemGroup>
<ItemGroup Condition="'$(Configuration)'=='Release'">
<PackageReference Include="HiDisp" Version="1.4.*" />
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<IsIgnoreObfuscar>true</IsIgnoreObfuscar>
<Optimize>true</Optimize>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
</Project>

19
Program.cs Normal file
View File

@ -0,0 +1,19 @@
using Hi.Disp;
using Hi.Disp.Flag;
using Hi.Geom;
using Hi.Wpf.Disp;
using System;
namespace Hi.Wpf
{
static class Program
{
[STAThread]
public static void Main(string[] args)
{
DispEngine.Init();
RenderingWindow.RunApplication("test",
new CoordinateDrawing(), new Stl(Box3d.CenterUnitBox).ToFaceDrawing());
}
}
}

View File

@ -0,0 +1,10 @@
{
"profiles": {
"HiAPI-Demo-WPF": {
"commandName": "Project",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

BIN
techcoordinate.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB