通用多边形管理例程






4.25/5 (5投票s)
2001年10月25日
5分钟阅读

86946

1449
一个让处理多边形更简单的类。
引言
最近我发现自己画了很多简单的多边形,比如轮廓形状。问题是这些形状需要以各种不同的旋转方式显示。其中一种形状是一个漂亮的指南针箭头,我在我的配套文章中使用了它来制作自注册自定义控件。完整的控件在这里重现。这篇文章主要讲的是我如何制作一个漂亮的旋转箭头。
 这里的想法是创建一个指南针,它指向一个物体前进的方向,使用地理坐标。绘图的许多细节将在配套文章中讨论。
这里的想法是创建一个指南针,它指向一个物体前进的方向,使用地理坐标。绘图的许多细节将在配套文章中讨论。 
为了创建这些简单的单色形状,我花了几小时编写了一个简单的编辑器,允许我输入一组x,y坐标。不需要鼠标,没有什么特别复杂的东西,但所有我需要的是x,y坐标的列表,而不是图元文件或其他什么复杂的东西。我最复杂的一幅画有大约20个端点。我使用了我写的那个矢量编辑器程序,它也在一篇配套文章中进行了描述。
这是定义指南针针头的点集。名义坐标系是一个100单位的坐标系,范围是±50。
-14, 30 -5, 38 0, 46 5, 38 14, 30 4, 34 4, -36 14,-46 0, -40 -14, -46 -4,-36 -4, 34
Polygon.h
class CPolygon { public: CPolygon() { heading = 0.0; scaling = 1.0; } BOOL Read(const CString & filename); BOOL Load(UINT resid); BOOL Load(LPCTSTR resource); CRect GetInputBB(); CRgn * GetRgn(); CRect Transform(double angle, double scale); void Draw(CDC & dc, CDoublePoint pt); bool IsDefined() { return points.GetSize() > 0; } protected: CArray<CDoublePoint, CDoublePoint> points; double heading; // current angle double scaling; CArray<CPoint, CPoint> transformed; };
CPolygon::CPolygon
CPolygon::CPolygon()
构造函数。初始化多边形。多边形不包含任何点。
CPolygon::Read
BOOL CPolygon::Read(const CString & filename)
| const CString & filename | 要读取的文件的名称。 | 
从指定文件中读取一组点。如果发生错误,则返回FALSE。如果发生错误,points数组的内容未定义。输入时只进行最小的语法检查,因为假定输入来自程序。
CPolygon::Load
BOOL CPolygon::Load(UINT resid) BOOL CPolygon::Load(LPCTSTR resourcename)
| UINT resid | POINTS资源的资源ID | 
| LPCTSTR resourcename | POINTS资源的名称 | 
从资源段加载一组点。资源段类型必须是POINTS。两种形式决定名称是数字资源ID还是字符串名称。
要将一组点包含在资源段中,请将以下样式的声明添加到\res\projectname.rc2文件中
resource_name POINTS DISCARDABLE "\\res\\filename"
例如,为了添加箭头资源,我这样做了
IDP_ARROW POINTS DISCARDABLE "\\res\\arrow.pln"
因为我没有定义符号,比如
#define IDP_ARROW 1101
我使用了该方法的LPCTSTR版本。
将文件(在本例中是arrow.pln)复制到项目目录下的\\res子目录中。
CPolygon::GetInputBB
CRect CPolygon::GetInputBB( )
返回一个CRect,它表示多边形在读入时(在进行任何旋转变换之前)的边界框。边界框是完全包含对象所有点的最小矩形。
CPolygon::GetRgn
CRgn * CPolygon::GetRgn( )
返回变换后的(旋转和缩放后的)多边形的区域。这可以用来使对象占据的区域无效。
CPolygon::Transform
CRect Transform(double angle, double scale, BOOL force = FALSE)
| double angle | 旋转角度,以地理坐标表示 | 
| double scale | 缩放因子。这被解释为相对于定义时读入的点。 | 
| BOOL force | 强制重新计算,即使内部优化确定现有的变换后点集是有效的。 | 
这将根据指定的角度(以地理坐标表示,0.0为北,90.0为东,180.0为南,270.0为西)和缩放来变换多边形点。结果是一个内部结构,包含变换后的点,适用于Draw方法。返回的CRect是变换后点的边界矩形,或者矩形(0,0,0,0)。作为一种优化,如果角度和缩放与上一次Transform调用相同,则不计算任何内容,并返回(0,0,0,0)。如果你需要强制重新计算以获得边界框返回值,请使用第三个参数force,并将其设置为TRUE,这将绕过优化。
请注意,CRect是以映射坐标表示的,y值向上增加,x值向右增加;假设点围绕一个逻辑对象中心的0,0轴居中。因此,IsRectEmpty将始终返回TRUE。如果你需要检查一个空矩形,你可能需要先创建一个副本,并在副本上调用NormalizeRect方法(如果你不需要保留CRect,你可以对结果调用NormalizeRect)。
必须在执行Draw方法之前调用此方法。Draw将始终根据Transform建立的当前变换来绘制多边形。如果自数据加载以来没有调用Transform,则变换后的点数组为空。
变换是根据下图中所示的变换矩阵进行的,围绕中心点0,0的经典旋转。给定两点x,y,x方向的缩放sx,y方向的缩放sy,新点x',y'根据以下矩阵乘法计算
             _                   _
            |  cos Ø    sin Ø  0  |
     [x y 0]|  -sin Ø   cos Ø  0  |=[sx*((cos Ø)*x-(sin Ø)*y)
            |_    0     0      0 _|  sy*((sin Ø)*x+(cos Ø)*y) 0]
(第三列是为了使矩阵乘法正确而添加的,然后被丢弃)。
在我的情况下,我只允许各向同性(sx == sy)缩放。
CPolygon::IsDefined
BOOL CPolygon::IsDefined( )
如果多边形由一组点定义,则返回TRUE。如果点数组为空,则返回FALSE。请注意,如果读取时出错,点数组通常是空的。
CPolygon::Draw
void CPolygon::Draw(CDC & dc, CDoublePoint pt)
| CDC & dc | 用于绘制对象的DC。 | 
| CDoublePoint pt | 在DC中绘制图像的点,以逻辑坐标表示。 | 
在指定的DC中,在由点指定的_位置_绘制变换后的多边形。假定DC处于y值向上(而不是向下,如MM_TEXT模式)增加的映射模式。返回时DC不变。必须在调用Draw之前调用Transform方法来创建变换后的点集。未能调用Transform将意味着使用上一次变换;如果没有执行过任何变换,变换集将为空,并且不会出现任何绘图。
