第五章 绘图基础(ALTWIND)

图形的坐标(按一个100*100单位的区域设定)存储在aptFigure数组中。这些坐标会根据客户去的宽度和高度按比例缩放。程序显示两个图形,一个使用ALTERNATE填充模式,另一个使用WINDING填充模式。结果如图:

drawPoints(float[] pts, int offset, int count, Paint paint) 

float[] points={0,0,50,50,50,100,100,50,100,100,150,50,150,100};// 绘制四个点:(50, 50) (50, 100) (100, 50) (100, 100)

canvas.drawPoints(points,2/* 跳过两个数,即前两个 0 */,8/* 一共绘制 8 个数(4 个点)*/, paint);


ALTWIND.C

自定义绘制技术点总结:

方式:重写绘制方法,其中最常用的是 onDraw()

关键: Canvas 的使用

  1, Canvas 的绘制类方法: drawXXX() (关键参数:Paint)

  2,Canvas 的辅助类方法:范围裁切(clipXXX())和几何变换

补充:使用不同的绘制方法来控制遮盖关系

  1 /*-------------------------------------------
  2 ALTWIND.C -- Alternate and Winding Fill Modes
  3              (c) Charles Petzold, 1998
  4 -------------------------------------------*/
  5 
  6 #include <Windows.h>
  7 
  8 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  9 
 10 int WINAPI WinMain( __in HINSTANCE hInstance
 11                     , __in_opt HINSTANCE hPrevInstance
 12                     , __in LPSTR lpCmdLine
 13                     , __in int nShowCmd )
 14 {
 15     static TCHAR szAppName[] = TEXT("AltWind");
 16     HWND hwnd;
 17     MSG msg;
 18     WNDCLASS wndclass;
 19 
 20     wndclass.style = CS_HREDRAW | CS_VREDRAW;
 21     wndclass.lpfnWndProc = WndProc;
 22     wndclass.cbClsExtra = 0;
 23     wndclass.cbWndExtra = 0;
 24     wndclass.hInstance = hInstance;
 25     wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
 26     wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
 27     wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
 28     wndclass.lpszMenuName = NULL;
 29     wndclass.lpszClassName = szAppName;
 30 
 31     if (!RegisterClass(&wndclass))
 32     {
 33         MessageBox(NULL, TEXT("Program requires Windows NT!")
 34             , szAppName, MB_ICONERROR);
 35         return 0;
 36     }
 37 
 38     hwnd= CreateWindow(szAppName, TEXT("Alternate and Winding Fill Modes")
 39         , WS_OVERLAPPEDWINDOW
 40         , CW_USEDEFAULT, CW_USEDEFAULT
 41         , CW_USEDEFAULT, CW_USEDEFAULT
 42         , NULL, NULL, hInstance, NULL);
 43 
 44     ShowWindow(hwnd, nShowCmd);
 45     UpdateWindow(hwnd);
 46 
 47     while (GetMessage(&msg, NULL, 0, 0))
 48     {
 49         TranslateMessage(&msg);
 50         DispatchMessage(&msg);
 51     }
 52 
 53     return msg.wParam;
 54 }
 55 
 56 LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 57 {
 58     static POINT aptFigure[10] = {10, 70
 59                                 , 50, 70
 60                                 , 50, 10
 61                                 , 90, 10
 62                                 , 90, 50
 63                                 , 30, 50
 64                                 , 30, 90
 65                                 , 70, 90
 66                                 , 70, 30
 67                                 , 10, 30};
 68     static int cxClient, cyClient;
 69     HDC hdc;
 70     int i;
 71     PAINTSTRUCT ps;
 72     POINT apt[10];
 73 
 74     switch (message)
 75     {
 76     case WM_SIZE:
 77         cxClient = LOWORD(lParam);
 78         cyClient = HIWORD(lParam);
 79         return 0;
 80 
 81     case WM_PAINT:
 82         hdc = BeginPaint(hwnd, &ps);
 83         SelectObject(hdc, GetStockObject(GRAY_BRUSH));
 84 
 85         for (i = 0; i !=10; ++i)
 86         {
 87             apt[i].x = cxClient * aptFigure[i].x / 200;
 88             apt[i].y = cyClient * aptFigure[i].y / 100;
 89         }
 90         SetPolyFillMode(hdc, ALTERNATE);
 91         Polygon(hdc, apt, 10);
 92 
 93         for (i = 0; i != 10; ++i)
 94         {
 95             apt[i].x += cxClient / 2;
 96         }
 97         SetPolyFillMode(hdc, WINDING);
 98         Polygon(hdc, apt, 10);
 99 
100         EndPaint(hwnd, &ps);
101         return 0;
102 
103     case WM_DESTROY:
104         PostQuitMessage(0);
105         return 0;
106     }
107 
108     return DefWindowProc(hwnd, message, wParam, lParam);
109 }

图片 1

Path 方法第二类:辅助的设置或计算

.setFillType(Path.FillType ft) 用来设置图形自相交时的填充算法,其他使用较少;

FillType有4个值:WINDING(默认)、EVEN_ODD、INVERSE_WINDING、INVERSE_EVEN_ODD

WINDING是「全填充」,而EVEN_ODD是「交叉填充」:

图片 2

EVEN_ODD 和 WINDING 的具体原理

EVEN_ODD

即 even-odd rule (奇偶原则):对于平面中的任意一点,向任意方向射出一条射线,这条射线和图形相交的次数(相交才算,相切不算哦)如果是奇数,则这个点被认为在图形内部,是要被涂色的区域;如果是偶数,则这个点被认为在图形外部,是不被涂色的区域。还以左右相交的双圆为例:

图片 3

射线的方向无所谓,同一个点射向任何方向的射线,结果都是一样的,不信你可以试试。

从上图可以看出,射线每穿过图形中的一条线,内外状态就发生一次切换,这就是为什么EVEN_ODD是一个「交叉填充」的模式。

WINDING

即 non-zero winding rule (非零环绕数原则):首先,它需要你图形中的所有线条都是有绘制方向的:

图片 4

然后,同样是从平面中的点向任意方向射出一条射线,但计算规则不一样:以 0 为初始值,对于射线和图形的所有交点,遇到每个顺时针的交点(图形从射线的左边向右穿过)把结果加 1,遇到每个逆时针的交点(图形从射线的右边向左穿过)把结果减 1,最终把所有的交点都算上,得到的结果如果不是 0,则认为这个点在图形内部,是要被涂色的区域;如果是 0,则认为这个点在图形外部,是不被涂色的区域。

图片 5

和EVEN_ODD相同,射线的方向并不影响结果。

所以,我前面的那个「简单粗暴」的总结,对于WINDING来说并不完全正确:如果你所有的图形都用相同的方向来绘制,那么WINDING确实是一个「全填充」的规则;但如果使用不同的方向来绘制图形,结果就不一样了。

图形的方向:对于添加子图形类方法(如Path.addCircle()Path.addRect())的方向,由方法的dir参数来控制,这个在前面已经讲过了;而对于画线类的方法(如Path.lineTo()Path.arcTo())就更简单了,线的方向就是图形的方向。

所以,完整版的EVEN_ODD和WINDING的效果应该是这样的:

图片 6

而INVERSE_EVEN_ODD和INVERSE_WINDING,只是把这两种效果进行反转而已,懂了EVEN_ODD和WINDING,自然也就懂INVERSE_EVEN_ODD和INVERSE_WINDING了,扔物线就不讲了。



图片 7

drawRect(float left, float top, float right, float bottom, Paint paint) 

left,top,right,bottom是矩形四条边相对于xyxy轴的坐标;

两个重载方法drawRect(RectF rect, Paint paint)和drawRect(Rect rect, Paint paint),可以直接填写RectF或Rect对象来绘制矩形;


图片 8图片 9

drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, Paint paint) 绘制弧形或扇形

drawArc()是使用一个椭圆来描述弧形的。left,top,right,bottom描述的是这个弧形所在的椭圆;

startAngle是弧形的起始角度(x 轴的正向,即正右的方向,是 0 度的位置;顺时针为正角度,逆时针为负角度);

sweepAngle是弧形划过的角度;

useCenter表示是否连接到圆心,如果不连接到圆心,就是弧形,如果连接到圆心,就是扇形。

注:通过 userCenter 的 true 或 false  +  Paint 的 stroke或 fill 可以画出 空心扇形、仅描边弧形、实心扇形、封口弧形;



线上箭头表示画线的方向。WINDING模式和ALTERNATE模式都会填充三个封闭的L型区域,号码从1到3。两个更小的内部区域,号码为4和5,在ALTERNATE模式下不被填充。但是在WINDING模式下,号码5的区域会被填充,这是因为区域的内部到达图形的外部必须穿过两条相同方向的线。号码为4的区域不会被填充,因为射线必须穿越两条边框线,但是这两条边框线的绘制方向相反。

drawPoint(float x, float y, Paint paint)

点的大小可以通过paint.setStrokeWidth(width)来设置;

点的形状可以通过paint.setStrokeCap(cap)来设置,端点有圆头 (ROUND)、平头 (BUTT) 和方头 (SQUARE) 三种;

FILL模式下的drawCircle()和drawRect()也能达到相同效果,按偏好选择;


丨一切的开始:onDraw()

    别漏写了super.onDraw()。

丨Canvas.drawXXX() 和 Paint 基础

    Paint.setStyle(Style style)设置绘制模式():Paint.style.FILL、STROKE、FILL_AND_STROKE

    Paint.setColor(int color)设置颜色

    Paint.setStrokeWidth(float width)设置线条宽度

    Paint.setTextSize(float textSize)设置文字大小

    Paint.setAntiAlias(boolean aa)设置抗锯齿开关        可以在创建时Paint paint=new Paint(Paint.ANTI_ALIAS_FLAG);


丨drawBitmap(Bitmap bitmap, float left, float top, Paint paint) 绘制 Bitmap

drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint)

drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)

drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint)



丨drawText(String text, float x, float y, Paint paint) 绘制文字

可以利用Paint设置textSize

drawLine(float startX, float startY, float stopX, float stopY, Paint paint) 画线

起点终点的坐标

本文由金沙澳门官网网址发布于应用资讯,转载请注明出处:第五章 绘图基础(ALTWIND)

相关阅读