Revit二次开发知识分享(二十四)实现鼠标可视化跟随动画效果

这篇具有很好参考价值的文章主要介绍了Revit二次开发知识分享(二十四)实现鼠标可视化跟随动画效果。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

背景:群友询问:怎样子实现在批量选择完管道,在点击放置标签时,想有一个可视化跟随的动画效果。然后研究了一番,下面提供了一个简易版的实行方案,大家可以参考学习。 源码

目标

实现如下图所示的选择完管件后,鼠标动画跟随效果
Revit二次开发知识分享(二十四)实现鼠标可视化跟随动画效果

关键思路和代码

1.读取当前视图的边框投射到屏幕上的点坐标

其中Rectangle是当前视图边框投影到屏幕上的正方形,可以直接取Left属性和Top属性来定位屏幕的位置

var uiviews = uidoc.GetOpenUIViews();
Rectangle rectangle = uiviews[0].GetWindowRectangle();

2.创建一个完全透明的窗体,只有一个画板控件

<Window
    x:Class="FloatDemo.Views.FloatView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:FloatDemo.Views"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Width="800"
    Height="450"
    Closed="Window_Closed"
    mc:Ignorable="d">
    <Canvas Name="Canvas" />
</Window>

namespace FloatDemo.Views
{
    /// <summary>
    /// FloatView.xaml 的交互逻辑
    /// </summary>
    public partial class FloatView : Window
    {
        public FloatView()
        {
            InitializeComponent();
            new System.Windows.Interop.WindowInteropHelper(this).Owner = Autodesk.Windows.ComponentManager.ApplicationWindow;
            AllowsTransparency = true;
            WindowStyle = WindowStyle.None;
            ResizeMode = ResizeMode.NoResize;
            ShowInTaskbar = false;
            Background = Brushes.Transparent;
            this.SourceInitialized += delegate
            {
                IntPtr hwnd = new WindowInteropHelper(this).Handle;
                uint extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
                SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_TRANSPARENT);
            };

        }
        private void Window_Closed(object sender, EventArgs e)
        {
           
        }
        private const int WS_EX_TRANSPARENT = 0x20;

        private const int GWL_EXSTYLE = -20;

        [DllImport("user32", EntryPoint = "SetWindowLong")]
        private static extern uint SetWindowLong(IntPtr hwnd, int nIndex, uint dwNewLong);

        [DllImport("user32", EntryPoint = "GetWindowLong")]
        private static extern uint GetWindowLong(IntPtr hwnd, int nIndex);
    }
}

其中SourceInitialized事件,是为了使鼠标可以完全透过窗体(百度得到的解决方案)
Revit二次开发知识分享(二十四)实现鼠标可视化跟随动画效果

3.根据Revit中得到的屏幕坐标,修改自定义窗体的位置,使窗体完全覆盖在Revit的视图上

/// <summary>
        /// 视图移动后窗口重新定位
        /// </summary>
        /// <param name="rec"></param>
        public void ChangeLocation(Rectangle rec)
        {
            MainWindows.Left = rec.Left;
            MainWindows.Top = rec.Top;
            MainWindows.Width = rec.Right - rec.Left;
            MainWindows.Height = rec.Bottom - rec.Top;
            MainWindows.Canvas.Children.Clear();
            if (CacheCanvasMousePoint != null)
                CacheCanvasMousePoint = new Point(CanvasMousePoint.X, CanvasMousePoint.Y);
        }

这里也做了一个点位的缓存,大伙可以查看源代码。

4.通过Hook方法,实现对鼠标移动的监控

namespace FloatDemo.Methods
{
    public class MouseHook
    {
        private int hHook;
        public const int WH_MOUSE_LL = 14;
        public Win32Api.HookProc hProc;
        public MouseHook()
        {
        }
        public int SetHook()
        {
            hProc = new Win32Api.HookProc(MouseHookProc);
            hHook = Win32Api.SetWindowsHookEx(WH_MOUSE_LL, hProc, IntPtr.Zero, 0);
            return hHook;
        }
        public void UnHook()
        {
            Win32Api.UnhookWindowsHookEx(hHook);
        }
        private int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam)
        {
            Win32Api.MouseHookStruct MyMouseHookStruct = (Win32Api.MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(Win32Api.MouseHookStruct));
            Point point = new Point(MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y);
            MouseMove?.Invoke(point);
            return Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam);
        }

        public Action<Point> MouseMove { get; set; }
    }
    public class Win32Api
    {
        [StructLayout(LayoutKind.Sequential)]
        public class POINT
        {
            public int x;
            public int y;
        }
        [StructLayout(LayoutKind.Sequential)]
        public class MouseHookStruct
        {
            public POINT pt;
            public int hwnd;
            public int wHitTestCode;
            public int dwExtraInfo;
        }
        public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);
        //安装钩子
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
        //卸载钩子
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern bool UnhookWindowsHookEx(int idHook);
        //调用下一个钩子
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam);
    }
    
}

当然这边仅提供了对鼠标移动的监控,大家自己完善的时候,是可以监控滚轮的操作等,来实现更加完善的操作。

5.通过移动点在窗体绘制线段

拿到鼠标移动点的时候,需要做一个点的平移,得到鼠标在窗体上的点,因为屏幕点的坐标系原点和我们自定义窗体的坐标系原点是不一样的。(后面可以自己扩充:点不在窗体范围时,自动跳出方法,不往下执行)

var uiviews = uidoc.GetOpenUIViews();
Rectangle rectangle = uiviews[0].GetWindowRectangle();
System.Windows.Point tempPoint = new System.Windows.Point(point.X - rectangle.Left, point.Y - rectangle.Top);

拿到鼠标在窗体的点,然后转成Revit坐标系下

/// <summary>
/// 窗体中的点转到Revit中
/// </summary>
/// <param name="point"></param>
/// <param name="uView"></param>
/// <returns></returns>
public static XYZ GetRevitPoint(UIDocument uidoc, System.Windows.Point point)
{
    UIView uView = uidoc.GetOpenUIViews()[0];
    var corners = uView.GetZoomCorners();
    double minX = corners.Min(x => x.X);
    double minY = corners.Min(x => x.Y);
    double maxX = corners.Max(x => x.X);
    double maxY = corners.Max(x => x.Y);
    double resultX = minX + (maxX - minX) * (point.X / FloatWindows.Instance.Width);
    double resultY = minY + (maxY - minY) * (1 - (point.Y / FloatWindows.Instance.Height));
    XYZ result = new XYZ(resultX,resultY,0);
    return result;
}

拿到选择的管线,这里默认是平行的,有特殊情况可以再自行考虑。然后计算得到鼠标的Revit点投影到线上的点,再通过得到的投影点转成窗体点,然后绘制出来。

public void MouseMoveChange(System.Windows.Point point)
        {
            Rectangle rectangle = GetRectangle(_uidoc);
            System.Windows.Point tempPoint = new System.Windows.Point(point.X - rectangle.Left, point.Y - rectangle.Top);
            if (tempPoint.X < 0 || tempPoint.Y < 0) return;
            FloatWindows.Instance.CanvasMousePoint = tempPoint;
            if (!FloatWindows.Instance.PointIsMove()) return;
            FloatWindows.Instance.ChangeLocation(rectangle);
            XYZ movePoint = CanvasPointMethod.GetRevitPoint(_uidoc, FloatWindows.Instance.CanvasMousePoint);
            CanvasPoint moveCanvasPoint = CanvasPointMethod.GetCanvasPoint(_uidoc, movePoint);
            double dd = 0;
            foreach (var pipeLine in _pipeLineList)
            {
                if (!pipeLine.CanProject(movePoint)) continue;
                XYZ proPoint = pipeLine.GetProjectPoint(movePoint);
                XYZ pointMoveDirection = (proPoint - movePoint).Normalize();
                CanvasPoint p2 = CanvasPointMethod.GetCanvasPoint(_uidoc, proPoint);
                CanvasPoint p3 = CanvasPointMethod.GetCanvasPoint(_uidoc, movePoint.Add(pointMoveDirection * dd));
                CanvasPoint p4 = CanvasPointMethod.GetCanvasPoint(_uidoc, movePoint.Add(pointMoveDirection * dd).Add(XYZ.BasisX * 10));
                FloatWindows.Instance.Add(p2, moveCanvasPoint);
                FloatWindows.Instance.Add(p3, p4);
                dd += (300/304.8);
            }
        }
  public class CanvasPointMethod
    {
        /// <summary>
        /// 返回屏幕坐标点
        /// </summary>
        /// <param name="targetPoint"></param>
        /// <param name="uView"></param>
        /// <returns></returns>
        public static CanvasPoint GetCanvasPoint(UIDocument uidoc, XYZ targetPoint)
        {
            UIView uView = uidoc.GetOpenUIViews()[0];
            var corners = uView.GetZoomCorners();
            double minX = corners.Min(x => x.X);
            double minY = corners.Min(x => x.Y);
            double maxX = corners.Max(x => x.X);
            double maxY = corners.Max(x => x.Y);
            CanvasPoint cp1 = new CanvasPoint();
            cp1.Top = 0 + (int)(FloatWindows.Instance.Height * (1 - (targetPoint.Y - minY) / (maxY - minY)));
            cp1.Left = 0 + (int)(FloatWindows.Instance.Width * (targetPoint.X - minX) / (maxX - minX));
            return cp1;
        }
        /// <summary>
        /// 窗体中的点转到Revit中
        /// </summary>
        /// <param name="point"></param>
        /// <param name="uView"></param>
        /// <returns></returns>
        public static XYZ GetRevitPoint(UIDocument uidoc, System.Windows.Point point)
        {
            UIView uView = uidoc.GetOpenUIViews()[0];
            var corners = uView.GetZoomCorners();
            double minX = corners.Min(x => x.X);
            double minY = corners.Min(x => x.Y);
            double maxX = corners.Max(x => x.X);
            double maxY = corners.Max(x => x.Y);
            double resultX = minX + (maxX - minX) * (point.X / FloatWindows.Instance.Width);
            double resultY = minY + (maxY - minY) * (1 - (point.Y / FloatWindows.Instance.Height));
            XYZ result = new XYZ(resultX,resultY,0);
            return result;
        }
    }

6.每次移动,都会删除之前绘制的线,再新建,达到更新的效果。

通过MouseHook类的MouseMove委托来实现。

最后

这里仅提供了一个解决方案,讲述了一个思路,还存在很多需要改进的地方。而且主要还是要看代码文件,这篇文章配合源码来看。如果要积分的话,直接私信我
下载源码文章来源地址https://www.toymoban.com/news/detail-498726.html

到了这里,关于Revit二次开发知识分享(二十四)实现鼠标可视化跟随动画效果的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Kafka 知识点学习【Kafka 学习之24问-第二十四刊】

    🏆作者简介,普修罗双战士,一直追求不断学习和成长,在技术的道路上持续探索和实践。 🏆多年互联网行业从业经验,历任核心研发工程师,项目技术负责人。 🎉欢迎 👍点赞✍评论⭐收藏 Kafka知识专栏学习 Kafka知识云集 访问地址 备注 Kafka知识点(1) https://blog.csdn.net/m

    2024年02月05日
    浏览(43)
  • 鸿蒙开发系列教程(二十四)--List 列表操作(3)

    定义列表项数据结构和初始化列表数据,构建列表整体布局和列表项。 提供新增列表项入口,即给新增按钮添加点击事件。 响应用户确定新增事件,更新列表数据。 列表的删除功能一般进入编辑模式后才可使用,所以需要提供编辑模式的入口。 需要响应用户的选择交互,记

    2024年02月21日
    浏览(41)
  • 第二十四章 开发Productions - ObjectScript Productions - 定义业务服务

    本页介绍如何定义业务服务类。 提示: IRIS® 提供使用特定入站适配器的专用业务服务类,其中之一可能适合需要。如果是这样,则不需要编程。有关部分列表,请参阅 Introducing Interoperability Productions 中的连接选项。 业务服务负责接受来自外部应用程序的请求到 IRIS 。下图显

    2024年02月07日
    浏览(54)
  • Linux驱动开发(十四)---USB驱动开发学习(键盘+鼠标)

    《Linux驱动开发(一)—环境搭建与hello world》 《Linux驱动开发(二)—驱动与设备的分离设计》 《Linux驱动开发(三)—设备树》 《Linux驱动开发(四)—树莓派内核编译》 《Linux驱动开发(五)—树莓派设备树配合驱动开发》 《Linux驱动开发(六)—树莓派配合硬件进行字

    2024年02月08日
    浏览(53)
  • Java版知识付费源码 Spring Cloud+Spring Boot+Mybatis+uniapp+前后端分离实现知识付费平台 +支持二次开发定制

     提供职业教育、企业培训、知识付费系统搭建服务。系统功能包含:录播课、直播课、题库、营销、公司组织架构、员工入职培训等。 提供私有化部署,免费售后,专业技术指导,支持PC、APP、H5、小程序多终端同步,支持二次开发定制,源码交付。   Java版知识付费-轻松

    2024年02月15日
    浏览(50)
  • 鸿蒙开发笔记(二十六):交互事件--触摸,按键,鼠标,焦点

    交互事件按照触发类型来分类,包括触屏事件、键鼠事件和焦点事件。 触屏事件:手指或手写笔在触屏上的单指或单笔操作。 键鼠事件:包括外设鼠标或触控板的操作事件和外设键盘的按键事件。 鼠标事件是指通过连接和使用外设鼠标/触控板操作时所响应的事件。 按键事

    2024年01月24日
    浏览(47)
  • AIGC内容分享(二十):「AI视频生成」技术核心基础知识和模型应用

    目录 何为AI视频? 一、技术发展概况 二、代表模型及应用​​​​​​​ 三、仍存在许多技术难点 「 AI 视频」 通常指的是由人工智能(AI)技术生成或处理的视频。这可能包括使用深度学习、计算机视觉和其他相关技术来改善视频的质量、内容或生成全新的视频内容。一

    2024年01月18日
    浏览(56)
  • Senparc.Weixin SDK 微信平台开发教程(二十四):顺应 AIGC 应用,自动“续航”回复超长文本消息

    GitHub:https://github.com/JeffreySu/WeiXinMPSDK Gitee:https://gitee.com/JeffreySu/WeiXinMPSDK 随着大预言模型应用的进一步流行,以及最大 Token 支持数量的不断上升,自动生成的文本长度也在不断增加。 微信作为国内国民级机器对话的最佳选择,成为了许多机器人首选的交互端口。然而,微信

    2024年02月16日
    浏览(49)
  • 【二十四】springboot使用EasyExcel和线程池实现多线程导入Excel数据

      springboot篇章整体栏目:  【一】springboot整合swagger(超详细 【二】springboot整合swagger(自定义)(超详细) 【三】springboot整合token(超详细) 【四】springboot整合mybatis-plus(超详细)(上) 【五】springboot整合mybatis-plus(超详细)(下) 【六】springboot整合自定义全局异常

    2023年04月08日
    浏览(68)
  • 分享几个Ecshop中二次开发的常见方法

    收货人信息的省市区设成非必选项 一般面向国外用户的ECSHOP商城,可能会有这方面的需求:【将Ecshop中收货人信息的省市区设成非必选项】,其实也就是只留一个“请选择国家”的下拉选择框。 修改相关JS文件 打开 /js/shopping_flow.js 文件,将下面JS代码删除掉 JavaScript Code 复制

    2023年04月16日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包