1.任意角度旋转
在XAML设计器中,设置RotateTransform属性
<InkCanvas x:Name="ToolInkCanvas" UseCustomCursor="True" ClipToBounds="False" MinHeight="50" MinWidth="50" EditingMode="None" Background="{x:Null}" Margin="1" >
<InkCanvas.RenderTransform>
<TransformGroup>
<RotateTransform/>
<ScaleTransform/>
</TransformGroup>
</InkCanvas.RenderTransform>
</InkCanvas>
根据鼠标按下时的位置和图片中心位置,利用WPF中Vector类计算向量夹角,得到角度,再设置元素的RotateTransform旋转属性变换。
/// <summary>
/// 图像旋转
/// </summary>
/// <param name="mouseVal">差值</param>
/// <param name="type">鼠标类型</param>
/// <param name="X">平移X轴距离</param>
/// <param name="startX">X轴起始位置</param>
/// <param name="Y">平移Y轴距离</param>
/// <param name="startY">Y轴起始位置</param>
/// <param name="isAction">是主动发起还是关联操作时被动调用</param>
private void RotateImage(double mouseVal, string type, double X, double startX, double Y, double startY, bool isAction = true)
{
double angle = 0;
if (type != "wheel")
{
Vector curVector = new Vector(X - ToolInkCanvas.ActualWidth / 2, Y - ToolInkCanvas.ActualHeight / 2);
double ang = Vector.AngleBetween(downVector, curVector);
angle = SetRotateTrans(ToolInkCanvas, ang, true);
ImgAngle = angle;
downVector = curVector;
}
else
{
if (mouseVal > 0)
{
angle = SetRotateTrans(ToolInkCanvas, 2, true);
}
else
{
angle = SetRotateTrans(ToolInkCanvas, -2, true);
}
ImgAngle = angle;
}
if (isAction && PubVal.IsStack)
{
for (int i = 0; i < Cell.MedicalView.SelectedBoxList.Count; i++)
{
var box = Cell.MedicalView.SelectedBoxList[i];
if (box != this)
{
box.RotateImage(mouseVal, type, X, startX, Y, startY, false);
}
}
}
//旋转所有box
for (int i = 0; i < Cell.BoxList.Count; i++)
{
if (Cell.BoxList[i] != this && (Cell.BoxList[i].ImageAlign == ImageAlignment.Center || Cell.BoxList[i].ImageAlign == ImageAlignment.Parent))
{
Cell.BoxList[i].RotateImage(angle);
}
}
Main.ToolBar.CheckAllText(this);
}
看效果:
2.镜像翻转
在上一篇《影像的平移和缩放》文中提到的ScaleTransform属性中,
同样还是先获取变换对象
ScaleTransform st = tgnew.Children[index] as ScaleTransform;
当 st.ScaleX的值为-1时则水平翻转,
当 st.ScaleY的值为-1时则垂直翻转
复制代码
/// <summary>
/// 设置元素比例
/// </summary>
/// <param name="ui">元素</param>
/// <param name="scaleX">x比例</param>
/// <param name="scaleY">y比例</param>
/// <param name="isAppend">是否为追加比例</param>
/// <param name="index">变换属性的下标</param>
public ScaleTransform SetScaleTrans(UIElement ui, double scaleX, double scaleY, bool isAppend, int index = 0)
{
TransformGroup tg = ui.RenderTransform as TransformGroup;
var tgnew = tg.CloneCurrentValue();
if (tgnew != null)
{
ui.RenderTransformOrigin = new Point(0.5, 0.5);
ScaleTransform st = tgnew.Children[index] as ScaleTransform;
if (isAppend)
{
st.ScaleX *= scaleX;
st.ScaleY *= scaleY;
}
else
{
st.ScaleX = scaleX;
st.ScaleY = scaleY;
}
ui.RenderTransform = tgnew;
return st;
}
return null;
}
调用翻转:
/// <summary>
/// 图像翻转
/// </summary>
/// <param name="type">翻转类型</param>
public void FlipImage(FlipType type)
{
if (type == FlipType.Horizontal)
{
var st = SetScaleTrans(ToolInkCanvas, -1, 1, true, 1);
}
else
{
var st = SetScaleTrans(ToolInkCanvas, 1, -1, true, 1);
}
UpDateTag();
}
看效果:
3.复合操作与标记文字角度自适应
在2D操作过程中,除了会同时做平移、缩放和旋转之外,图像上通常有测量标记,当影像发生2D变化时,需要将测量文字自适应角度回正,与旋转方向相反。
复制代码
/// <summary>
/// 重新设置文本大小和旋转角度
/// <param name="txt">文本控件</param>
/// </summary>
public void ReSetMeasureSize(TextBlock txt)
{
if (cvsWidth < cvsHeight)
{
txt.FontSize = (cvsWidth / w_num);
}
else
{
txt.FontSize = (cvsHeight / h_num);
}
if (txt.RenderTransform.Dispatcher == null)
{
TransformGroup tf = new TransformGroup();
tf.Children.Add(new RotateTransform());
tf.Children.Add(new ScaleTransform());
txt.RenderTransform = tf;
}
TransformGroup cvsTf = inkCanvas.RenderTransform as TransformGroup;
var cvsTg = cvsTf.CloneCurrentValue();
RotateTransform rtf = cvsTg.Children[0] as RotateTransform;
//设置翻转
ScaleTransform stf = cvsTg.Children[1] as ScaleTransform;
TransformGroup tfg = txt.RenderTransform as TransformGroup;
var tfgnew = tfg.CloneCurrentValue();
if (tfgnew != null)
{
ScaleTransform st = tfgnew.Children[1] as ScaleTransform;
if (stf.ScaleX * st.ScaleX < 0)
{
st.ScaleX *= -1;
}
if (stf.ScaleY * st.ScaleY < 0)
{
st.ScaleY *= -1;
}
txt.RenderTransform = tfgnew;
}
//设置旋转
TransformGroup tg = txt.RenderTransform as TransformGroup;
var tgnew = tg.CloneCurrentValue();
if (tgnew != null)
{
txt.RenderTransformOrigin = new Point(0, 0);
RotateTransform rt = tgnew.Children[0] as RotateTransform;
if (rtf.Angle != rt.Angle)
{
rt.Angle = -1 * rtf.Angle;
}
ScaleTransform st = tfgnew.Children[1] as ScaleTransform;
if (((st.ScaleX < 0 && st.ScaleY > 0) || (st.ScaleY < 0 && st.ScaleX > 0)) && ((rt.Angle > 0 && rtf.Angle <= 0) || (rt.Angle < 0 && rtf.Angle >= 0)))
{
rt.Angle *= -1;
}
else if (st.ScaleY > 0 && st.ScaleX > 0 && ((rt.Angle < 0 && rtf.Angle < 0)||(rt.Angle >= 0 && rtf.Angle >= 0)))
{
rt.Angle *= -1;
}
else if (st.ScaleY < 0 && st.ScaleX < 0 && ((rt.Angle < 0 && rtf.Angle < 0) || (rt.Angle >= 0 && rtf.Angle >= 0)))
{
rt.Angle *= -1;
}
txt.RenderTransform = tgnew;
}
}
看效果:
C#开发PACS、RIS、3D医学影像处理系统系列教程 目录整理:
菜鸟入门篇
C#开发PACS医学影像处理系统(七):读取影像Dicom信息
C#开发PACS医学影像处理系统(十):Dicom影像下载策略与算法
C#开发PACS医学影像处理系统(十一):Dicom影像挂片协议
C#开发PACS医学影像处理系统(十二):绘图处理之图形标记
C#开发PACS医学影像处理系统(十三):绘图处理之病灶测量
C#开发PACS医学影像处理系统(十四):处理Dicom影像窗宽窗位
C#开发PACS医学影像处理系统(十五):Dicom影像交叉定位线算法
C#开发PACS医学影像处理系统(十六):2D处理之影像平移和缩放
C#开发PACS医学影像处理系统(十七):2D处理之影像旋转和翻转
医学影像三维篇
C#开发PACS医学影像三维重建(一):使用VTK重建3D影像
C#开发PACS医学影像三维重建(二):使用VTK进行体绘制
C#开发PACS医学影像三维重建(三):纹理映射与颜色传输
C#开发PACS医学影像三维重建(四):3D网格平滑效果
C#开发PACS医学影像三维重建(五):基于梯度透明的组织漫游
C#开发PACS医学影像三维重建(六):三维光源与阴影效果
C#开发PACS医学影像三维重建(七):空间测量与标注
C#开发PACS医学影像三维重建(八):VR体绘制
C#开发PACS医学影像三维重建(九):MPR三视图切面重建
C#开发PACS医学影像三维重建(十):MIP最小密度投影
C#开发PACS医学影像三维重建(十一):CPR曲面重建
C#开发PACS医学影像三维重建(十二):VE虚拟内镜技术
熟手进阶篇
C#处理医学影像(一):基于Hessian矩阵的血管肺纹理骨骼增强对比
C#处理医学影像(二):基于Hessian矩阵的医学影像增强与窗宽窗位
胶片打印:
C#开发医学影像胶片打印系统(二):胶片打印机通讯
C#开发医学影像胶片打印系统(三):Pacs二维功能在排版中的应用
登峰造极篇
C#开发基于Python人工智能的肺结节自动检测
C#开发基于Python人工智能的脊柱侧弯曲率算法
C#开发基于Python机器学习的医学影像骨骼仿真动画
C#开发基于Python机器学习的术后恢复模拟
C#开发基于U3D的VR眼镜设备虚拟人体三维重建
C#开发基于全息投影的裸眼3D医学影像显示技术
免费下载