【CAD算法】基于最速下降法(梯度下降)的最短路径实现(python实现)[5]

2023-11-02

1.内容回顾

关于Bezier曲线内容,请参考https://blog.csdn.net/iwanderu/article/details/103604863
优化问题有很多解决方式,例如最速下降,批量梯度下降,随机梯度下降,LM算法,GN算法。梯度下降法是最简单的一种优化方法,缺点是在极值点附近会有zigzag。所有算法的核心就是Jacobian矩阵的确定。

2.题目描述

Refer to the figure for an example: there are m = 7 curves and points A and B, the red polygon is a trace of the curves which goes through in the order C1, C2, …, C7; this curve is said to be minimal if its length is the shortest.
在这里插入图片描述
You will read in Ci from a text file (in the (b) format of Lab 1) and key in the XYZ coordinates of points A and B. Write a computer program that will use the Steepest Ascend method to compute the minimum trace. Note that the length of the trace is a function D(u1, u2, …, u7) of 7 variables, where ui is the parameter of curve Ci with range [0, 1]. Again, you should display the intermediate result after each iteration.

首先有7个Bezier曲线,上面各取一个点,还有2个端点,求所有点的连线最短时各个点的位置。

3.Coons曲面的获取

3.1头文件的引用和变量定义

import os
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import pandas as pd

np.set_printoptions(suppress = True)
#database = []
m = np.array([],dtype = np.uint8) # the number of bazier curves
pointsNumber = np.array([],dtype = np.uint8) #for the ith curve, the points number of it
closedOrOpen = np.array([],dtype = np.uint8) #for the ith curve, 0 means it is open, 1 means it is closed
point = np.array([],dtype = np.float64) #the control points for all the curves
f = np.array([],dtype=np.float64)
u_i = np.array([],dtype = np.float64)#u_i is the current u for current line for current iteration
bezierLine = np.array([],dtype=np.float64) #list of points of path
pointA = np.array([],dtype=np.float64) 
pointB = np.array([],dtype=np.float64)
D = np.array([],dtype=np.float64) #the history of path length
min_D = 10000000 #make sure that D is smaller after each iteration

3.2 实现从txt文件输入Beizer曲线的控制点坐标

关于Bezier曲线内容,请参考https://blog.csdn.net/iwanderu/article/details/103604863。

pointsNumber_str = ""
closedOrOpen_str = ""
point_str = ""
line_zero = ""
filepath = ""

def inputFromText():
  global filepath
  filepath = os.path.abspath('.') + "/" + raw_input("please input the file name(eg:data.txt):")

  with open (filepath) as data:
    line_zero = data.readline()
    line_zero_list = list(line_zero.split())
    global m
    m = np.array(line_zero_list, dtype=np.uint8)

    for i in range(m[0]): 
      pointsNumber_str = data.readline()
      pointsNumber_list = list(pointsNumber_str.split())
      temp1 = np.array(pointsNumber_list,dtype=np.uint8)
      global pointsNumber
      pointsNumber = np.append(pointsNumber,temp1) # the number of control points of the ith Bezier curve

      closedOrOpen_str = data.readline()
      closedOrOpen_list = list(closedOrOpen_str.split())
      temp2 = np.array(closedOrOpen_list,dtype=np.uint8)
      global closedOrOpen
      closedOrOpen = np.append(closedOrOpen,temp2) #0 means the ith curve is closed, 1 means it is open
      
      global point
      for j in range(temp1[0]):
      #u += 1
        point_str = data.readline()
        point_list = list(point_str.split())
        temp3 = np.array(point_list,dtype=np.float64)
        point = np.append(point,temp3) # control points for the ith Bezier Curve

    global pointA
    pointA_str = data.readline()
    pointA_list = list(pointA_str.split())
    temp4 = np.array(pointA_list,dtype=np.float64)
    pointA = np.append(pointA,temp4) # point A 3*1
    global pointB
    pointB_str = data.readline()
    pointB_list = list(pointB_str.split())
    temp5 = np.array(pointB_list,dtype=np.float64)
    pointB = np.append(pointB,temp5) # point B 3*1 
    
    global bezierLine
    bezierLine = np.append(bezierLine,pointA)
    #bezierLine = bezierLine.reshape((-1,3))
  
  point = np.reshape(point, (-1,3))

3.3 获取Bezier曲线,并实现绘图,和计算Jacobian

首先是函数定义,下面是这个函数各个传入参数的意义。

def getBezierKurve(closedOrOpen,pointsNumber,point,point_index,u_i,jacobian_flag,drawbezier_flag,iter_flag,jacobiancontrol_flag):
#closedOrOpen: current kurve is closed or open bezier kurve
#pointsNumber: the number of control points of current kurve
#point: the xyz coordinates of control points of total kurve
#point_index: help find which control points belong to current kurve
#u_i: the current u for the current iteration
#jacobian_flag: help decide witch part of Jacobian is non-zero

#because this function conbine too many meanings(not good) so we need flags to control which one is on:
#drawbezier_flag: if true, it will draw bezier kurves
#iter_flag: if true, it will draw the current trace points and lines
#jacobiancontrol_flag: if true, it will calculate the partial derivative

第一步,处理从txt传入的数据,获得Bezier曲线

  C = []
  n = pointsNumber - 1 # n is fewer in numbers than the total control points number. According to definition.
  point_show = np.array([],dtype=np.float64)
  for i in range(n+1):
    point_show = np.append(point_show,point[point_index + i])  

  if (closedOrOpen == 0): # if it is closed, means the oth and nth control points are the same.
    n += 1
    point_show = np.append(point_show,point[point_index])
  elif (closedOrOpen == 1):
    pass
  point_show = point_show.reshape((-1,3))

  if ((n+1) % 2 == 0):
    for i in range((n+1) / 2):
      up = 1
      down = 1
      j = n
      while (j > i):
        up *= j
        j = j - 1
      j = n - i
      while (j > 0):
        down *= j
        j = j - 1
      C.append(up / down)
  elif ((n+1) % 2 == 1):
    for i in range(n / 2):
      up = 1
      down = 1
      j = n
      while (j > i):
        up *= j
        j = j - 1
      j = n - i
      while (j > 0):
        down *= j
        j = j - 1
      C.append(up / down)
    up = 1
    down = 1
    j = n
    while (j > n/2):
      up *= j
      j = j - 1
    j = n/2
    while (j > 0):
      down *= j
      j = j - 1
    C.append(up / down)
  if (n%2 == 1):
    for i in range(int((n+1)/2)):
      C.append(C[int(n/2-i)])
  if (n%2 == 0):
    for i in range(int((n+1)/2)):
      C.append(C[int(n/2-i-1)])
  #print("C",C) 

第二步,绘制Bezier曲线

  if (drawbezier_flag==1):
    global f
    #f = np.array([],dtype=np.float64)
    #the following steps is to draw the kurve,not so important
  #  print("point_show\n",point_show)
  #  print("n+1",n+1)
    u = 0
    for j in range(1000): 
      fx = 0
      fy = 0  #do not forget return 0!!!!!!!!!!!!
      fz = 0
      for i in range(n+1):
        fx += C[i] * u**i * (1-u)**(n-i) * point_show[i][0]
        fy += C[i] * u**i * (1-u)**(n-i) * point_show[i][1]
        fz += C[i] * u**i * (1-u)**(n-i) * point_show[i][2]
      list = []
      list.append(fx)
      list.append(fy) 
      list.append(fz)
      array_list = np.array([list],dtype=np.float64) 
      u += 0.001
      f = np.append(f,array_list)

    f = f.reshape((-1,3))
    #ax.plot(f_show[:,0],f_show[:,1],f_show[:,2],'b.',markersize=1,label='open bazier curve')
    #ax.plot(point_show[:,0],point_show[:,1],point_show[:,2],'-',markersize=1, label='control line')
    #ax.plot(point_show[:,0],point_show[:,1],point_show[:,2],'r.',markersize=8, label='control points')

第三步,绘制迭代过程中某一步的效果曲线

  if (drawbezier_flag==1):
    global f
    #f = np.array([],dtype=np.float64)
    #the following steps is to draw the kurve,not so important
  #  print("point_show\n",point_show)
  #  print("n+1",n+1)
    u = 0
    for j in range(1000): 
      fx = 0
      fy = 0  #do not forget return 0!!!!!!!!!!!!
      fz = 0
      for i in range(n+1):
        fx += C[i] * u**i * (1-u)**(n-i) * point_show[i][0]
        fy += C[i] * u**i * (1-u)**(n-i) * point_show[i][1]
        fz += C[i] * u**i * (1-u)**(n-i) * point_show[i][2]
      list = []
      list.append(fx)
      list.append(fy) 
      list.append(fz)
      array_list = np.array([list],dtype=np.float64) 
      u += 0.001
      f = np.append(f,array_list)

    f = f.reshape((-1,3))
    #ax.plot(f_show[:,0],f_show[:,1],f_show[:,2],'b.',markersize=1,label='open bazier curve')
    #ax.plot(point_show[:,0],point_show[:,1],point_show[:,2],'-',markersize=1, label='control line')
    #ax.plot(point_show[:,0],point_show[:,1],point_show[:,2],'r.',markersize=8, label='control points')

第四步,计算当前时刻Bezier曲线对参数u的导数。

  if (jacobiancontrol_flag==1):
  #the following step is to get the current line for current iteration
    fx = 0
    fy = 0  #do not forget return 0!!!!!!!!!!!
    fz = 0
    for i in range(n+1):
      fx += C[i] * u_i**i * (1-u_i)**(n-i) * point_show[i][0]
      fy += C[i] * u_i**i * (1-u_i)**(n-i) * point_show[i][1]
      fz += C[i] * u_i**i * (1-u_i)**(n-i) * point_show[i][2]
    #u_i is the current u for current line for current iteration  
    _list = []
    _list.append(fx)
    _list.append(fy) 
    _list.append(fz)
    _array_list = np.array([_list],dtype=np.float64)
    global bezierLine #for current u, find the corresponding points on each line
    bezierLine = np.append(bezierLine,_array_list)
    #bezierLine = bezierLine.reshape((-1,3))
    #print("bezierLine")
    #print(bezierLine)

    # calculate the partial derivative
    global partial_derivative
    #partial_derivative = np.zeros(3*m[0]) 
    partial_derivative = np.zeros(3)
    dfx = 0
    dfy = 0  #do not forget return 0!!!!!!!!!!!
    dfz = 0
    for i in range(n+1):
      if (i==0):
        dfx -= C[i] * (n-i)*(1-u_i)**(n-i-1) * point_show[i][0]
        dfy -= C[i] * (n-i)*(1-u_i)**(n-i-1) * point_show[i][1]
        dfz -= C[i] * (n-i)*(1-u_i)**(n-i-1) * point_show[i][2] 
      elif (n==i):
        dfx += C[i] * i*u_i**(i-1) * point_show[i][0]
        dfy += C[i] * i*u_i**(i-1) * point_show[i][1]
        dfz += C[i] * i*u_i**(i-1) * point_show[i][2]
      else: 
        dfx += C[i] * (i*u_i**(i-1)*(1-u_i)**(n-i)-u_i**i*(n-i)*(1-u_i)**(n-i-1)) * point_show[i][0]
        dfy += C[i] * (i*u_i**(i-1)*(1-u_i)**(n-i)-u_i**i*(n-i)*(1-u_i)**(n-i-1)) * point_show[i][1]
        dfz += C[i] * (i*u_i**(i-1)*(1-u_i)**(n-i)-u_i**i*(n-i)*(1-u_i)**(n-i-1)) * point_show[i][2]
    #partial_derivative[jacobian_flag*3] = dfx
    #partial_derivative[jacobian_flag*3+1] = dfy
    #partial_derivative[jacobian_flag*3+2] = dfz
    partial_derivative[0] = dfx
    partial_derivative[1] = dfy
    partial_derivative[2] = dfz
    #print("partial_derivative")
    #print(partial_derivative)

3.4 最速下降优化
损失函数是整个路径的长度,也就是每一段线段两端端点坐标平方和开根号。其实为了化简运算,可以不开这个根号。

def steepestAscendmethod(ITERATION_TIME):
  D = 0
  unit_step = 0.0005 #learning rate for each iteration
  kurve_jacobian = np.array([],dtype=np.float64) #partial derivative of line df/du
  jacobian_trace = np.zeros((m[0],1)) #jacobian of trace length = [dD/du1 dD/du2 ...  dD/dun]
  #global ax

  fig = plt.figure()
  ax = fig.gca(projection='3d')

  for i in range(ITERATION_TIME):
    point_index = 0
    #key = raw_input("should we continue? yes/no:")
    if (0):#key =="no"):
      #print("OK, you are right.\n")
      #break
      pass
    elif (1):#key =="yes"):
      #print("let's continue:\n")
      point_index = 0

      for i in range(m[0]):
        getBezierKurve(closedOrOpen[i],pointsNumber[i],point,point_index,0,0,1,0,0) #draw curves only
        point_index += pointsNumber[i]

      point_index = 0
      for j in range(m[0]):
        #print(j)
        #print("*******************************")
        getBezierKurve(closedOrOpen[j],pointsNumber[j],point,point_index,u_i[j],0,0,0,1)
        point_index += pointsNumber[j]

        kurve_jacobian = np.append(kurve_jacobian,partial_derivative) # do not forget reshape

      kurve_jacobian = kurve_jacobian.reshape((-1,3))

      global bezierLine
      bezierLine = np.append(bezierLine,pointB)
      bezierLine = bezierLine.reshape((-1,3))
      ax.plot(bezierLine[:,0],bezierLine[:,1],bezierLine[:,2],'-',markersize=1, label='trace')
      ax.plot(f[:,0],f[:,1],f[:,2],'r.',markersize=1)#,label='open bazier curve')
      ax.set_xlabel('X')
      ax.set_ylabel('Y')
      ax.set_zlabel('Z')
      plt.show()

      for i in range(m[0]):
        jacobian_trace[i] = 2*((bezierLine[i+1][0]-bezierLine[i+2][0])-(bezierLine[i][0]-bezierLine[i+1][0]))*kurve_jacobian[i][0] + 2*((bezierLine[i+1][1]-bezierLine[i+2][1])-(bezierLine[i][1]-bezierLine[i+1][1]))*kurve_jacobian[i][1] + 2*((bezierLine[i+1][2]-bezierLine[i+2][2])-(bezierLine[i][2]-bezierLine[i+1][2]))*kurve_jacobian[i][2]
      #print(jacobian_trace)
      
      global D
      D_item = 0
      for i in range(m[0]):
        D_item += ((bezierLine[i+1][0]-bezierLine[i+2][0])-(bezierLine[i][0]-bezierLine[i+1][0]))**2 + ((bezierLine[i+1][1]-bezierLine[i+2][1])-(bezierLine[i][1]-bezierLine[i+1][1]))**2 + ((bezierLine[i+1][2]-bezierLine[i+2][2])-(bezierLine[i][2]-bezierLine[i+1][2]))**2
      D = np.append(D,D_item)
      print("the length of trace")
      #print(D_item)      

      if (D[D.shape[0]-1] <= min_D):      
        for i in range(m[0]):
          step = jacobian_trace[i] * unit_step
          u_i[i] -= step
          while (u_i[i] > 1 or u_i[i] < 0): #make sure that 0<u<1如果当前值超过了u的定义范围,那么下降值再乘以一个非常小的量unit_step
            u_i[i] += step
            step = step * unit_step
            u_i[i] -= step   

      global min_D
      if (min_D > D[D.shape[0]-1]):
        min_D = D[D.shape[0]-1]
      else:
        D[D.shape[0]-1] = min_D
      print(D[D.shape[0]-1])

      kurve_jacobian = np.array([],dtype=np.float64) #return to init station
      bezierLine = np.array([],dtype=np.float64)
      bezierLine = np.append(bezierLine,pointA)
    else:
      print("Error: unknown error")

3.5 main()

inputFromText()
#fig = plt.figure()
#ax = fig.gca(projection='3d')

u_i = np.random.rand(m[0],1)
for i in range(10):
  key = raw_input("should we continue? yes/no:")
  if (key =="no"):
    print("OK, you are right.\n")
    break
  elif (key =="yes"):
    print("let's continue:\n")
    for j in range(10):
      #if (D.shape[0]==0 or D[D.shape[0]-1]<=min_D): 
      steepestAscendmethod(1)

4.实验结果

实际上,初始值对实验结果的影响很大,不好的初始值,可能会让算法陷入局部最小值。所以说,如果使用梯度下降法,被优化函数是凸函数是十分重要的。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
第一张图片各个点是随机生成对,随着迭代的进行,各个点的位置在不断优化,但是仍然发现,收敛时并不是最优位置,因此损失函数不是一个凸函数。下图是损失函数在各个迭代后的数值,在不断减小。
在这里插入图片描述

所有代码的链接如下:https://github.com/iwander-all/CAD.git

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【CAD算法】基于最速下降法(梯度下降)的最短路径实现(python实现)[5] 的相关文章

  • CAD批量打图精灵功能列表

    功能简介功能细分识别图框识别直线 多段线 二维多段线 三维多段线 面域 视口 代理实体 块参照 外部参照单图模式 xff0c 识别整个图形的边界 xff0c 适用于模型或布局只有一张图的情况多图模式 xff0c 识别矩形或无矩形块边界标准
  • lisp方格网高程提取_纯CAD提取飞时达土方软件生成的方格网高层数据X,Y,Z的值

    概况 再来看看图层情况 图层 可以看的出来数据都被作为一个块 xff0c 块名称GPCADFGD xff0c 将鼠标移至特性栏右侧显示更多块信息 xff01 块信息 看方格网数据对应块信息分析得知 ZBG BG的值是原始高层值 xff0c
  • ROS自定义地图(CAD、手绘等)

    0x00 概述 在前面的文章中 xff0c 我们介绍如何自动导航时 xff0c 都是基于使用gmapping或者hector mapping创建的地图 当然使用其他的建图方法创建的地图也可以 xff0c 但是目前为止 xff0c 无论使用哪
  • ROS自定义地图(CAD、手绘等)

    0x00 概述 在前面的文章中 xff0c 我们介绍如何自动导航时 xff0c 都是基于使用gmapping或者hector mapping创建的地图 当然使用其他的建图方法创建的地图也可以 xff0c 但是目前为止 xff0c 无论使用哪
  • 【ABviewer从零开始教学编辑器篇①】创建文件和元素选择

    ABViewer是一款高质量 高效率 低成本的多功能设计及工程文档管理工具 能为您提供全面的专业的浏览及编辑功能 同时支持30多种光栅和矢量图形格式 在小编看来 ABViewer是一款非常简单且实用的CAD文档查看与编辑器 对于使用小白可能
  • AutoCAD二次开发_从入门到放弃

    在建筑与设计行业中 CAD有着非常广泛的应用 而其中的很多基本操作无法满足实际需求 容易产生大量的重复性的操作 这种重复性的操作违背了程序设计的思维 因此诞生了入门CAD二次开发的想法 跟大多数程序设计语言一样 在了解CAD二次开发所应用的
  • 关于使用2d照片进行3d建模

    转载感言 作者一句业余 搞得弟兄们面红耳赤了 感谢作者的可行性分析 Autodesk 的 123D Catch 让我们能够很简单的根据一组照片构建3D物体 你只需要从各个角度拍摄希望建模的物体 然后通过 123D Catch 将照片上传到
  • 如何炸开(分解)CAD多重插入块

    新建一个空白文本文档 然后将下面 红色 代码复制到里面并保存 将文件名以及后缀名改成unlk lsp defun c unlk en ent setq en entsel n请选择被加密的图形 if en if cdr assoc 0 se
  • 【ABviewer从零开始教学查看器篇③】打开文件之缩略图菜单

    ABViewer是一款高质量 高效率 低成本的多功能设计及工程文档管理工具 能为您提供全面的专业的浏览及编辑功能 同时支持30多种光栅和矢量图形格式 在小编看来 ABViewer是一款非常简单且实用的CAD文档查看与编辑器 对于使用小白可能
  • 如何在Java中将STL转换为PDF或PNG图像?试试这个

    STL文件用于显示3D曲面的几何形状 但是 只有少数与CAD相关的应用程序支持查看或使用STL文件 因此 您可能需要将STL文件转换为PDF或PNG图像 因为它广泛支持PDF或图像文件格式 所以它使您可以在许多操作系统和环境中概述文件 让我
  • 常见的几何算法库

    常见的几何算法库包括 ACIS Parasolid和OpenCASCADE 简称OCC 前两个是商业的 后者是开源的 在CAD CAE这个领域 开源算法库基本上没有多大优势 基于ACIS和Parasolid至少有很多知名的产品 比如ACIS
  • solidworks大型装配体慢卡顿怎么办?来看专业的装配设计与仿真工作站是怎么解决的!

    相信很多CAD专业领域的设计工程师都或多或少的遇到慢 卡 顿的情况 按照网上各种设置一通问题依旧 换成昂贵的双路品牌图形工作站依然得不到改善 那么问题到底出在哪儿 下面就依Solidworks为例 从三维设计与仿真的特点来分析软件如何与硬件
  • 如何在 C# 中以编程方式将 IGS/IGES 文件转换为 PDF?

    计算机辅助设计应用程序使用 IGS 文件 因为它们包含设计信息 您可以将 IGS 文件转换为 PDF 格式的文档 以便在多个操作系统和环境中查看内容 使用 C 以编程方式将 IGS 或 IGES 文件转换为 PDF 使用高级选项将 IGES
  • 三维数据处理软件架构

    三维数据处理软件都包含哪些模块 三维数据处理软件 一般包含三个模块 数据管理和处理 三维渲染 UI 这与图形学的三个经典问题是相对应的 建模 渲染和交互 与一般常见的数据处理软件 比如图像视频处理 不同的是 这里的数据展示模块需要三维渲染
  • C# Revit二次开发基础/核心编程--- 元素Element(基础、编辑)

    一 本节课程 C Revit二次开发基础 核心编程 元素Element 基础 编辑 二 本节要讲解的知识点 元素Element的基础概念 如何编辑元素 具体内容 元素Element基础 元素在Revit里面尤其重要 用户能看见的大多数对象都
  • 常见CAD/CAM控件大全

    前言 CAD CAM 计算机辅助设计与制造 技术是随着计算机和数字化信息技术发展而形成的新技术 是20世纪最杰出的工程成就之一 也是数字化 信息化制造技术的基础 其发展和应用对制造业产生了巨大的影响和推动作用 经过几十年的发展和应用 不仅C
  • 在 WPF 应用程序中嵌入 Unity3D 应用程序

    我想在 WPF 中开发一个新的 CAD 软件 而不是使用 WPF 3D 是否可以使用 Unity3D 作为我的图形引擎 能够根据 WPF 中的数据对象旋转 平移 缩放和查看 3D 图形对象 我问这个问题的原因是 Unity 是一个游戏引擎
  • 如何解码 .dxf 文件?

    我想将 dxf 文件内的绘图转换为 g 代码 有一些工具可以做到这一点 但我想自己编写代码 因此 第一部分是解码 dxf 格式 然而 dxf 文件的内容看起来并不容易破译 我下载了一个 dxf 文件here并在文本编辑器中打开它 我也指的是
  • 在Python中导入CAD对象并存储为数组

    我正在使用 Autodesk Fusion 360 对 3D 零件进行建模 参见下图 然后可以将其导出并保存为 step iges sat 或 smt 文件 我想要实现的目标是将这部分转换为Python中的3D numpy数组 数组的每个元
  • WPF 中的 2D CAD 应用

    我正在尝试在 WPF NET 4 0 中编写一个类似 CAD 的应用程序 它需要能够显示大量 2D 点 线 它将用于通过鼠标悬停时的缩放 平移 旋转和点捕捉来显示整个城市的 CAD 平面图 现在我纯粹使用WPF 我从 CAD 文件中读取对象

随机推荐