引子
前一阵基于AnyCAD做了些小项目,发现SDK中不少与文档(Document)、元素构件(Element)相关的概念和Revit等BIM软件有一定相似度,这在进行业务开发时有很大用处,但不知为何目前官方在这方面的文档比较少,也未提供太多具体示例,所以准备选取一些Highlight简单写些小教程。工业软件SDK或二次开发接口大多使用相似的架构和理念,一方面借此作为自己学习和开发的基础,另一方面也希望可以帮助到从事相关工作的朋友。
概述
AnyCAD图形平台主要提供一系列造型、显示、以及一些工业领域应用的脚手架,gitee上有不少官方提供的示例仓库:
- rapid.net.starter
- anycad.rapid.net.sample
- RapidCAX
还不熟悉此平台的朋友可以先从官网和上面的例子入门,这里不作过多展开。
在大多例子中,AnyCAD创建和操作的对象都仅仅用于显示,但复杂的CAD软件往往需要具备数据管理功能,所有针对数据对象的增删查改都应可回退或重做(Undo/Redo),AnyCAD也提供了这些基础功能,在官方开发指南数据管理这一节介绍了基本概念和用法,本文fork了rapid.net.starter这一仓库进行了一些修改,需要参考的朋友可以把代码pull到本地直接运行(安装相关依赖的前提下,具体依赖请参考官方提供的教程)。
准备工作
AnyCAD提供的应用框架AppFramework能够让开发者以MVVM的模式快速搭建应用,我们这里也借助它来完成应用与文档的初始化;安装nuget包后新建一个MainViewModelImpl.cs文件,创建一个从AnyCAD.NX.ViewModel.WpfMainViewModel继承的类即可:
public partial class MainViewModelImpl : WpfMainViewModel
{
public MainViewModelImpl(IRenderView viewer)
: base(viewer)
{
}
}
接着在MainWindow的构造函数中实例化MainViewModelImpl:
public MainWindow()
{
InitializeComponent();
var viewModel = new MainViewModelImpl(mRenderCtrl);
this.DataContext = viewModel;
}
并在已经注册的ViewerReady事件函数中初始化viewModel:
private void mRenderCtrl_ViewerReady()
{
// 初始化
ViewModel.Initialize(mRenderCtrl);
}
此时编译运行程序将会得到一个已初始化文档对象的窗口:
在事务中创建对象
参照开发指南里的示例代码,我们增加一个菜单项用于创建包含圆柱体形状的ShapeElement,并将这部分代码包含在UndoTransaction的Start与Commit之间:
// MainWindow.xaml
<Metro:MetroWindow.RightWindowCommands>
<Metro:WindowCommands ShowSeparators="False">
<Menu Margin="50,2,0,0" Background="#00000000">
<MenuItem Header="创建" Background="#00000000">
<MenuItem Header="圆柱体" Command="{Binding NewCylinderCommand}"/>
</MenuItem>
</Menu>
</Metro:WindowCommands>
</Metro:MetroWindow.RightWindowCommands>
// MainViewModelImpl.cs
[RelayCommand]
void OnNewCylinder() // 该方法与xaml中的创建圆柱体命令绑定
{
UndoTransaction undo = new(Document); // 实例化UndoTransaction对象
undo.Start("create.cylinder"); // 开启事务
var shape = ShapeBuilder.MakeCylinder(GP.XOY(), 10, 20, 0); // 创建圆柱体shape
var shapeElement = ShapeElement.Create(Document); // 在文档中创建ShapeElement对象
shapeElement.SetShape(shape); // 将构造好的shape赋予ShapeElement对象
undo.Commit(); // 提交事务
}
运行后通过菜单项便可创建圆柱体:
Undo/Redo操作
目前为止和rapid.net.starter原本所展示的内容似乎并无区别,但实际上新建圆柱体这一操作已经能够进行回退操作了,由于SDK并没有自带回退与重做键盘事件的绑定,我们需要在MainWindow.xaml自行绑定:
<Metro:MetroWindow.InputBindings>
<KeyBinding
Key="Z"
Command="{Binding UndoCommand}"
Modifiers="Control" />
<KeyBinding
Key="Y"
Command="{Binding RedoCommand}"
Modifiers="Control" />
</Metro:MetroWindow.InputBindings>
或者也可以增加菜单项来执行这两个命令:
<MenuItem Header="事务" Background="#00000000">
<MenuItem Header="回退" Command="{Binding ExecuteSystemCommand}" CommandParameter="Undo"/>
<MenuItem Header="重做" Command="{Binding ExecuteSystemCommand}" CommandParameter="Redo"/>
</MenuItem>
那么这时我们再创建圆柱体之后就可以通过快捷键或菜单项进行Undo/Redo操作了:
在事务中编辑对象
同时,后续对已创建对象的编辑也同样支持在事务中进行,以进行Undo/Redo操作,AnyCAD也提供了移动/旋转物体的小控件,调用"MoveInstance/RotateInstance"命令即可唤起:
<MenuItem Header="编辑" Background="#00000000">
<MenuItem Header="移动" Command="{Binding ExecuteSystemCommand}" CommandParameter="MoveInstance"></MenuItem>
<MenuItem Header="旋转" Command="{Binding ExecuteSystemCommand}" CommandParameter="RotateInstance"></MenuItem>
</MenuItem>
并且,通过这两个小控件进行的编辑操作已经被包含在了事务中,不再需要开发者去操作UndoTransaction对象(不过截止文章撰写时,这里需要两次Undo才能回到编辑前的状态,已report issue给平台,想必后续会修复这个问题):
总结
数据管理是开发复杂CAD应用的重要功能,AnyCAD帮助开发者实现了一部分核心内容,这大大提升了业务实现的效率。后续我将结合自己的经历撰写更多工业软件开发的小文章,欢迎大家阅读与指正。