简记:
CGAffineTransformMake(a,b,c,d,tx,ty)
ad缩放bc旋转tx,ty位移,基础的2D矩阵
公式
x=ax+cy+tx
y=bx+dy+ty
1.矩阵的基本知识:
struct CGAffineTransform
{
CGFloat a, b, c, d;
CGFloat tx, ty;
};
CGAffineTransform CGAffineTransformMake (CGFloat a,CGFloat b,CGFloat c,CGFloat d,CGFloat tx,CGFloat ty);
为了把二维图形的变化统一在一个坐标系里,引入了齐次坐标的概念,即把一个图形用一个三维矩阵表示,其中第三列总是(0,0,1),用来作为坐标系的标准。所以所有的变化都由前两列完成。
以上参数在矩阵中的表示为:
|a b 0|
|c d 0|
|tx ty 1|
运算原理:原坐标设为(X,Y,1);
|a b 0|
[X,Y, 1] |c d 0| = [aX + cY + tx bX + dY + ty 1] ;
|tx ty 1|
通过矩阵运算后的坐标[aX + cY + tx bX + dY + ty 1],我们对比一下可知:
第一种:设a=d=1, b=c=0.
[aX + cY + tx bX + dY + ty 1] = [X + tx Y + ty 1];
可见,这个时候,坐标是按照向量(tx,ty)进行平移,其实这也就是函数
CGAffineTransform CGAffineMakeTranslation(CGFloat tx,CGFloat ty)的计算原理。
第二种:设b=c=tx=ty=0.
[aX + cY + tx bX + dY + ty 1] = [aX dY 1];
可见,这个时候,坐标X按照a进行缩放,Y按照d进行缩放,a,d就是X,Y的比例系数,其实这也就是函数
CGAffineTransform CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)的计算原理。a对应于sx,d对应于sy。
第三种:设tx=ty=0,a=cosɵ,b=sinɵ,c=-sinɵ,d=cosɵ。
[aX + cY + tx bX + dY + ty 1] = [Xcosɵ - Ysinɵ Xsinɵ + Ycosɵ 1] ;
可见,这个时候,ɵ就是旋转的角度,逆时针为正,顺时针为负。其实这也就是函数
CGAffineTransform CGAffineTransformMakeRotation(CGFloat angle)的计算原理。angle即ɵ的弧度表示。
2.利用上面的变换写一个UIImage矩阵变换的例子:
下面是一个关于image的矩阵运算的例子,无外乎是运用以上三种变换的组合,达到所定义的效果
//UIImageOrientation的定义,定义了如下几种变换 typedef enum { UIImageOrientationUp, // default orientation UIImageOrientationDown, // 180 deg rotation UIImageOrientationLeft, // 90 deg CCW UIImageOrientationRight, // 90 deg CW UIImageOrientationUpMirrored, // as above but image mirrored along other axis. horizontal flip UIImageOrientationDownMirrored, // horizontal flip UIImageOrientationLeftMirrored, // vertical flip UIImageOrientationRightMirrored, // vertical flip } UIImageOrientation; //按照UIImageOrientation的定义,利用矩阵自定义实现对应的变换; -(UIImage *)transformImage:(UIImage *)aImage { CGImageRef imgRef = aImage.CGImage; CGFloat width = CGImageGetWidth(imgRef); CGFloat height = CGImageGetHeight(imgRef); CGAffineTransform transform = CGAffineTransformIdentity; CGRect bounds = CGRectMake(0, 0, width, height); CGFloat scaleRatio = 1; CGFloat boundHeight; UIImageOrientation orient = aImage.imageOrientation; switch(UIImageOrientationLeftMirrored) { case UIImageOrientationUp: transform = CGAffineTransformIdentity; break; case UIImageOrientationUpMirrored: transform = CGAffineTransformMakeTranslation(width, 0.0); transform = CGAffineTransformScale(transform, -1.0, 1.0); //沿y轴向左翻 break; case UIImageOrientationDown: transform = CGAffineTransformMakeTranslation(width, height); transform = CGAffineTransformRotate(transform, M_PI); break; case UIImageOrientationDownMirrored: transform = CGAffineTransformMakeTranslation(0.0, height); transform = CGAffineTransformScale(transform, 1.0, -1.0); break; case UIImageOrientationLeft: boundHeight = bounds.size.height; bounds.size.height = bounds.size.width; bounds.size.width = boundHeight; transform = CGAffineTransformMakeTranslation(0.0, width); transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0); break; case UIImageOrientationLeftMirrored: boundHeight = bounds.size.height; bounds.size.height = bounds.size.width; bounds.size.width = boundHeight; transform = CGAffineTransformMakeTranslation(height, width); transform = CGAffineTransformScale(transform, -1.0, 1.0); transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0); break; case UIImageOrientationRight: //EXIF = 8 boundHeight = bounds.size.height; bounds.size.height = bounds.size.width; bounds.size.width = boundHeight; transform = CGAffineTransformMakeTranslation(height, 0.0); transform = CGAffineTransformRotate(transform, M_PI / 2.0); break; case UIImageOrientationRightMirrored: boundHeight = bounds.size.height; bounds.size.height = bounds.size.width; bounds.size.width = boundHeight; transform = CGAffineTransformMakeScale(-1.0, 1.0); transform = CGAffineTransformRotate(transform, M_PI / 2.0); break; default: [NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"]; } UIGraphicsBeginImageContext(bounds.size); CGContextRef context = UIGraphicsGetCurrentContext(); if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) { CGContextScaleCTM(context, -scaleRatio, scaleRatio); CGContextTranslateCTM(context, -height, 0); } else { CGContextScaleCTM(context, scaleRatio, -scaleRatio); CGContextTranslateCTM(context, 0, -height); } CGContextConcatCTM(context, transform); CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef); UIImage *imageCopy = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return imageCopy; }
参考:
https://developer.apple.com/library/ios/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_affine/dq_affine.html
1、CGRectInset
CGRect CGRectInset ( CGRect rect, CGFloat dx, CGFloat dy );
该结构体的应用是以原rect为中心,再参考dx,dy,进行缩放或者放大。
测试:
CGRect rect = CGRectMake(10.0, 10.0, 100.0, 100.0); CGRect rectToDraw = CGRectInset(rect, 10.0, 10.0); NSLog(@"==%@", NSStringFromCGRect(rectToDraw)); 结果为:“=={{20.0, 20.0}, {80.0, 80.0}}” CGRect rect = CGRectMake(10.0, 10.0, 100.0, 100.0); CGRect rectToDraw = CGRectInset(rect, -10.0, -10.0); NSLog(@"==%@", NSStringFromCGRect(rectToDraw)); 结果为:“=={{0.0, 0.0}, {120.0, 120.0}}”
2、CGRectOffset
CGRect CGRectOffset( CGRect rect, CGFloat dx, CGFloat dy );
相对于源矩形原点rect(左上角的点)沿x轴和y轴偏移, 再rect基础上沿x轴和y轴偏移
测试:
CGRect rect = CGRectMake(10.0, 10.0, 100.0, 100.0); CGRect rectToDraw = CGRectOffset(rect, 12.0, 12.0); NSLog(@"==%@", NSStringFromCGRect(rectToDraw)); 结果为:“=={{22.0, 22.0}, {100.0, 100.0}}”
3、frame和dounds
frame和bounds是UIView中的两个属性(property)。
- (CGRect)frame { return CGRectMake(self.frame.origin.x,self.frame.origin.y,self.frame.size.width,self.frame.size.height); } - (CGRect)bounds { return CGRectMake(0,0,self.frame.size.width,self.frame.size.height); }
frame指的是:该view在父view坐标系统中的位置和大小。(参照点是父亲的坐标系统)
bounds指的是:该view在本身坐标系统中 的位置和大小。(参照点是本身坐标系统)
关于httpClient的个别字符乱码
近期在做抓取的工作,登录到别人的网站上获取页面的信息,解析之后封装成自己的东西。
遇到一个问题,httpclient的post方法实现的连接网页,后来解析时有一个字出现了乱码。先附上我的代码:
public String getCourse(String sessionId) throws ClientProtocolException,
IOException {
HttpClient client = new DefaultHttpClient();
String url = "http://218.195.96.24/Jwmis/znpk/Pri_StuSel_rpt.aspx";
HttpPost post1 = new HttpPost(url);
String year = "";
List<NameValuePair> params = Lists.newArrayList();
int currentYear = DateUtil.getYear();
int currentMonth = DateUtil.getMonth();
if (currentMonth < 9) {
year = (currentYear - 1) + "1";
} else {
year = currentYear + "0";
}
// String year = CrawlerConfigUtil.SHANXILIGONG_YEAR;//
// 陕西理工的课表查询年份写在配置文件
params.add(new BasicNameValuePair("Sel_XNXQ", year));// 年份
params.add(new BasicNameValuePair("px", "1"));
params.add(new BasicNameValuePair("rad", "1"));
params.add(new BasicNameValuePair("Submit01", "检索"));
post1.setHeader("Content-Type", "application/x-www-form-urlencoded");
post1.setHeader("Cookie", "ASP.NET_SessionId=" + sessionId);
post1.setHeader(
"User-Agent",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:24.0) Gecko/20100101 Firefox/24.0");
//设置请求的编码为utf-8
client.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "utf-8");
//设置请求中传递参数的编码
post1.setEntity(new UrlEncodedFormEntity(params,"gb2312"));
HttpResponse response1 = client.execute(post1);
HttpEntity entity1 = response1.getEntity();
//设置响应的编码为gbk
String result1 = EntityUtilsl.toString(entity1,"GBK");
return result1;
}
这里返回的result1,不管怎么去设置请求编码,请求参数编码,还有响应的编码,都有个别字符编码的问题。最终找到一种,分享出来给大家,希望对需要的人有帮助。
将
//设置响应的编码为gbk
String result1 = EntityUtilsl.toString(entity1,"GBK");
更改为:byte[] bytearray = EntityUtils.toByteArray(entity1);
String result1 = new String(bytearray, "gbk");
就是说先将其转为byte[],然后再转为字符串。就可以解决问题了。