CAD数据文件格式DXF部分实体(圆弧、椭圆、凸度)解析[原理讲解+公式推导+java实现]

news2025/1/12 3:25:45

文章目录

  • CAD图像读取与显示说明
  • 官方实体说明
  • 实体
    • 圆弧
      • dxf记录信息
      • 代码实现
      • 测试
    • 优化多段线的凸度
      • dxf记录信息
      • 代码实现
      • 测试
    • 椭圆
      • dxf记录信息
      • 代码实现
      • 测试
  • 引用
    • 图片引用
    • 文章引用

CAD图像读取与显示说明

  如果想要开发一个可以读取dxf图像的软件,为了方便图像在软件中的绘制,往往会将图形进行离散称为一系列点,然后将一系列点按照顺序相连即可绘制出图形。

在这里插入图片描述

CAD界面

在这里插入图片描述

软件系统界面

  软件系统界面的图形正是通过离散之后的点集绘制而成的,通过观察上面的两个图,可以发现用肉眼几乎看不出差异,说明通过连接离散点的方式来绘制图形在日常应用中绰绰有余。本文主要讲解一下一些复杂图形实体的离散。

官方实体说明

实体中文文档说明

实体

圆弧

dxf记录信息

在这里插入图片描述
看到上面的信息,你是不是已经笑出声来,“这不是小学二年级的知识吗,简单,咔咔两下解决”
在这里插入图片描述

代码实现

    /**
     * 离散圆弧
     * 注意:起始角度、终止角度需要传入弧度制
     *
     * @param centerX
     * @param centerY
     * @param radius
     * @param startRadian 起始弧度
     * @param endRadian 终止弧度
     * @param discreteRadian 离散弧度,每隔多少绘制一个点
     * @param xList 记录离散点集的x坐标
     * @param yList 记录离散点集的y坐标
     */
    private void discreteArc(double centerX, double centerY, double radius, double startRadian, double endRadian, double discreteRadian,
                             List<Float> xList, List<Float> yList) {
        if (endRadian < startRadian) {
            endRadian += 2 * Math.PI;
        }
        double radian = startRadian;
        while (radian < endRadian) {
            float tempX = (float) (centerX + radius * Math.cos(radian));
            float tempY = (float) (centerY + radius * Math.sin(radian));
            xList.add(tempX);
            yList.add(tempY);
            radian += discreteRadian;
        }
        //添加最终的点
        float tempX = (float) (centerX + radius * Math.cos(endRadian));
        float tempY = (float) (centerY + radius * Math.sin(endRadian));
        xList.add(tempX);
        yList.add(tempY);
    }

测试

在这里插入图片描述
在这里插入图片描述

优化多段线的凸度

dxf记录信息

在这里插入图片描述
  为了用户可以在绘制图形的时候可以一气呵成,CAD为用户提供了优化多段线,优化多段线中也可以绘制圆弧,但是这里可没有告诉我们圆弧的圆心,周长,圆弧起始角度和终止角度这些,只给了一个凸度信息。
在这里插入图片描述

脑瓜疼
  如何根据凸度推导出圆弧的圆心和半径,可以参考大佬的文章[已知圆弧的起点端点和凸度计算圆心](https://blog.csdn.net/jiangyb999/article/details/89366912)

在这里插入图片描述

根据所引用文章可知最终结论

  那至于要怎么离散呢,如果求出了圆弧的信息了,那离散的方式直接使用上面所提到的圆弧离散方法即可
在这里插入图片描述

代码实现

/**
     * 获取圆弧的圆心、起点角度、终点角度
     *
     * @param x1
     * @param y1
     * @param x2
     * @param y2
     * @param convexity 凸度:圆弧段四分之一夹角的正切值;凸度为0表示直线段;凸度为1表示半圆;凸度大于0,向里面凹;凸度小于0,向外面凸
     * @return
     */
    private double[] getArcMessage(double x1, double y1, double x2, double y2, double convexity) {
        double b = (1.0 / 2) * (1.0 / convexity - convexity);

        计算圆弧圆心
        //圆心坐标
        double centerX = 0.5 * ((x1 + x2) - b * (y2 - y1));
        double centerY = 0.5 * ((y1 + y2) + b * (x2 - x1));

        计算起点和终点所对应的角度
        double startRadian = MathUtil.getRadianByPoint(x1 - centerX, y1 - centerY);
        double endRadian = MathUtil.getRadianByPoint(x2 - centerX, y2 - centerY);
        if (convexity < 0) {
            double temp = startRadian;
            startRadian = endRadian;
            endRadian = temp;
        }

        计算圆弧半径
        double radius = MathUtil.getDistanceOfTwoPoint(x1, y1, centerX, centerY);

        存储圆弧信息
        double[] message = new double[5];
        message[0] = centerX;
        message[1] = centerY;
        message[2] = radius;
        message[3] = startRadian;
        message[4] = endRadian;

  /*      System.out.println("根据两点及其之间的凸度获取圆弧信息-------------------------------------------------------------------------------------");
        System.out.println("x1:" + x1 + ";y1:" + y1 + ";x2:" + x2 + ";y2:" + y2 + ";convexity:" + tempConvexity);
        System.out.println("centerX:" + centerX + ";centerY:" + centerY + ";radius:" + radius + ";startDegree:" + Math.toDegrees(startRadian) + ";endDegree:" + Math.toDegrees(endRadian));
        System.out.println("凸度解析完成---------------------------------------------------------------------------------------------------------");
        System.out.println();*/

        return message;
    }

   MathUtil.getRadianByPoint:获取一个向量和(1,0)向量的夹角(弧度制)
在这里插入图片描述

   /**
     * 已知 x、y,求角度 0,2PI
     * 获取(x,y)与x轴正方向(1,0)的夹角
     *
     * @param x
     * @param y
     * @return
     */
    public static double getRadianByPoint(double x, double y) {
        double acos = Math.acos(x / Math.sqrt(x * x + y * y));
        double radian = y > 0 ? acos : (2 * Math.PI - acos);
        if (radian < 0 || radian > 2 * Math.PI) {
            System.out.println("radian:" + radian);
            System.out.println(1 / 0);
        }
        return radian;
    }

  MathUtil.getDistanceOfTwoPoint:获取两点之间的直线距离

 /**
     * 获取两个点之间的距离
     *
     * @return
     */
    public static double getDistanceOfTwoPoint(double x1, double y1, double x2, double y2) {
        return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
    }

测试

在这里插入图片描述
在这里插入图片描述

椭圆

dxf记录信息

在这里插入图片描述
  看完上面的信息,你可能会一脸疑惑,心想:“啥呀这是,长轴端点是啥子哦,高中也mei学啊”

在这里插入图片描述
  高中的椭圆都是老老实实趴在坐标原点,但是CAD的椭圆因为要满足更多的奇形怪状的图形,于是身法需要飘忽不定,不讲武德,莫急,待老夫降伏它。

在这里插入图片描述
  相较于中心的长轴端点其实就是(x,y)=(x2-x1,y2-y1)(别问我怎么知道的,我是在CAD画图然后反推出来的,宝宝心里苦),这下是不是豁然开朗了,至于位置椭圆不是水平的,圆形也不在坐标原点。只需要先将椭圆的位置掰正,就可以调用椭圆公式了,最后再将得到的离散点坐标通过旋转和平移即可回到原位,不说了 ,直接操作一手代码。

代码实现

  /**
     * 离散椭圆
     * 注意:需要传入弧度
     *
     * @param centerX        椭圆圆心
     * @param centerY        椭圆圆心
     * @param axisDirectionX 相较于中心的长轴端点x坐标
     * @param axisDirectionY 相较于中心的长轴端点y坐标
     * @param aspectRatio    短轴/长轴
     * @param startRadian    起始弧度 (对于闭合椭圆,该值为 0.0)
     * @param endRadian      终止弧度 (对于闭合椭圆,该值为 2pi)
     * @param discreteRadian 离散弧度
     * @param xListList
     * @param yListList
     */
    private void discreteEllipse(float centerX, float centerY, float axisDirectionX, float axisDirectionY, float aspectRatio, float startRadian, float endRadian, double discreteRadian,
                                 List<List<Float>> xListList, List<List<Float>> yListList) {
        List<Float> xList = new ArrayList<>();
        List<Float> yList = new ArrayList<>();

        //长轴长度
        double a = Math.sqrt(Math.pow(axisDirectionX, 2) + Math.pow(axisDirectionY, 2));
        //短轴长度
        double b = aspectRatio * a;
        //计算椭圆端点偏转角度(0,360)
        double degree = Math.toDegrees(MathUtil.getRadianByPoint(axisDirectionX, axisDirectionY));
        //重新处理startRadian和endRadian
        startRadian = (float) Math.toRadians(Math.toDegrees(startRadian));
        endRadian = (float) Math.toRadians(Math.toDegrees(endRadian));

        double radian = startRadian;
        while (radian < endRadian) {
            double x = centerX + a * Math.cos(radian);
            double y = centerY + b * Math.sin(radian);
            //将坐标旋转 degree
            double[] rotate = MathUtil.rotate(x, y, centerX, centerY, degree);
            xList.add((float) rotate[0]);
            yList.add((float) rotate[1]);
            radian += discreteRadian;
        }
        //添加最终的点
        double x = centerX + a * Math.cos(endRadian);
        double y = centerY + b * Math.sin(endRadian);
        //将坐标旋转 degree
        double[] rotate = MathUtil.rotate(x, y, centerX, centerY, degree);
        xList.add((float) rotate[0]);
        yList.add((float) rotate[1]);
        xListList.add(xList);
        yListList.add(yList);
    }

  旋转方法 MathUtil.rotate

 /**
     * 将(x1,y1)绕着(x2,y2)逆时针旋转rotateDegree
     *
     * @param x1
     * @param y1
     * @param x2
     * @param y2
     * @param rotateDegree
     * @return
     */
    public static double[] rotate(double x1, double y1, double x2, double y2, double rotateDegree) {
        double[] arr = new double[2];
        //根据角度求弧度
        double radian = (rotateDegree * 1.0 / 180) * Math.PI;
        //旋转
        arr[0] = (x1 - x2) * Math.cos(radian) - (y1 - y2) * Math.sin(radian) + x2;
        arr[1] = (y1 - y2) * Math.cos(radian) + (x1 - x2) * Math.sin(radian) + y2;

        return arr;
    }

测试

在这里插入图片描述
在这里插入图片描述

引用

图片引用

[脑瓜疼表情包]:脑瓜疼
[一脸疑惑表情包]:一脸疑惑

文章引用

已知圆弧的起点端点和凸度计算圆心:https://blog.csdn.net/jiangyb999/article/details/89366912

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/22506.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

优秀开源项目解读(六

一、Piggy Metrics介绍 PiggyMetrics是一个模拟的个人记账理财的应用&#xff0c;原作者称其为一个端到端的微服务PoC(Proof of Concept)&#xff0c;也就是说他开发这个是为了验证微服务架构和Spring Cloud技术栈。PiggyMetrics目前在github上有超过12k星&#xff0c;是学习微…

安卓讲课笔记5.6 列表视图

文章目录零、本讲学习目标一、导入新课二、新课讲解&#xff08;一&#xff09;列表视图概述1、继承关系图2、列表视图API文档3、列表视图四要素4、四种常用适配器&#xff08;二&#xff09;数组适配器1、数组适配器API文档2、数据适配器继承关系图3、数组适配器构造方法&…

第3章 定义内存缓存和log4net日志中间件

006 ICaching、MemoryCaching、SqlSugarMemoryCacheService 、MemoryCacheSetup Icaching&#xff1a;继承该接口的具体实现类&#xff0c;用于把内存缓存中间件实例注入到内置容器中&#xff0c;为实体实例的缓存数据交互操作提供内存管理操作支撑。 MemoryCaching&#xff1a…

了解Redis之命令操作

目录 1、Redis简介 2、Redis安装 2.1解压redis 2.2.安装gcc 2.3.编译redis 2.4.检测安装情况 2.5.修改redis.conf文件 2.6启动redis 2.7.测试redis启动是否成功 3、Redis命令 3.1.String 3.2.Hash 3.3.List 3.4.set 1、Redis简介 Redis是一个开源&#xff08;BSD许可…

第二次上机作业 大连理工大学

某百货公司6月份各天的销售数据如下:【数据】 x = c(257,276,301,252,238,310,246,236,265,278,271,292,261,281,301,274,267,280,291,258,272,284,268,303,273,263,301,249,269,295)计算该百货公司日销售额的中位数、四分位数和众数 median(x)# 中位数 quantile(x) # 四分位…

详解TCP为什么不能是两次握手

三次握手的过程 注意不要遗漏全双工下两缓存&#xff08;读/写缓存&#xff09;的分配和变量的分配。 CLOSED&#xff1a;表示初始状态。 LISTEN&#xff1a;该状态表示服务器端的某个SOCKET处于监听状态&#xff0c;可以接受连接。 SYN_SENT&#xff1a;这个状态与SYN_RCVD遥…

极限学习机和自适应稀疏表示算法 (EA-SRC)(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

梦开始的地方—— C语言动态内存管理(malloc+calloc+realloc+free)

文章目录动态内存管理1.为什么需要动态内存分配&#xff1f;2. 动态内存函数malloc&freecallocrealloc3. 常见的动态内存错误对NULL解引用对动态开辟空间的越界访问对非动态开辟内存使用free释放使用free释放一块动态开辟内存的一部分对同一块动态内存多次释放动态开辟内存…

Vue实现模糊查询:filter()

需求&#xff1a;在输入框里输入内容&#xff0c;包含相关内容的值被筛选出来&#xff1b; 图示&#xff1a; 最初的代码&#xff1a; <body><div id"box"><input type"text" input"handleInput()" v-model"mytext"&…

计算机网络 - 网络层 选择填空判断复习题

一. 单选题&#xff08;共25题&#xff0c;80分&#xff09; (单选题) 以下( )协议完成了从网卡到IP地址的映射。 A A.ARP协议 B.RARP协议 C.IGMP协议 D.ICMP协议 (单选题) 一个C类地址,采用了255.255.255.240作为子网掩码,那么这个C类地址可以划分为( )个子网。 A A.16 B.32 …

零基础自学javase黑马课程第十四天

零基础自学javase黑马课程第十四天 ✨欢迎关注&#x1f5b1;点赞&#x1f380;收藏⭐留言✒ &#x1f52e;本文由京与旧铺原创&#xff0c;csdn首发&#xff01; &#x1f618;系列专栏&#xff1a;java学习 &#x1f4bb;首发时间&#xff1a;&#x1f39e;2022年11月21日&…

【Hack The Box】Linux练习-- FriendZone

HTB 学习笔记 【Hack The Box】Linux练习-- FriendZone &#x1f525;系列专栏&#xff1a;Hack The Box &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f4c6;首发时间&#xff1a;&#x1f334;2022年11月17日&#x1f334; &#…

秋招失足,拿到这份“Java 高分指南(25 专题)”,金三银四翻盘有望

面试造火箭&#xff0c;工作拧螺丝&#xff01;金九银十灰溜溜地落榜&#xff0c;备受打击。正当准备明年金三银四之际&#xff0c;意外喜提朋友赠送的这“Java 高分指南&#xff08;25 专题&#xff09;”&#xff1a;Elasticsearch、微服务、Linux、JavaOOP、集合/泛型、Mysq…

move_base代码解析(一)MoveBase::executeCb

move_base是ROS中的经典路径规划算法&#xff0c;move_base 功能包提供了基于动作(action)的路径规划实现&#xff0c;move_base 可以根据给定的目标点&#xff0c;控制机器人底盘运动至目标位置&#xff0c;并且在运动过程中会连续反馈机器人自身的姿态与目标点的状态信息。 …

HTTP协议中的HTTP报文

HTTP中的HTTP报文 1、HTTP报文信息 1.1定义 用于HTTP协议交互的信息叫做HTTP 报文。 HTTP 报文大致可分为报文首部和报文主体两块。两者由最初出现的空行&#xff08;CRLF&#xff09;来划分&#xff08;通常并不一定要有报文主体&#xff09;。 1.2请求报文和响应报文 请…

CSS13_由html{height: 100%} 引发的CSS百分比宽高度的思考

一、html, body { height:100% } CSS有一个常见设置&#xff1a;html,body{ height:100% }&#xff0c;可能大家已经熟视无睹了&#xff0c;但细细思索&#xff0c;可能会有些奇怪&#xff0c;为什么html还需要设置height:100%呢&#xff1f;html不就代表整个页面了吗&#xf…

[附源码]java毕业设计网上书店管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

SpringBoot项目使用JSP

SpringBoot不推荐使用JSP,而是使用模板技术代替JSP视图 先创建个SpringBoot项目 使用JSP需要如下配置 加入一个处理JSP的依赖(使用该JSP依赖原因是SpringBoot的jar包是内嵌了一个Tomcat因此要用这个Jar包,如果你的SpringBoot需要打成war包,不使用内嵌Tomcat,可用通用的JSP依赖…

深度学习基础--神经网络(3)神经网络的学习,损失函数初识

文章目录神经网络的学习从数据中学习数据区分损失函数均方误差交叉熵误差mini-batch学习损失函数更新的思路本文为学习笔记整理参考书籍&#xff1a;《深度学习入门 : 基于Python的理论与实现 》/ (日) 斋藤康毅著 ; 陆宇杰译. – 北京 : 人民邮电出版社, 2018.7&#xff08;20…

Android插件式换肤以及资源加载流程分析

前言 APP更换皮肤的方式有很多&#xff0c;如系统自带的黑夜模式、插件换肤、通过下发配置文件加载不同主题等等&#xff0c;我们这里就浅谈下插件换肤方式。想实现插件换肤功能&#xff0c;我们就需要先弄清楚 :APP是如何完成资源加载的。 资源加载流程 这里我们以ImageVie…