编程

当前位置:永利皇宫463登录 > 编程 > HN0I3000最优乘车

HN0I3000最优乘车

来源:http://www.makebuLuo.com 作者:永利皇宫463登录 时间:2019-09-12 14:29

图片 1内图层图像图片 2外图层图像

HN0I三千最优乘车 (最短路变形)

版权申明:本篇小说版权归我YJSheep(www.cnblogs.com/yangyaojia)全体,转发请保留原地点!

【试题】为了简化城市国有小车收取工资系统,某城市决定对大非常多的公汽都使用一票制,但鉴于有些公共小车所通过的停车站太多和行程太长,就接纳两票或多票制。经过这种票制革新后,大家坐公汽从二个站到另四个站时,就不得不采用一个好的乘车方案,以使他们的乘车耗费低于。

为了便利于求出最好的乘车方案,大家只要:

l  采取一票制的公家小车,无论从哪些站上车到极度站下车,乘该公汽的成本为1(开销单位)。

l  选择多票制的共用汽车,将实行某个站为关键站;那么,假设某一个人乘该路公汽从A站到B站时,不经过任何关键站的乘车费用为1,而通过K个关键站的乘车花费为K+1;所谓经过关键站是指:乘该路公汽时,该关键站是其途中的二个站,但它不是上车站亦不是下车站;举个例子,某路公汽经过1,2,3,4,*5,6,7,8,9;当中5是关键站,那么,从5站上车到9站下车或从2站上车到5站下车的开支为1,而从4站上车到6站下车的花销将是2。

l  全体国有汽车都是双向行驶的,也即若是公共小车经过的站点有A和B,那么,你能够乘该公汽从A到B或从B到A。

你的职分便是:对于输入文件中付出的公物小车各停车站,和某旅客的源点站A和终点站B,请您编制程序为旅客求出最好的乘车方案,使得她的乘车开销最少。

输入:第1行为N、R、A和B,当中N为城市公共小车停车站的总个数,那一个停车站被统一号码为1、2、……、N;凯雷德为公汽总路数。A为起源站的号子,B为终点站的数码。(1≤N≤一千,1≤冠道≤300,每路公汽的最多站点数为20)。数据里面用空格分开。

第2行到奥迪Q5+1行的每一作为一路公家汽车经过的停车站编号,停车站编号的排列顺序是该路公汽按贰个样子行车顺序依次通过的停车站,如为首要停车站,则其编号的先头有四个*。每行数据里面用空格分开。

出口:从A站到B站所需的最少费用。借使不能够乘那么些集体汽车从A到B,输出-1。

输入输出示例:

INPUT4.TXT

12 4 1 12

1 2 3 *4 5 6 7

1 2 3 8

8 4 5 9

7 6 5 *9 10 11 12

OUTPUT4.TXT

3

解题报告

好稀有的难题,在网络根本找不到的说。

很标准的最短路。对于每一条公共交通线路,我们让内部的每三个站点相互建边,使其权值为票价,注意边界难题,源点与终点为重要站不计入票价中。

用堆优dijkstra即可。

 

#include<bits/stdc++.h>
#define Pair pair<int,int>
#define MAXN 1000+10
#define MAXM 600000+1
using namespace std;
int n,m,num,head[MAXN],s,t,dis[MAXN],v[MAXM];
int pre[MAXN];

int read(int &k)
{
    int in=0,j=0;char c;
    c=getchar();
    for(;c>'9'||c<'0';c=getchar())
    {
        if(c=='n') return 0;
        if(c=='*') j=1;
    }
    for(;c<='9'&&c>='0';c=getchar()) in=in*10+c-'0';
    k=in;
    if(j) return 2;
    return 1;
}


struct Edge{
    int dis,next,to,exi,from;
}edge[MAXM];


void add(int from,int to,int dis)
{
    edge[++num].next=head[from];
    edge[num].to=to;
    edge[num].dis=dis;
    edge[num].from=from;
    head[from]=num;
    edge[num].exi=1;
}
void dij()
{
    memset(dis,0,sizeof(dis));
    memset(v,0,sizeof(v));
    priority_queue<Pair,vector<Pair>,greater<Pair> > h;
    for(int i=1;i<=n;i++) dis[i]=2147483647;
    dis[s]=0;
    h.push(Pair(dis[s],s));
    while(h.size()>0)
    {
        int k=h.top().second;h.pop();
        if(v[k]) continue;
        v[k]=1;
        for(int i=head[k];i;i=edge[i].next)
        if(dis[k]+edge[i].dis<dis[edge[i].to]&&edge[i].exi==1)
        {
            dis[edge[i].to]=dis[k]+edge[i].dis;
            h.push(Pair(dis[edge[i].to],edge[i].to));
            pre[edge[i].to]=edge[i].from;
        }
    }
}

int main()
{
    freopen("bus.in","r",stdin);
    freopen("bus.out","w",stdout);

    scanf("%d%d%d%dn",&n,&m,&s,&t);
    for(int i=1;i<=m;i++)
    {
        int x,o,np=0;int p[MAXN][3],k=1;
        while(1)
        {
            o=read(x);if(o==0) break;
            else if(o==2) p[++np][0]=x,p[np][1]=k,k++,p[np][2]=k;
            else p[++np][0]=x,p[np][1]=p[np][2]=k;
        }
        for(int i=1;i<=np;i++)
        {
            for(int j=1+i;j<=np;j++)
            {

                int money=min( min(abs(p[i][1]-p[j][1]),abs(p[i][2]-p[j][2]))
                ,min(abs(p[i][1]-p[j][2]),abs(p[i][2]-p[j][1])));
                add(p[i][0],p[j][0],money+1);
                add(p[j][0],p[i][0],money+1);

            }
        }
    }

    dij();

    if(dis[t]>=2147483647) printf("-1n");
    else printf("%dn",dis[t]);
    return 0;
}

 

戏马台

perspective = CATransform3DRotate(perspective, CGFloat, 1, 0, 0)perspective = CATransform3DRotate(perspective, CGFloat, 0, 1, 0)

图片 3

图片 4图5.15 内嵌图层施加相反变形

图片 5

让我们用那一个构成函数成立更复杂的变形。我们将依次使用二分一缩放、30度旋转以及向右位移200点。图5.4来得了最终结果。

游记来自蝉游记网址-净空智子

图片 6

结果在图5.8,但它并十分的小像大家想像中的天经地义。

戏马台

有有个别和图5.4不符的是:图像右移距离不是点名的200点,它也同样向下移动实际不是只是平移。其缘由在于你是逐条施加变形的,前的的变形会耳熏目染后边的变形。200点的向右位移被旋转30度然后缩放百分之五十,所以它实际形成斜向下的100点。

图片 7

图片 8图5.12 在容器视图中并排的多个视图

图片 9

既然大家能够在三个维度空间上旋转图层,大家也足以从后面着重它们。假如我们在表5.4中把角度改为M_PI而非现在的M_PI_4,大家将把图片旋转二个半圆,那样它就能够背对镜头。

图片 10

不佳的是,没人能透露矩阵是何许,你得温馨去考查。——Morpheus,The Matrix

戏马台

表5.10 给立方体表面应用动态光影效果import UIKitimport GLKitlet LIGHT_DIRECTON = GLKVector3Make(0, 1, -0.5)let AMBIENT_LIGHT: CGFloat = 0.5class ViewController: UIViewController { @IBOutlet weak var containerView: UIView! var faces: Array<UIView> = [] func getRandomColor() -> UIColor { // 创建随机颜色 let red: CGFloat = CGFloat(arc4random / 255.0 let green: CGFloat = CGFloat(arc4random / 255.0 let blue: CGFloat = CGFloat(arc4random / 255.0 return UIColor(red: red, green: green, blue: blue, alpha: 1) } func createFace(number: NSInteger) -> UIView { // 创建表面视图 let face = UIView(frame: CGRectMake(0, 0, 200, 200)) face.backgroundColor = UIColor.whiteColor() // 创建标签 let label = UILabel(frame: CGRectZero) label.text = number.description label.textColor = getRandomColor() label.font = UIFont.systemFontOfSize // 将标签放在中间 label.sizeToFit() // 用于将标签的bounds大小设为恰好符合 let faceSize = face.bounds.size label.center = CGPointMake(faceSize.width / 2.0, faceSize.height / 2.0) // 将标签加入表面视图 face.addSubview return face } func applyLightingToFace(face: CALayer) { // 增加光线层 let layer = CALayer() layer.frame = face.bounds face.addSublayer // 转换face的变形的矩阵 // GLKMatrix4有和CATransform3D一样的结构 let transform = face.transform let matrix4: GLKMatrix4 = GLKMatrix4Make(Float(transform.m11), Float(transform.m12), Float(transform.m13), Float(transform.m14), Float(transform.m21), Float(transform.m22), Float(transform.m23), Float(transform.m24), Float(transform.m31), Float(transform.m32), Float(transform.m33), Float(transform.m34), Float(transform.m41), Float(transform.m42), Float(transform.m43), Float(transform.m44)) let matrix3: GLKMatrix3 = GLKMatrix4GetMatrix3 // 获得face的正常向量 var normal = GLKVector3Make normal = GLKMatrix3MultiplyVector3(matrix3, normal) normal = GLKVector3Normalize // 获得与光向量的点积 let light = GLKVector3Normalize(LIGHT_DIRECTON) let dotProduct = GLKVector3DotProduct(light, normal) // 设置光线层的透明度 let shadow = 1 + CGFloat(dotProduct) - AMBIENT_LIGHT let color = UIColor(white: 0, alpha: shadow) layer.backgroundColor = color.CGColor } func addFace(index: NSInteger, withTransform transform: CATransform3D) { // 获得表面视图并把它加入容器中 let face = self.faces[index] self.containerView.addSubview // 将表面视图在容器中居中 let containerSize = self.containerView.bounds.size face.center = CGPointMake(containerSize.width / 2.0, containerSize.height / 2.0) // 应用变形 face.layer.transform = transform // 应用光影 self.applyLightingToFace(face.layer) } override func viewDidLayoutSubviews() { // 创建六个表面 for (var i = 1; i <= 6; i++) { let face = createFace faces.append } // 设置容器子视图视图形变 var perspective = CATransform3DIdentity perspective.m34 = -1.0 / 500.0 perspective = CATransform3DRotate(perspective, CGFloat, 1, 0, 0) perspective = CATransform3DRotate(perspective, CGFloat, 0, 1, 0) self.containerView.layer.sublayerTransform = perspective // 添加立方体的表面1 var transform = CATransform3DMakeTranslation(0, 0, 100) self.addFace(0, withTransform: transform) // 添加立方体的表面2 transform = CATransform3DMakeTranslation(100, 0, 0) transform = CATransform3DRotate(transform, CGFloat, 0, 1, 0) self.addFace(1, withTransform: transform) // 添加立方体的表面3 transform = CATransform3DMakeTranslation(0, -100, 0) transform = CATransform3DRotate(transform, CGFloat, 1, 0, 0) self.addFace(2, withTransform: transform) // 添加立方体的表面4 transform = CATransform3DMakeTranslation(0, 100, 0) transform = CATransform3DRotate(transform, CGFloat, 1, 0, 0) self.addFace(3, withTransform: transform) // 添加立方体的表面5 transform = CATransform3DMakeTranslation(-100, 0, 0) transform = CATransform3DRotate(transform, CGFloat, 0, 1, 0) self.addFace(4, withTransform: transform) // 添加立方体的表面6 transform = CATransform3DMakeTranslation(0, 0, -100) transform = CATransform3DRotate(transform, CGFloat, 0, 1, 0) self.addFace(5, withTransform: transform) }}

戏马台

C的数学库(会自行在种种iOS项目中引进)提供了一部分平日倍数的π便于使用,M_PI_4是二个象征π除以4的常量。假诺用弧度思量不方便人民群众,你可以动用如下宏来进行弧度、角度的转移:

戏马台

你大概注意到纵然大家得以望见第多个面上的开关,但按下去后未有用。为啥吗?

戏马台 图片 11

图片 12图5.22 有动态总计光影的立方体

第1天
2014-04-19

图片 13图5.10 大家利用了透视变形的视图

戏马台

图片 14图5.1 CGAffineTransform和CGPoint用来表示矩阵

戏马台

图片 15图5.16 旋转视图符合图5.15中的预期

CALayer有另贰个更变形属性叫做sublayerTransform。那也是八个CATransform3D,但实际不是对其采纳的图层变形,它只影响其子图层。这意味着你可以对多少个容器图层应用透视变形来震慑它的子图层,它的具有子图层都会自动一连透视效果。

碰巧CG前缀所示,CGAffineTransform花色属于Core Graphics框架。Core Graphics是叁个严格的2D绘图API,CGAffineTransform只得用来2D变形(正是只可以用于二维平面)。

专一大家用来角度的值是叁个叫M_PI_4的常量,并不是您或然以为的45。iOS中的全部角度的变形函数都应用弧度而非角度。弧度平日是特定倍数的数学常量π。弧度π等于180度,所以π除以4等于45度。

最终,借使您想结合八个已有的变形矩阵,你可以用如下函数,那将会从丙个已有矩阵中开创三个新的CGAffineTransform矩阵:

大家预料会看出如图5.17的结果。

CALayer有三性格能叫doubleSided用来调节图层的北侧是还是不是被绘制。doubleSided是一个BOOL值且默感到YES。假如你将其设为NO,那么当图层背向镜头,它压根不会被绘制。

可是并非如小编辈预料,大家看见如图5.18的事物。爆发了哪些?大家的内图层还是向左倾斜,也反过来了;它被预期在方块面上啊!

当变形矩阵应用在图层上时,图层矩阵的第个角上的点会独立变形,那会产生贰个新的四边形。CGAffineTransform的“仿射”是指甭管矩阵用了何等值,图层中平行线变形后仍是平行的。CGAffineTransform能够用于任何符合标准的变形。图5.2展现了部分仿射或非仿射的变形:

只须求在三个您以为福利的地方设置透视变形,但它还应该有三个可想而知优点:尽头被设为窗口图层的着力,并非各样子图层独立设置。那意味你能够放肆使用图层的positionframe来移动子图层实际不是先把它们移到显示屏中样再经过变形移位来维持它们的限度不改变。

import UIKitimport GLKitlet LIGHT_DIRECTON = GLKVector3Make(0, 1, -0.5)let AMBIENT_LIGHT: CGFloat = 0.5class ViewController: UIViewController { @IBOutlet weak var containerView: UIView! var faces: Array<UIView> = [] func getRandomColor() -> UIColor { // 创建随机颜色 let red: CGFloat = CGFloat(arc4random / 255.0 let green: CGFloat = CGFloat(arc4random / 255.0 let blue: CGFloat = CGFloat(arc4random / 255.0 return UIColor(red: red, green: green, blue: blue, alpha: 1) } func createFace(number: NSInteger) -> UIView { // 创建表面视图 let face = UIView(frame: CGRectMake(0, 0, 200, 200)) let faceSize = face.bounds.size face.backgroundColor = UIColor.whiteColor() // 创建按钮 let button = UIButton(frame: CGRectMake(0, 0, 100, 100)) button.layer.cornerRadius = 25 button.backgroundColor = UIColor.redColor() button.alpha = 0.1 button.tag = number button.addTarget(self, action: "touchDown:", forControlEvents: UIControlEvents.TouchDown) // 将按钮移到中间 button.center = CGPointMake(faceSize.width / 2.0, faceSize.height / 2.0) // 将按钮加入表面 face.addSubview // 创建标签 let label = UILabel(frame: CGRectZero) label.text = number.description label.textColor = getRandomColor() label.font = UIFont.systemFontOfSize // 将标签放在中间 label.sizeToFit() // 用于将标签的bounds大小设为恰好符合 label.center = CGPointMake(faceSize.width / 2.0, faceSize.height / 2.0) // 将标签加入表面视图 face.addSubview return face } func touchDown(sender: UIButton!) { if (sender.tag == 3) { sender.alpha = 1 } } func applyLightingToFace(face: CALayer) { // 增加光线层 let layer = CALayer() layer.frame = face.bounds face.addSublayer // 转换face的变形的矩阵 // GLKMatrix4有和CATransform3D一样的结构 let transform = face.transform let matrix4: GLKMatrix4 = GLKMatrix4Make(Float(transform.m11), Float(transform.m12), Float(transform.m13), Float(transform.m14), Float(transform.m21), Float(transform.m22), Float(transform.m23), Float(transform.m24), Float(transform.m31), Float(transform.m32), Float(transform.m33), Float(transform.m34), Float(transform.m41), Float(transform.m42), Float(transform.m43), Float(transform.m44)) let matrix3: GLKMatrix3 = GLKMatrix4GetMatrix3 // 获得face的正常向量 var normal = GLKVector3Make normal = GLKMatrix3MultiplyVector3(matrix3, normal) normal = GLKVector3Normalize // 获得与光向量的点积 let light = GLKVector3Normalize(LIGHT_DIRECTON) let dotProduct = GLKVector3DotProduct(light, normal) // 设置光线层的透明度 let shadow = 1 + CGFloat(dotProduct) - AMBIENT_LIGHT let color = UIColor(white: 0, alpha: shadow) layer.backgroundColor = color.CGColor } func addFace(index: NSInteger, withTransform transform: CATransform3D) { // 获得表面视图并把它加入容器中 let face = self.faces[index] self.containerView.addSubview // 将表面视图在容器中居中 let containerSize = self.containerView.bounds.size face.center = CGPointMake(containerSize.width / 2.0, containerSize.height / 2.0) // 应用变形 face.layer.transform = transform // 应用光影 self.applyLightingToFace(face.layer) } override func viewDidLayoutSubviews() { // 创建六个表面 for (var i = 1; i <= 6; i++) { let face = createFace faces.append } // 设置容器子视图视图形变 var perspective = CATransform3DIdentity perspective.m34 = -1.0 / 500.0 perspective = CATransform3DRotate(perspective, CGFloat, 1, 0, 0) perspective = CATransform3DRotate(perspective, CGFloat, 0, 1, 0) self.containerView.layer.sublayerTransform = perspective // 添加立方体的表面1 var transform = CATransform3DMakeTranslation(0, 0, 100) self.addFace(0, withTransform: transform) // 添加立方体的表面2 transform = CATransform3DMakeTranslation(100, 0, 0) transform = CATransform3DRotate(transform, CGFloat, 0, 1, 0) self.addFace(1, withTransform: transform) // 添加立方体的表面4 transform = CATransform3DMakeTranslation(0, 100, 0) transform = CATransform3DRotate(transform, CGFloat, 1, 0, 0) self.addFace(3, withTransform: transform) // 添加立方体的表面5 transform = CATransform3DMakeTranslation(-100, 0, 0) transform = CATransform3DRotate(transform, CGFloat, 0, 1, 0) self.addFace(4, withTransform: transform) // 添加立方体的表面6 transform = CATransform3DMakeTranslation(0, 0, -100) transform = CATransform3DRotate(transform, CGFloat, 0, 1, 0) self.addFace(5, withTransform: transform) // 添加立方体的表面3 transform = CATransform3DMakeTranslation(0, -100, 0) transform = CATransform3DRotate(transform, CGFloat, 1, 0, 0) self.addFace(2, withTransform: transform) }}
CGAffineTansformRotate(CGAffineTansform t, CGFloat angle)CGAffineTansformScale(CGAffineTansform t, CGFloat sx, CGFloat sy)CGAffineTansformTranslate(CGAffineTansform t, CGFloat tx, CGFloat ty)

旋转和缩放变形是分明的,它们各自旋转、缩放贰个向量。而位移变形仅是给向量扩展一定的x和y值,所以借使向量表示点,它会移动点。

图片 16图5.18 实际上绕Y轴反方向旋转的结果

默认下,m34值为0。大家得以对我们的景色设置m34品质二个-1.0/d的值,这里d是想像中的镜头和显示器的相距,用点来衡量。大家什么计算这一个距离应该是多少?大家并没有须要真的划算,大家只需求编造一点。

CGAffineTansformIdentity

它有绕Y轴45度旋转镜头的效果与利益(或许说相对于镜头旋转整个显示器,那取决于你怎么想),然后再五个绕X轴旋转45度。大家前几天从贰个角看立方体,大家得以看到它实际的榜样。

而解决格局也可能有过多:大家能够将除了面3 外的具备面视图的userInteractionEnabled设为NO,那样它们不再接受触摸。也许大家得以轻便的在先后中最后增加大家的面3。无论何种方法,大家都得以点击那几个按键。最后代码如下:

表5.4 绕Y轴旋转图层import UIKitclass ViewController: UIViewController { @IBOutlet weak var layerView: UIView! override func viewDidLoad() { super.viewDidLoad() // 绕Y轴45度旋转图层 let transform = CATransform3DMakeRotation(CGFloat, 0, 1, 0) self.layerView.layer.transform = transform }}
CGAffineTansformConcat(CGAffineTansform t1, CGAffineTansform t2);

UIView能够透过安装transform性子来变形,但就像是全部的布局属性同样,UIViewtransform实际只是贰个CALayer特征的卷入。

尽管我们看不相会4、5、6(因为它们被面1、2、3挡住了),iOS仍予以它们在触摸事件中的第一响应权。当大家品尝触摸面3上的开关的时候,面5或面6拦截了对应的触摸事件,就好像大家在一个平时的2D布局中将它们放到了前头一样。

表5.5 给变形添加透视import UIKitclass ViewController: UIViewController { @IBOutlet weak var layerView: UIView! override func viewDidLoad() { super.viewDidLoad() // 创建一个变形 var transform = CATransform3DIdentity // 应用透视 transform.m34 = -1.0 / 500.0 // 绕Y轴45度旋转图层 transform = CATransform3DRotate(transform, CGFloat, 0, 1, 0) // 应用到图层 self.layerView.layer.transform = transform }}
CATransform3DMakeRotation(CGFloat angle, CGFloat x, CGFloat y, CGFloat z)CATransform3DMakeScale(CGFloat sx, CGFloat sy, CGFloat sz)CATransform3DMakeTranslation(Gloat tx, CGFloat ty, CGFloat tz)

因为镜头并不是真正存在,大家可以率性钦赐它的岗位只要看起来不错就足以。平常500到一千的值功效不错,但你只怕开采或大或小的值大概对一定排列的视图效果更加好。裁减距离值会增添透视效果,所以二个足够小的值会看起来非常扭曲,贰个比十分大的值会看起来和未有透视效果等同。表5.5显得了给大家视图加多透视的代码,图5.10来得了结果。

图片 17图5.5 叁个水准的扭曲

让我们用实施验证那点。表5.7突显了连带代码,图5.16显得了结果。[1]

最少,在您采纳正规的CALayer实例时那是不易的。CALayer有多少个叫CATransformLayer的子类被规划来消除这一主题素材。那将要第6章“特定图层”中等教育授。

其乘法是将CGPoint向量的各样列值去乘CGAffineTransform矩阵中的每一行,然后结果可加得到四个新的CGPoint。那在图中用浅湖蓝值表示;要想矩阵乘法成产,侧边的矩阵的列数必得等于左边矩阵的行数。因而咱们得用单位矩阵来填满它们,那样能够让计算得以开展而不会耳濡目染结果。大家并不真的内需仓库储存额外的值,因为它们并不会更换但在总计时要求它们。

在第3章“图层几何”中,大家用UIViewtransform性格来旋转挂钟的指针,但我们并从未表达其背后的原理。UIViewtransform属性是CGAffineTransform质量,被用于表现二维的团团转、缩放和移动。CGAffineTransform是贰个3行2列的矩阵,它能够乘以二个二维行向量(在此地是CGPoint)来转变其值。

CGAffineTransform一样,CATransform3D是贰个矩阵。但并非八个23矩阵,CATransform3D是一个44矩阵能够直接在3D中变形三个点。

只顾看内图层的负45度旋转是何等平衡外图层的45度旋转的,那致使内图层最后照旧指向正上。

表5.2 用多个函数创建一个组合变形import UIKitclass ViewController: UIViewController { @IBOutlet weak var layerView: UIView! override func viewDidLoad() { super.viewDidLoad() // 创建一个新的变形 var transform = CGAffineTransformIdentity // 缩放50% transform = CGAffineTransformScale(transform, 0.5, 0.5) // 旋转30度 transform = CGAffineTransformRotate(transform, CGFloat / 180.0 * 30.0) // 位移200点 transform = CGAffineTransformTranslate(transform, 200, 0) // 应用到图层上 self.layerView.layer.setAffineTransform(transform) }}

这一章介绍了2D和3D变形。你学了一部分矩阵数学,以及哪些用Core Animation创立3D场景。你看见了背面包车型大巴图层的指南而且领会了您不可能在三个平面图像中四面观察七个物体。最终,这一章演示了当管理触摸事件时,视图或图层在档次中的顺序比它们展现在显示屏上的逐一首要。

图层从北侧看起来何等?如图5.14所示。

翻译代码:

 import UIKit class ViewController: UIViewController {

 @IBOutlet weak var layerView: UIView!

 override func viewDidLoad() { super.viewDidLoad()

 // 45度旋转图层 let transform = CGAffineTransformMakeRotation(CGFloat self.layerView.layer.setAffineTransform(transform) } }
表5.1 用affineTransform来45度旋转图层@interface ViewController ()@property (nonatomic, weak) IBOutlet UIView *layerView;@end@implementation ViewController- viewDidLoad { [super viewDidLoad]; //rotate the layer 45 degrees CGAffineTransform transform = CGAffineTransformMakeRotation; self.layerView.layer.affineTransform = transform; }@end

在等轴测投影中,远处的实体和就近的实体缩放比例相同。这种投影有其用途(如,对于建筑绘图或鸟瞰图以及伪3D录像游戏等),但它不是大家以往想要的。

让我们用叁个例证演示那或多或少。大家会在Interface Builder中并排泄置八个视图。然后通过安装它们容器视图的透视变形,大家得以给它们选拔一样的透视和尽头。看表5.6中绝对于图5.13结实的代码。

图片 18图5.9 CATransform3D中用于透视的m34值

这表示你利用变形的逐个会影响结果;先旋转后位移分化于先位移后旋转。

因为Core Graphics为您提供了不利总结变形矩阵的函数,你相当少需求从来设置CGAffineTransform的值,除非您想创建剪切形变,这在Core Graphics中是未有放置函数的。

图片 19图5.20 朝前体现的立方体

既然如此您早已掌握了3D空间中放置图层的根基,让大家品尝构造贰个3D实体(好呢,从技艺上讲是多个中空物体,但它看起来是由衷的)。大家将用五个单身的视图作为表面来协会三个立方。

为了修补那一点,我们需求修改大家的变形矩阵来在我们在此以前用的转动变形之外引进透视变形(一时也称作Z变形)。Core Animation尚无提须求我们别的函数来安装透视变形,所以我们只好手动修改大家的矩阵。幸运的是,那极度简单易行:CATransform#D的透视效果由矩阵中的m34要素的值调节。m34值被用于计算X和Y值部分缩放远远地离开镜头多少。

那看起来疑似遵照预期的办事的。现在让我们尝试3D的表现。我们将修改代码让它们绕Y轴转动而非Z轴,同期加多透视来看精通爆发了何等。大家不能够用表5.6中的sublayerTransform措施,因为我们内图层不是容器的直接子图层,所以我们应有为它们各自加多透视。

正如您所见,图层是双面包车型大巴;前后是成镜面临称的。固然那并非一个须求想要的特点。固然您的图层有文字或控件,看见它们的镜像会让客户认为困惑。它也可以有地下的萧疏:想像由图层中不透明的立方体组成的实业,为啥大家要浪费GPU周期来绘制大家永远不会看见的北侧?

事实注明即便Core Animation图层存在于3D空间,它们并荒诞不经于同样的3D空间中。种种图层的3D场景是扁平化的。当你从摆正看图层时,你会映注重帘由其子图层创设的3D场景的假象,当你倾斜图层时,你会发觉到3D场景只是画在图层表面包车型大巴。

图片 20图5.17 预期的绕Y轴转动的结果

表5.3 实现扭曲变形import UIKitclass ViewController: UIViewController { @IBOutlet weak var layerView: UIView! func CGAffineTransformMakeShear(x: CGFloat, y: CGFloat) -> CGAffineTransform { var transform = CGAffineTransformIdentity transform.c = -x transform.b = y return transform } override func viewDidLoad() { super.viewDidLoad() // 扭曲45度图层 self.layerView.layer.setAffineTransform(CGAffineTransformMakeShear }}

您今后应该对X轴和Y轴很理解,它们是个别向右和下沿伸的(固然你只怕回想起第3章中介绍说在那只是在iOS上,而在Mac OS上Y轴向上指)。Z轴与它们垂直而且指向镜头。

图片 21图5.3 用仿射变形旋转45度的视图

分开变形是第多种放射变形。它比位移、旋转和缩放少见(那是干吗Core Graphics未有为它提供放置函数),但它不时拾贰分有效。它能够很好地使用于图片。术语就是“扭曲”。表5.3显得了用来私分变形函数的代码。

你或者以为将doubleSided设为NO或是具有支持,因为它会将远的面视图渲染不见,但不幸的是这并不起功用;由于背对镜头而被埋伏的视图仍会阻碍触摸事件(并不像用hidden属性隐藏或安装发光度为0的视图同样),所以禁止使用双面渲染并不可能化解这一主题材料(固然它大概因为质量原因被应用)。

然而译者完结效果与利益如下:

图片 22反方向旋转的外视图和内视图

Core Graphics也提供一组在已有变形之上进一步变形的函数。当你想创制一个单独的既缩放旋转的变形矩阵时特别实用。如下:

正如您在图中所见,绕Z轴旋转相当于我们此前谈到的3D仿射旋转。而绕X轴或Y轴转动会旋转出显示屏的二维平面向镜头倾斜。

翻译自身代码的机能:

图片 23绕Y轴反方向旋转

本条点子的一种达成是表5.10。大家用了GLKit框架来做向量总结(你须要在您的门类中引入这一框架)。每多少个面包车型地铁CATransform3D利用部分指针方法转型为叁个GLKMatrix4,然后那么些3*3_旋转矩阵_使用GLKMatrix4GetMatrix3函数扩充。那么些旋转矩阵是用来支配图层方向的变形的一局地,大家得以用它来计量符合规律向量。

第6章第讲明Core Animation提供的一定的CALayer子类以及它们的分歧用途。

Core Animation提供一些就像是CGAffineTransform矩阵同样的函数来创建组合CATransform3D矩阵。这几个函数和Core Grapihcs很像,但3D位移和缩放提供八个外加的z参数,何况旋转函数接收xyz角度意味着,它们一同整合了旋转轴的向量。

在第4章“视觉特效”中大家讲课了一部分增高图层、内容外观表现的技术。这一章中,我们切磋CGAffineTransform用以图层旋转、位移以及变形。CATransform3d能够将一般的平面矩形(就算是有黑影的圆角矩形)变为三个维度平面。

它将来看起来是像三个立方,但很难识别不相同面包车型地铁总是。Core Animation能够用3D展现图层,但尚未的概念。借使您想让您的立方体看起来更实际,你须要协和加上阴影效果。你能够因此调解差别视图的背影色来促成或对它们提前采取有光线效果的图像。

图5.22呈现了结果。尝试微调LIGHT_DIRECTION向量和AMBIENT_LIGHT值来调治光影效果。

图片 24图5.14 大家视图的南部,显示四个雪人图像的镜像

在切实可行中,尽头常常是您视图的主干,一般大家要在动用里创建真实的透视,尽头应该在显示屏大旨,可能至少有你3D物体的视图中央。

图片 25图5.4 依次使用八个仿射变形的职能

当你操作变形时,创设一个什么都不做的变形往往特别有用,即CGAffineTansform等于零或空。在矩阵的社会风气里,那样二个值被誉为单位矩阵Core Graphics为那几个提供一个十二分有益的常量:

这使得用Core Animation制作复杂3D场景十一分困难。你不能够用图层树构造等级次序化的3D结构,同一场景的别的3D表面必需与同一图层为小家伙,那是因为各个父图层都会扁平化其子图层。

在其行使于containterView前,加上上边几行来旋转perspective变形矩阵。

由于使用xib混编stroyboard较为麻烦,译者使用代码创制表面。

最早的小说继续如下:

为了实现大家例子的目标,立方体在Interface Builder会如图5.19排列。大家得以用代码创制表面,但选取Interface Builder的优势在于我们得以轻便地为各种表面增多、排列子视图。记住这么些外界是日常的客商界面成分,它们得以满含其余视图和控件。它们是完整的且会相互影响,所以在大家把它们折叠成三个立方后还大概会存在。

表5.7 绕Z轴反方向旋转import UIKitclass ViewController: UIViewController { @IBOutlet weak var outerView: UIView! @IBOutlet weak var innerView: UIView! override func viewDidLoad() { super.viewDidLoad() // 外图层45度旋转 let outer = CATransform3DMakeRotation(CGFloat, 0, 0, 1) self.outerView.layer.transform = outer // 内图层-45度旋转 let inner = CATransform3DMakeRotation(CGFloat, 0, 0, 1) self.innerView.layer.transform = inner }}

sublayerTransform属性固然存在三个有3D变形的视图或图层,对它们各样独立应用一样的m34值来确认保证它们在变形前共有二个在显示器大旨的positon。借让你自定义贰个常量或函数来创建并内定它们地点,那整个会一定简单,但一样有限定(举个例子,你不能够由此Interface Builder排列视图)。那是一个越来越好的点子。

让小编举个例证:表5.4的代码应用CATransform3DMakeRotation来绕Y轴转动大家视图的主图层。大家得以把它想成向右倾麦粒肿图,因而大家是以二个角度来看它的。

图片 26图5.21 从一个角看立方体

图片 27图5.7 X、Y和Z轴及绕它们旋转的平面

旋转立方体本人只怕会很劳顿,因为大家不得不独立旋转每一面。三个简短的格局是旋转镜头,这些大家得以能过修改容器视图的sublayerTransform来实现。

CGAffineTransformMakeRotation(CGFloat angle)CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty)

由于译者先前时代并未加多按键,因而更新了弹指间新的代码如下:

即使我们把三个对贰个图层施加变形,而这些图层富含四个被向相反方向变形的图层,会发生什么样?困惑骊?看图5.15。

图片 28图5.11 尽头

图片 29一律透视的七个单身的变形视图

Core Animation概念尽头在被变形的图层anchorPoint处(这一般是图层中央,也大概不是,第3章有详解)。那是在说,尽头在于anchorPoint在视图应用变形的岗位;若是变形包蕴三个将图层移到显示器某处的运动,尽头将要它位移前的职位。

图片 30图5.6 CATransform3D矩阵变形多少个3D点

import UIKitimport GLKitlet LIGHT_DIRECTON = GLKVector3Make(0, 1, -0.5)let AMBIENT_LIGHT: CGFloat = 0.5class ViewController: UIViewController { @IBOutlet weak var containerView: UIView! var faces: Array<UIView> = [] func getRandomColor() -> UIColor { // 创建随机颜色 let red: CGFloat = CGFloat(arc4random / 255.0 let green: CGFloat = CGFloat(arc4random / 255.0 let blue: CGFloat = CGFloat(arc4random / 255.0 return UIColor(red: red, green: green, blue: blue, alpha: 1) } func createFace(number: NSInteger) -> UIView { // 创建表面视图 let face = UIView(frame: CGRectMake(0, 0, 200, 200)) let faceSize = face.bounds.size face.backgroundColor = UIColor.whiteColor() // 创建按钮 let button = UIButton(frame: CGRectMake(0, 0, 100, 100)) button.layer.cornerRadius = 25 button.backgroundColor = UIColor.redColor() button.alpha = 0.1 // 将按钮移到中间 button.center = CGPointMake(faceSize.width / 2.0, faceSize.height / 2.0) // 将按钮加入表面 face.addSubview // 创建标签 let label = UILabel(frame: CGRectZero) label.text = number.description label.textColor = getRandomColor() label.font = UIFont.systemFontOfSize // 将标签放在中间 label.sizeToFit() // 用于将标签的bounds大小设为恰好符合 label.center = CGPointMake(faceSize.width / 2.0, faceSize.height / 2.0) // 将标签加入表面视图 face.addSubview return face } func applyLightingToFace(face: CALayer) { // 增加光线层 let layer = CALayer() layer.frame = face.bounds face.addSublayer // 转换face的变形的矩阵 // GLKMatrix4有和CATransform3D一样的结构 let transform = face.transform let matrix4: GLKMatrix4 = GLKMatrix4Make(Float(transform.m11), Float(transform.m12), Float(transform.m13), Float(transform.m14), Float(transform.m21), Float(transform.m22), Float(transform.m23), Float(transform.m24), Float(transform.m31), Float(transform.m32), Float(transform.m33), Float(transform.m34), Float(transform.m41), Float(transform.m42), Float(transform.m43), Float(transform.m44)) let matrix3: GLKMatrix3 = GLKMatrix4GetMatrix3 // 获得face的正常向量 var normal = GLKVector3Make normal = GLKMatrix3MultiplyVector3(matrix3, normal) normal = GLKVector3Normalize // 获得与光向量的点积 let light = GLKVector3Normalize(LIGHT_DIRECTON) let dotProduct = GLKVector3DotProduct(light, normal) // 设置光线层的透明度 let shadow = 1 + CGFloat(dotProduct) - AMBIENT_LIGHT let color = UIColor(white: 0, alpha: shadow) layer.backgroundColor = color.CGColor } func addFace(index: NSInteger, withTransform transform: CATransform3D) { // 获得表面视图并把它加入容器中 let face = self.faces[index] self.containerView.addSubview // 将表面视图在容器中居中 let containerSize = self.containerView.bounds.size face.center = CGPointMake(containerSize.width / 2.0, containerSize.height / 2.0) // 应用变形 face.layer.transform = transform // 应用光影 self.applyLightingToFace(face.layer) } override func viewDidLayoutSubviews() { // 创建六个表面 for (var i = 1; i <= 6; i++) { let face = createFace faces.append } // 设置容器子视图视图形变 var perspective = CATransform3DIdentity perspective.m34 = -1.0 / 500.0 perspective = CATransform3DRotate(perspective, CGFloat, 1, 0, 0) perspective = CATransform3DRotate(perspective, CGFloat, 0, 1, 0) self.containerView.layer.sublayerTransform = perspective // 添加立方体的表面1 var transform = CATransform3DMakeTranslation(0, 0, 100) self.addFace(0, withTransform: transform) // 添加立方体的表面2 transform = CATransform3DMakeTranslation(100, 0, 0) transform = CATransform3DRotate(transform, CGFloat, 0, 1, 0) self.addFace(1, withTransform: transform) // 添加立方体的表面3 transform = CATransform3DMakeTranslation(0, -100, 0) transform = CATransform3DRotate(transform, CGFloat, 1, 0, 0) self.addFace(2, withTransform: transform) // 添加立方体的表面4 transform = CATransform3DMakeTranslation(0, 100, 0) transform = CATransform3DRotate(transform, CGFloat, 1, 0, 0) self.addFace(3, withTransform: transform) // 添加立方体的表面5 transform = CATransform3DMakeTranslation(-100, 0, 0) transform = CATransform3DRotate(transform, CGFloat, 0, 1, 0) self.addFace(4, withTransform: transform) // 添加立方体的表面6 transform = CATransform3DMakeTranslation(0, 0, -100) transform = CATransform3DRotate(transform, CGFloat, 0, 1, 0) self.addFace(5, withTransform: transform) }}
表5.6 使用sublayerTransformimport UIKitclass ViewController: UIViewController { @IBOutlet weak var containerView: UIView! @IBOutlet weak var layerView1: UIImageView! @IBOutlet weak var layerView2: UIImageView! override func viewDidLoad() { super.viewDidLoad() // 给容器应用透视变形 var perspective = CATransform3DIdentity perspective.m34 = -1.0 / 500.0 self.containerView.layer.sublayerTransform = perspective // layerView1绕Y轴45度旋转 let transform1 = CATransform3DMakeRotation(CGFloat, 0, 1, 0) self.layerView1.layer.transform = transform1 // layerView2绕Y轴45度旋转 let transform2 = CATransform3DMakeRotation(CGFloat, 0, 1, 0) self.layerView2.layer.transform = transform2 }}

图片 31图5.2 仿射和非仿射变形

在切实中,由于透视会招致近大远小。大家恐怕期望远处的视图看起来比左近的视图小,但那并从未生出。我们明日收看的视图是等轴测投影,那是三个提供平行线的3D绘图方法,与我们原先谈起的仿射变形更为相似。

CALayer也可能有四个transform属性,但它的档期的顺序是CATransform3D,而不是CGAffineTransform。大家将要那章后边介绍,但近日实际不是大家关怀的。CALayer中的affineTransform等同于UIView中的transform品质。表5.1呈现了接纳affineTransform属性45度顺时针旋转图层的代码。

当以透视绘制时,远远地离开镜头的实体会变小。若是离的足够远,它们会收缩成贰个点。全体国外的实体最后会交汇于同三个尽头。

在第3章中,大家看了zPosition质量,那允许我们前后移动图层。transform属性(是一个CATransform3D烦死)富含了这一方式,允许大家在三个维度空间移动旋转图层。

那并不是因为iOS不可能精确的传递触摸事件到3D中的开关位置;它事实上是有其一力量的。那个主题素材是视图档案的次序。正如大家在第3章中轻便聊起的,触摸事件依据它们父视图的视图顺序传递,并不是它们在3D空间的Z坐标。当大家给立方体扩大面视图时,大家是以数字顺序增加的,所以面4、5、6会在面3的视图/图层顺序前。

假使您必要创造动态的光影效果,你能够在各类图层上覆盖一个半透明的黑灰阴影图层,然后根据视图方向改造反射率。为了总结阴影图层的光滑度,你要求拿到每一面的例行向量接下来总结它们与想象中光明来源的的向量积。向量积能够告诉您光线源和那一个图层的角度,笔者申明了它应该被照亮的水平。

表5.9 创建立方体import UIKitclass ViewController: UIViewController { @IBOutlet weak var containerView: UIView! var faces: Array<UIView> = [] func getRandomColor() -> UIColor { // 创建随机颜色 let red: CGFloat = CGFloat(arc4random / 255.0 let green: CGFloat = CGFloat(arc4random / 255.0 let blue: CGFloat = CGFloat(arc4random / 255.0 return UIColor(red: red, green: green, blue: blue, alpha: 1) } func createFace(number: NSInteger) -> UIView { // 创建表面视图 let face = UIView(frame: CGRectMake(0, 0, 200, 200)) face.backgroundColor = UIColor.whiteColor() // 创建标签 let label = UILabel(frame: CGRectZero) label.text = number.description label.textColor = getRandomColor() label.font = UIFont.systemFontOfSize // 将标签放在中间 label.sizeToFit() // 用于将标签的bounds大小设为恰好符合 let faceSize = face.bounds.size label.center = CGPointMake(faceSize.width / 2.0, faceSize.height / 2.0) // 将标签加入表面视图 face.addSubview return face } func addFace(index: NSInteger, withTransform transform: CATransform3D) { // 获得表面视图并把它加入容器中 let face = self.faces[index] self.containerView.addSubview // 将表面视图在容器中居中 let containerSize = self.containerView.bounds.size face.center = CGPointMake(containerSize.width / 2.0, containerSize.height / 2.0) // 应用变形 face.layer.transform = transform } override func viewDidLayoutSubviews() { // 创建六个表面 for (var i = 1; i <= 6; i++) { let face = createFace faces.append } // 设置容器子视图视图形变 var perspective = CATransform3DIdentity perspective.m34 = -1.0 / 500.0 self.containerView.layer.sublayerTransform = perspective // 添加立方体的表面1 var transform = CATransform3DMakeTranslation(0, 0, 100) self.addFace(0, withTransform: transform) // 添加立方体的表面2 transform = CATransform3DMakeTranslation(100, 0, 0) transform = CATransform3DRotate(transform, CGFloat, 0, 1, 0) self.addFace(1, withTransform: transform) // 添加立方体的表面3 transform = CATransform3DMakeTranslation(0, -100, 0) transform = CATransform3DRotate(transform, CGFloat, 1, 0, 0) self.addFace(2, withTransform: transform) // 添加立方体的表面4 transform = CATransform3DMakeTranslation(0, 100, 0) transform = CATransform3DRotate(transform, CGFloat, 1, 0, 0) self.addFace(3, withTransform: transform) // 添加立方体的表面5 transform = CATransform3DMakeTranslation(-100, 0, 0) transform = CATransform3DRotate(transform, CGFloat, 0, 1, 0) self.addFace(4, withTransform: transform) // 添加立方体的表面6 transform = CATransform3DMakeTranslation(0, 0, -100) transform = CATransform3DRotate(transform, CGFloat, 0, 1, 0) self.addFace(5, withTransform: transform) }}

让我们用三个简便的体系来演示这几个函数的功用。大家从三个粗略的视图开端,给它丰盛多少个45度的旋转换形。

不,它实在是道理当然是那样的的。视图看起来窄了是因为大家斜斜的看它,所以只有个别面前蒙受镜头。它看起来不得法的案由是从未透视

表5.8 绕Y轴反方向旋转override func viewDidLoad() { super.viewDidLoad() // 外图层45度旋转 var outer = CATransform3DIdentity outer.m34 = -1.0 / 500.0 outer = CATransform3DRotate(outer, CGFloat, 0, 1, 0) self.outerView.layer.transform = outer // 内图层-45度旋转 var inner = CATransform3DIdentity inner.m34 = -1.0 / 500.0 inner = CATransform3DRotate(inner, CGFloat, 0, 1, 0) self.innerView.layer.transform = inner}

由此,你会临时看见贰个二维变形被代表成33的矩阵(而不是23)。你也会时时看见当向量值竖直叠在协同临时间,那一个矩阵以2行3列的格式表示。那被称为列主序格式。咱们在图5.第11中学浮现的是行主序格式。任何你欢快的象征方式都以足以的。

#define RADIANS_TO_DEGREES / M_PI * 180.0)#define DEGREES_TO_RADIANS / 180.0 * M_PI)

小编们的立方体从这些角度看并不刚强;它看起来就好像星型。为了科学的展现它,我们须求从一个不均等的思想看它。

它起来压根不疑似旋转了;它看起来更疑似使用缩放变形水平回退了。大家做错了吗?

图片 32图5.8 一个绕Y轴转动45度的视图

这看似于您在玩3D游戏时倾斜显示屏。你可能在您游戏中看见了一面墙,但倾斜荧屏并不能够令你四下调查这面墙。显示器上的现象并不随你看的角度不一致而改动;图层内容也是大同小异的。

图片 33未点击前图片 34图5.23 今后背面视图不会阻碍按键,大家能够点击它

矩阵数学的完全解释超过了本书的限制,倘诺您对矩阵不是曾经打探,变形矩阵的定义大概有一些可怕 。幸运的是,Core Graphics提供了部分放置函数来直接协会简单变形,那无需开拓者实行其余数学总结。上面包车型大巴函数每种都足以成立三个新的CGAffineTransform矩阵:

当你改动图层的position,你也改动了界限地点。当你管理3D时应当牢记那或多或少。如若您想改换某图层的m34值来使其看起来疑似3D的,你应该将它放在显示屏中央然后利用移动(并非改换它的position)来移至最后的职分,这样它才干够和显示器上的别的实体有一块的尽头。

逻辑上的话,借使内图层和外图层有相反的变形(在那边,是绕Z轴的团团转),我们或然感到那多个变形会相互平衡。

本文由永利皇宫463登录发布于编程,转载请注明出处:HN0I3000最优乘车

关键词:

上一篇:没有了

下一篇:Alamofire源码解读