旋转控件(一):矩形的平移旋转缩放

之前做了这个东西,一个内部素材加外操作边框,包含基本的移动、缩放、旋转,拉伸,快速定位,十字对齐等操作。常见使用场景如添加马赛克,添加画中画等。感觉比较有意思而且中间也遇到了一些问题就记录一下

先上图:

如图,这次就先讲一下平移、旋转、缩放

如果只是view做平移,有很多种实现方式比如通过layout、动画等。 基于我们的使用场景:知道一个图片的位置信息和旋转角度(中心旋转),就可以将它画出来。所以选择了维护一个rect以及绕中心旋转的角度rotation,这样一些第三方如需要c层操作的地方,直接把这些信息给c层也可以马上明确。

一、如何画

可以看出这个控件其实是一个图片+外面一个框,不过要考虑到旋转的情况,这里我们就借助matrix来做中心旋转。其实相对的就是先把canvas绕图片的中心做一次旋转

  @Override protected void dispatchDraw(Canvas canvas) {
    canvas.save();
    canvas.concat(mRotateMatrix);
    mainDrawable.setBounds((int) mRect.left, (int) mRect.top, (int) mRect.right,
        (int) mRect.bottom);
    mainDrawable.draw(canvas);
    canvas.drawRect(mRect, mPaint);
    drawAnchors(canvas, mRect);
    canvas.restore();
    super.dispatchDraw(canvas);
  }
复制代码

虚线就用paint设置setPathEffect就可以了,虚线框角上的几个角标也是借助rect的位置信息来画出来 比如画右上角的旋转按钮:

if (rotateDrawable != null) {
      //右上角
      rotateDrawable.setBounds(right - drawableWidth, top - drawableHeight, right + drawableWidth,
          top + drawableHeight);
      rotateDrawable.draw(canvas);
    }
复制代码

重点就是去计算上面代码的mRotateMatrix

  private void invalidateMatrix() {
    mRotateMatrix.reset();
    mRotateMatrix.postTranslate(-mRect.centerX(), -mRect.centerY());
    mRotateMatrix.postRotate(mRotation);
    mRotateMatrix.postTranslate(mRect.centerX(), mRect.centerY());
  }
复制代码

这里简单提一下matrix。学过线性代数的都知道矩阵吧,matrix其实就是个3x3的矩阵,里面的元素控制着旋转、缩放、平移、错切。直接new出来的矩阵是一个单位矩阵,描述的就是原来的图形信息,没有做变换。 然后就是矩阵计算不满足交换律,换句话说矩阵的前乘和后乘结果不一样,反应在matrix里面就是pre和post接口效果不一样。 简单点理解就是pre是放在操作队列头,post放在队尾,还有个set会清空整个队列再把它放进去。如果觉得担心记混,推荐就用post接口,符合先进先出的原则,先post的先执行。

二、如何判断什么时候该缩放、旋转或者平移

这里肯定是事件处理相关的了。处于方便,我们在ontouchEvent的时候把操作委托给GestureDetector,在onDown回调时判断点到了哪里,比如旋转、缩放、平移。然后在onScroll回调的时候通过每次的增量dx,dy计算缩放的比例、旋转角度以及移动距离。 在手指头按下时,由于我们知道图片rec的位置信息和角标位置信息,所以通过x和y可以判断是否点到了角标。 但是有个问题是,画的矩形是在旋转过的画布上面,我们手指头的xy是屏幕上的位置,这里对应不起来,会出现旋转后就点不到角标了 为了解决这个问题,手指头按下的point需要利用matix做一次映射。在这里的场景其实就相当于把旋转的信息考虑进去,其实也完全可以自己用三角函数算,但是matrix已经提供这种接口了,而且是调用的c层计算,效率应该更高些。

 final Matrix rotateMatrix = new Matrix();
    //反向旋转回去 抵消canvas的旋转
    rotateMatrix.postTranslate(-mRect.centerX(), -mRect.centerY());
    rotateMatrix.postRotate(-mRotation);
    rotateMatrix.postTranslate(mRect.centerX(), mRect.centerY());
    rotateMatrix.mapPoints(point);
    eventX = point[0];
    eventY = point[1];

    RectF rectF = mRect;
    //hit rotate  右上
    if (Math.abs(rectF.right - eventX) < drawableWidth * 2
        && Math.abs(rectF.top - eventY) < drawableHeight * 2) {
      return HitModes.ROTATE;
    }
复制代码

需要注意的是这里matix的旋转角度和canvas的是相反的,其实就相当于转了n角度,然后又转回去n角度,相当于没有转。然后就可以按照没有旋转的情况判断有没有点到角标。

三、如何进行旋转、缩放、平移

第二步已经判断到用户想要进行什么操作了,接下来就是执行对应的操作了。 平移

先说简单的平移吧,上面说了,我们的场景是一个矩形位置信息+绕中心旋转角度。所以平移其实就是改矩形的位置罢了,直接调rec的offset,然后一定要记得在重新绘制前更新canvas的旋转矩阵

  private void onMove(float dx, float dy) {
    mRect.offset(-dx, -dy);
    invalidateMatrix();
    invalidate();
  }
复制代码

缩放

首先我们要明确一个东西,就是缩放时旋转中心一定是不变的。所以可以算出中心和右下角的距离以及scroll后的中心和右下角的距离算出两个距离的变化当成x的变化。我们这里是等比例缩放,根据比例算出y的变化。 这里做了一个缩放最小的限制,缩放到1.5个角度宽高后就不嫩再缩小了,这样可以保证角标不会挤在一起。

  private void onScale(float dx, float dy) {
    // TODO: 2019/4/8 这里的dx,dy计算需要改进
    float[] pt1 = new float[] { mRect.centerX(), mRect.centerY() };
    float[] pt2 = new float[] { mRect.right, mRect.bottom };
    float[] pt3 = new float[] { mRect.right + dx, mRect.bottom + dy };
    float distance1 = getPointDistance(pt1, pt2);
    float distance2 = getPointDistance(pt1, pt3);
    float distance = distance1 - distance2;
    if (!checkCanScale(distance)) {
      return;
    }
    mRect.inset(-distance, -distance / mRatio);
    invalidateMatrix();
    invalidate();
  }
复制代码

旋转

至于旋转其实也简单,因为旋转时中心也是不变的,类似缩放的操作。根据右上角的旋转角标和中心的角度,以及scroll后右上角和中心的角度,这两个的角度差就是旋转角度。 已知两个点的位置,通过math的atan2函数可以算出角度

  private void onRotate(float triggerX, float triggerY) {
    // TODO: 2019/4/8 这里的dx,dy计算需要改进
    float[] pt1 = new float[] { mRect.centerX(), mRect.centerY() };
    float[] pt2 = new float[] { mRect.right, mRect.top };
    float[] pt3 = new float[] { triggerX, triggerY };
    double angel1 = PointUtil.calculateAngleBetweenPoints(pt2, pt1);
    double angel2 = PointUtil.calculateAngleBetweenPoints(pt3, pt1);
    mRotation = (float) (angel1 - angel2);
    invalidateMatrix();
    invalidate();
  }
复制代码

到这里基本的平移旋转缩放都介绍完了,详细的一些位置计算可以参考demo github.com/dynamicBai/… 给个star鼓励下呗

后面会逐步介绍:拉伸四边的操作(旋转中心会变化)、图片在屏幕上的快速定位和微调、移动时十字辅助线对齐等效果。

转载于:https://juejin.im/post/5cbdc3c4f265da039444aa9e

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MicroDraw图形控件最新版本 最新版本详情咨询:VX:zhangty426 MicroDraw SDK For Windows,支持windows9x/ME/XP/7/8 发行方式:单机版、开发版本、网络版、B/S版本; MicroDraw图形控件是国内专业图形组件(中间件),兼容多种CAD/GIS文件格式和操作方式; MDF,DWG,DXF,DWF,DXB,DGN,QCD,IGS,MDF,PLT,HPGL,MIF。并提供500多种方法和属性供开发者调用。可以用于开发行业(CAD/GIS/GPS)软件(如:建筑CAD,机械CAD,服装CAD等),数据加工软件(CAD/CNC)(如:线切割软件,激光打标软件),管理软件(MIS/PDM/ERP/MRP2/CAPP,图档管理),监控系统(煤矿,电力,电讯,煤气,消防等行业) 运行环境: 操作系统:Windows 9x/me/nt/2k/xp /win7/8 WinServer2003/2008 编程语言:Viusal Basic/Viusal C++/Delphi/ASP/IE/Powerbuild/Viusal Foxpro/C++ Builder/.NET(vb.net c# vc.net)/易语言 文件管理功能: 1. 支持的文件格式包括:BMP、GIF、ICO、TGA、PCX、WBMP、WMF、JPEG、PNG、MNG、TIFF、JBIG、PNM,PPM,PGM、RAS,DXF ,DWF(4.0-6.0)、DWG(2.5-2014) 、IGS, PDF、MIF,PLT,PRN,HPGL/HPGL2、DGN, SHP,CGM; 2. 打开图形图像文件;支持从URL/ftp网上打开,可以将文件保存到ftp上; 3. 打印文件:全部打印和选择打印,打印预览, 打印到文件; 4. 保存和读取自定义格式文件; 5. 将矢量图以指定的尺寸保存为光珊图或者复制到系统粘贴板上; 6. 插入OLE对象,OFFICE文档。 7. 支持模型及其布局文件的浏览。 8. 在不打开文件的情况下,导入文件的某个图层; 9. 对比文件; 10. 支持FTP服务器文件的导入;. 11. 支付PDF文件的浏览和打印; 12. 设置缺省文件格式模式的显示; 打印功能: 1. 直接对当前文件进行打印; 2. 单单的打印框选的元素; 3. 预览打印; 4. 打印出图时附加打印公司标示及其文本信息; 5. 设置水印并在出图时打印水印; 显示功能: 1. 显示平移,自由缩放,框选放大,最佳显示; 2. 回溯显示; 3. 支持显示透明命令操作; 4. 支持三维文件格式显示; 5. 鸟瞰,鹰眼,放大镜功能; 6. 显示网格,显示十字光标; 7. 显示元素外框控制点,同时通过元素控制点对元素进行控制放大、缩小、旋转; 8. 显示或者隐藏元素,图层元素; 9. 设置背景图片 10. 自定义图库文件。 11. 右键菜单功能; 12. 增加了显示水印功能 13. 显示或者隐藏工具条中的指定按钮; 支持事件 1. 支持鼠标移动、点击、双击及滚轮操作事件; 2. 支持键盘的按下、抬起事件; 3. 支持显示绘制事件,用户可以自定义元素显示样式; 4. 支持多种缺省工具操作事件,缺省工具对元素进行操作都会触发相应事件; 5. 保存、打开、打印文件触发相应事件; 6. 文件上传和下载触发相应事件; 7. 选择操作后会触发相应事件; 元素支持功能: 1. 点;直线,折线,射线;圆,圆弧;椭圆,椭圆弧;样条线;函数曲线;填充区域,位图填充;多义线,文字,轨迹文字,剖面线; 2. 文字标注,尺寸标注(水平,竖直,对齐,角度,半径,直径尺寸等); 3. 块插入、图片插入、OLE对象; 4. 多边形; 5. 基本三维元素创建; 6. 图层、文字样式、尺寸样式、线型、剖面线填充样式等; 编辑构造功能: 1. 删除、复制、粘贴、镜像、移动、旋转、延伸、修剪、拖拽、缩放、圆形阵列、矩形阵列; 2. undo /redo 3. 组合、炸开;炸开文字; 其他可选模块: 1. 算法模块,计算图形的长度、面积、体积、交点等; 寻找最大封闭区域、最小 封闭区域、偏移元素;有限元分析算法;图形比较算法;区域求交算法等; 2.数控加工模块,提取几何元素加工数据;优化加工路径; 3.图库功能,自定义图库; 4.视频测绘模块,将cad图纸和视频内容进行叠加比对;

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值