PolyStar - WPF 多边形和星形






4.88/5 (30投票s)
用于创建各种星形和多边形的控件和工具。
引言
本文包含一个用于生成多边形和星形的 Shape
类,以及一个允许我们预览这些对象的编辑器。这始于我发现需要一个“旋转的小东西”来在漫长的过程中显示。一个几何形状演变而来,随之而来的是一个设计应用程序。
本文的大部分内容将介绍用于创建星形和多边形(下称“多星形”)的几何变换的实现。在此过程中,我遇到了 DependencyProperty
类实现中的一些奇怪之处。希望我的经验能有所帮助。
虽然理解是一个很棒的事情,但在检查其内部工作原理之前,您可以使用 PolyStar
类和设计应用程序。您可以将 PolygonImageLib
的引用添加到您的项目中,使用 Generator 工具构建多边形,然后获取 XAML 并将其粘贴进去,无论是作为 PolyStar
还是 Polygon
。
Assemblies
代码包含三个程序集。PolygonBuilder 包含显示 PolyStar
s 的代码,PolygonImageLib 包含 PolyStar
的类,PointTransformations 包含处理多边形中点的基本类。PointTransformations
中的类大多来自我上一篇文章。
多边形和星形
多边形可以被认为是沿着由半径和点/边数指定的圆的等角点集。生成星形和多边形的代码在 PolyMatrixBuilder
中。
if (mShapeType == EShapeType.Polygon)
{
Matrix mat = new Matrix(2);
for (int i = 0; i < mSides; i++)
{
double x = mRadius * Math.Cos((2 * Math.PI / mSides) * i);
double y = mRadius * Math.Sin((2 * Math.PI / mSides) * i);
mat.AddRow(new Double[] { x, y });
}
星形要复杂一些。定义星形的一种方法是将其视为两个具有相同边数、相同原点但半径不同的多边形,但内侧多边形是旋转过的。
为了创建星形,我们克隆点矩阵,旋转它们,然后将两个矩阵交错。请注意,内半径可以为负数,这会产生有趣的效果,特别是当负内半径绝对值略小于半径时。界面设置为负值需要手动输入,而不是从滑块获取。
角度偏移
角度偏移可以被认为是内侧多边形相对于正常星形位置的旋转量。
请注意,它可以是正数或负数。另外,如果偏移量大于 360/(边数) 度,则几何形状会发生显著变化。
斜角
斜角通常被认为是削平形状的角。严格来说,我应该说倒角,但这不常用。还有另一种思考斜角的方式。我们可以复制点集,稍微旋转它,然后交错两个点集。这就是我采用的方法。
当斜角为负数,或者对于多边形角度大于 360/(边数) 度,或者对于星形角度大于 180/(边数) 度时,我们会得到有趣的效果。
星形生成代码
将代码中的所有几何概念结合起来,我们得到星形如下:
Matrix innerMat = (Matrix)outerMat.Clone();
// Will work because centered about origin
innerMat.Multiply(mInnerRadius / mRadius);
PointTransformations.RotationalTransformation rot =
new RotationalTransformation() { Matrix = innerMat };
rot.RotateRadiansAroundOrigin(Math.PI / mSides); //Circle is 2PI radians
if (mIsAngularlyOffset)
{
rot.RotateDegreesAroundOrigin(mAngularOffset);
}
outerMat.Interleave(innerMat, false);
if (mIsBeveled )
{
Matrix bevelmat = (Matrix)outerMat.Clone();
rot.Matrix = bevelmat;
rot.RotateDegreesAroundOrigin(mBevelOffset);
outerMat.Interleave(bevelmat, false);
rot.Matrix = outerMat;
//Remove appearance of rotation
rot.RotateDegreesAroundOrigin(-mBevelOffset / 2);
}
之后,调用 OverallTransformation
s 中的一些总体变换来旋转形状,或在垂直或水平方向上将其压扁。这样做是为了方便维护。
依赖属性
我创建 PolyStar
的动机是动画化它。这要求大多数属性都成为依赖属性。一切都进展顺利,只有一些小麻烦。请注意,如果您有一个 double
属性,您需要将零值设置为 0.0 而不是 0。它不会自动为您转换,并且在创建对象的 XAML 中会崩溃,而不是在错误赋值点崩溃。
当我决定当 IsRotated
设置为 false
时,也将 Rotation
的值设置为 0 会更好时,出现了问题。我天真地认为以下代码会起作用:
set
{
SetValue(IsRotatedProperty, value);
Rotation= 0;
}
Rotation
没有改变,但 IRotated
得到了很好的修改。过了一段时间,我尝试了以下方法:
set
{
double[] x = { 0 };
double y = x[4];
SetValue(IsRotatedProperty, value);
double z = x[4];
}
这应该会生成一个运行时错误,但并没有。显然,编译器只是忽略了 set
语句中的所有内容,除了 SetValue
。但是,如果存在语法错误,它将无法编译。如果您想在属性设置时执行某些操作,则需要使用回调。在 set
区域中放置代码将不起作用。
这是一个有效的属性版本。
静态辅助函数
private static DependencyProperty DependencyProp
(string name, System.Type type,object defaultValue){
FrameworkPropertyMetadata fpm = new FrameworkPropertyMetadata
( defaultValue, FrameworkPropertyMetadataOptions.AffectsRender);
DependencyProperty dp = DependencyProperty.Register
(name, type , typeof(PolyStar), fpm);
return dp;
}
private static DependencyProperty DependencyProp
(string name, System.Type type, object defaultValue,
PropertyChangedCallback callback)
{
FrameworkPropertyMetadata fpm = new FrameworkPropertyMetadata
(defaultValue, FrameworkPropertyMetadataOptions.AffectsRender,callback);
DependencyProperty dp = DependencyProperty.Register
(name, type, typeof(PolyStar), fpm );
return dp;
}
属性定义
public static DependencyProperty IsRotatedProperty =
DependencyProp("IsRotated", typeof(bool), false, IsRotatedCallBack);
public bool IsRotated
{
get { return (bool)GetValue(IsRotatedProperty ); }
set
{
SetValue(IsRotatedProperty, value);
}
}
最后是回调
static void IsRotatedCallBack(DependencyObject property,
DependencyPropertyChangedEventArgs args)
{
if (!(bool)args.NewValue)
{
PolyStar pTemp = (PolyStar)property;
pTemp.Rotation = 0;
}
}
结论
还有其他关于技术实现的细节可能很有趣。IValueConverter<t>
值得一看。MainWindow.xaml 以一种有益的方式使用了 VisualBrush
,这是我一直怀疑自己是否会做到的事情。我写这篇文章的目的是创建一个工具,让人们能够轻松地将有趣的多边形和星形添加到他们的应用程序中。我希望我成功了。
历史
- 2008 年 9 月 27 日:初次发布