当前位置: 首页 > news >正文

曲线与曲面的绘制

一、学习目标

(1)掌握常用规则参数曲线与曲面的编程绘制方法。
(2)掌握自由曲线与曲面的编程绘制方法。
(3)了解自由曲面的拼接编程方法。

二、学习内容

(1)编程绘一个规则参数曲线(如抛物线、星开线、心脏线)和规则参数曲面(如球、园柱、圆台、圆环线等)。
(2)编程绘制一个n次Bezier曲线和一个网格状三次Bezier曲面正轴测投影图。

三、实现代码

  (1)parametric_curves_surfaces.py,核心算法文件
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# 参数曲线绘制函数
def plot_parametric_curves():
    # 创建图形
    fig, axs = plt.subplots(2, 2, figsize=(12, 10))
    
    # 抛物线
    t = np.linspace(-2, 2, 100)
    x_parabola = t
    y_parabola = t**2
    axs[0, 0].plot(x_parabola, y_parabola)
    axs[0, 0].set_title('抛物线')
    
    # 星形线
    t = np.linspace(0, 2*np.pi, 100)
    x_astroid = np.cos(t)**3
    y_astroid = np.sin(t)**3
    axs[0, 1].plot(x_astroid, y_astroid)
    axs[0, 1].set_title('星形线')
    
    # 心脏线
    t = np.linspace(0, 2*np.pi, 100)
    x_cardioid = 2*np.cos(t) - np.cos(2*t)
    y_cardioid = 2*np.sin(t) - np.sin(2*t)
    axs[1, 0].plot(x_cardioid, y_cardioid)
    axs[1, 0].set_title('心脏线')
    
    plt.tight_layout()
    plt.show()

# 参数曲面绘制函数
def plot_parametric_surfaces():
    fig = plt.figure(figsize=(15, 10))
    
    # 球面
    ax1 = fig.add_subplot(221, projection='3d')
    u = np.linspace(0, 2 * np.pi, 100)
    v = np.linspace(0, np.pi, 100)
    x_sphere = np.outer(np.cos(u), np.sin(v))
    y_sphere = np.outer(np.sin(u), np.sin(v))
    z_sphere = np.outer(np.ones(np.size(u)), np.cos(v))
    ax1.plot_surface(x_sphere, y_sphere, z_sphere)
    ax1.set_title('球面')
    
    # 圆柱面
    ax2 = fig.add_subplot(222, projection='3d')
    theta = np.linspace(0, 2*np.pi, 100)
    z = np.linspace(0, 1, 100)
    theta_grid, z_grid = np.meshgrid(theta, z)
    x_cylinder = np.cos(theta_grid)
    y_cylinder = np.sin(theta_grid)
    z_cylinder = z_grid
    ax2.plot_surface(x_cylinder, y_cylinder, z_cylinder)
    ax2.set_title('圆柱面')
    
    # 圆台面
    ax3 = fig.add_subplot(223, projection='3d')
    r1, r2 = 1, 0.5
    theta = np.linspace(0, 2*np.pi, 100)
    z = np.linspace(0, 1, 100)
    theta_grid, z_grid = np.meshgrid(theta, z)
    r = r1 + (r2 - r1) * z_grid
    x_cone = r * np.cos(theta_grid)
    y_cone = r * np.sin(theta_grid)
    z_cone = z_grid
    ax3.plot_surface(x_cone, y_cone, z_cone)
    ax3.set_title('圆台面')
    
    # 圆环面
    ax4 = fig.add_subplot(224, projection='3d')
    R, r = 2, 1
    u = np.linspace(0, 2*np.pi, 100)
    v = np.linspace(0, 2*np.pi, 100)
    u_grid, v_grid = np.meshgrid(u, v)
    x_torus = (R + r*np.cos(v_grid)) * np.cos(u_grid)
    y_torus = (R + r*np.cos(v_grid)) * np.sin(u_grid)
    z_torus = r * np.sin(v_grid)
    ax4.plot_surface(x_torus, y_torus, z_torus)
    ax4.set_title('圆环面')
    
    plt.tight_layout()
    plt.show()

# Bezier曲线和曲面
def bezier_curve(points, t):
    n = len(points) - 1
    result = np.zeros(2)
    for i in range(n + 1):
        result += points[i] * comb(n, i) * (1 - t)**(n - i) * t**i
    return result

def comb(n, k):
    return np.math.factorial(n) / (np.math.factorial(k) * np.math.factorial(n - k))

def plot_bezier_curve():
    # 控制点
    points = np.array([
        [0, 0],
        [1, 2],
        [2, -1],
        [3, 1],
        [4, 0]
    ])
    
    # 生成曲线点
    t = np.linspace(0, 1, 100)
    curve_points = np.array([bezier_curve(points, ti) for ti in t])
    
    # 绘制
    plt.figure(figsize=(8, 6))
    plt.plot(points[:, 0], points[:, 1], 'ro-', label='控制点')
    plt.plot(curve_points[:, 0], curve_points[:, 1], 'b-', label='Bezier曲线')
    plt.legend()
    plt.title('5次Bezier曲线')
    plt.grid(True)
    plt.show()

def bezier_surface(points, u, v):
    n, m = points.shape[0] - 1, points.shape[1] - 1
    result = np.zeros(3)
    for i in range(n + 1):
        for j in range(m + 1):
            result += points[i, j] * comb(n, i) * comb(m, j) * (1 - u)**(n - i) * u**i * (1 - v)**(m - j) * v**j
    return result

def plot_bezier_surface():
    # 控制点网格
    points = np.array([
        [[0, 0, 0], [1, 0, 1], [2, 0, 0]],
        [[0, 1, 1], [1, 1, 2], [2, 1, 1]],
        [[0, 2, 0], [1, 2, 1], [2, 2, 0]]
    ])
    
    # 生成曲面点
    u = np.linspace(0, 1, 20)
    v = np.linspace(0, 1, 20)
    u_grid, v_grid = np.meshgrid(u, v)
    
    surface_points = np.zeros((len(u), len(v), 3))
    for i in range(len(u)):
        for j in range(len(v)):
            surface_points[i, j] = bezier_surface(points, u[i], v[j])
    
    # 绘制
    fig = plt.figure(figsize=(10, 8))
    ax = fig.add_subplot(111, projection='3d')
    
    # 绘制控制点网格
    for i in range(points.shape[0]):
        for j in range(points.shape[1]):
            ax.scatter(points[i, j, 0], points[i, j, 1], points[i, j, 2], color='red')
    
    # 绘制曲面
    ax.plot_surface(surface_points[:, :, 0], surface_points[:, :, 1], surface_points[:, :, 2], alpha=0.5)
    
    ax.set_title('3x3控制点网格的Bezier曲面')
    plt.show()

if __name__ == "__main__":
    # 绘制参数曲线
    plot_parametric_curves()
    
    # 绘制参数曲面
    plot_parametric_surfaces()
    
    # 绘制Bezier曲线
    plot_bezier_curve()
    
    # 绘制Bezier曲面
    plot_bezier_surface() 

(2)app.py,使用Flask框架,提供参数曲线和曲面的Web可视化。
from flask import Flask, render_template, jsonify
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_agg import FigureCanvasAgg
import io
import base64

app = Flask(__name__)

def get_parametric_curves():
    # 创建图形
    fig, axs = plt.subplots(2, 2, figsize=(12, 10))
    
    # 抛物线
    t = np.linspace(-2, 2, 100)
    x_parabola = t
    y_parabola = t**2
    axs[0, 0].plot(x_parabola, y_parabola, 'b-', linewidth=2)
    axs[0, 0].set_title('抛物线', fontsize=12)
    axs[0, 0].grid(True)
    
    # 星形线
    t = np.linspace(0, 2*np.pi, 100)
    x_astroid = np.cos(t)**3
    y_astroid = np.sin(t)**3
    axs[0, 1].plot(x_astroid, y_astroid, 'r-', linewidth=2)
    axs[0, 1].set_title('星形线', fontsize=12)
    axs[0, 1].grid(True)
    
    # 心脏线
    t = np.linspace(0, 2*np.pi, 100)
    x_cardioid = 2*np.cos(t) - np.cos(2*t)
    y_cardioid = 2*np.sin(t) - np.sin(2*t)
    axs[1, 0].plot(x_cardioid, y_cardioid, 'g-', linewidth=2)
    axs[1, 0].set_title('心脏线', fontsize=12)
    axs[1, 0].grid(True)
    
    plt.tight_layout()
    return fig_to_base64(fig)

def get_parametric_surfaces():
    fig = plt.figure(figsize=(15, 10))
    
    # 球面
    ax1 = fig.add_subplot(221, projection='3d')
    u = np.linspace(0, 2 * np.pi, 100)
    v = np.linspace(0, np.pi, 100)
    x_sphere = np.outer(np.cos(u), np.sin(v))
    y_sphere = np.outer(np.sin(u), np.sin(v))
    z_sphere = np.outer(np.ones(np.size(u)), np.cos(v))
    ax1.plot_surface(x_sphere, y_sphere, z_sphere, cmap='viridis')
    ax1.set_title('球面', fontsize=12)
    
    # 圆柱面
    ax2 = fig.add_subplot(222, projection='3d')
    theta = np.linspace(0, 2*np.pi, 100)
    z = np.linspace(0, 1, 100)
    theta_grid, z_grid = np.meshgrid(theta, z)
    x_cylinder = np.cos(theta_grid)
    y_cylinder = np.sin(theta_grid)
    z_cylinder = z_grid
    ax2.plot_surface(x_cylinder, y_cylinder, z_cylinder, cmap='plasma')
    ax2.set_title('圆柱面', fontsize=12)
    
    # 圆台面
    ax3 = fig.add_subplot(223, projection='3d')
    r1, r2 = 1, 0.5
    theta = np.linspace(0, 2*np.pi, 100)
    z = np.linspace(0, 1, 100)
    theta_grid, z_grid = np.meshgrid(theta, z)
    r = r1 + (r2 - r1) * z_grid
    x_cone = r * np.cos(theta_grid)
    y_cone = r * np.sin(theta_grid)
    z_cone = z_grid
    ax3.plot_surface(x_cone, y_cone, z_cone, cmap='inferno')
    ax3.set_title('圆台面', fontsize=12)
    
    # 圆环面
    ax4 = fig.add_subplot(224, projection='3d')
    R, r = 2, 1
    u = np.linspace(0, 2*np.pi, 100)
    v = np.linspace(0, 2*np.pi, 100)
    u_grid, v_grid = np.meshgrid(u, v)
    x_torus = (R + r*np.cos(v_grid)) * np.cos(u_grid)
    y_torus = (R + r*np.cos(v_grid)) * np.sin(u_grid)
    z_torus = r * np.sin(v_grid)
    ax4.plot_surface(x_torus, y_torus, z_torus, cmap='magma')
    ax4.set_title('圆环面', fontsize=12)
    
    plt.tight_layout()
    return fig_to_base64(fig)

def get_bezier_curve():
    points = np.array([
        [0, 0],
        [1, 2],
        [2, -1],
        [3, 1],
        [4, 0]
    ])
    
    t = np.linspace(0, 1, 100)
    curve_points = np.array([bezier_curve(points, ti) for ti in t])
    
    plt.figure(figsize=(8, 6))
    plt.plot(points[:, 0], points[:, 1], 'ro-', label='控制点')
    plt.plot(curve_points[:, 0], curve_points[:, 1], 'b-', label='Bezier曲线')
    plt.legend()
    plt.title('5次Bezier曲线', fontsize=12)
    plt.grid(True)
    return fig_to_base64(plt.gcf())

def get_bezier_surface():
    points = np.array([
        [[0, 0, 0], [1, 0, 1], [2, 0, 0]],
        [[0, 1, 1], [1, 1, 2], [2, 1, 1]],
        [[0, 2, 0], [1, 2, 1], [2, 2, 0]]
    ])
    
    u = np.linspace(0, 1, 20)
    v = np.linspace(0, 1, 20)
    u_grid, v_grid = np.meshgrid(u, v)
    
    surface_points = np.zeros((len(u), len(v), 3))
    for i in range(len(u)):
        for j in range(len(v)):
            surface_points[i, j] = bezier_surface(points, u[i], v[j])
    
    fig = plt.figure(figsize=(10, 8))
    ax = fig.add_subplot(111, projection='3d')
    
    for i in range(points.shape[0]):
        for j in range(points.shape[1]):
            ax.scatter(points[i, j, 0], points[i, j, 1], points[i, j, 2], color='red')
    
    ax.plot_surface(surface_points[:, :, 0], surface_points[:, :, 1], surface_points[:, :, 2], alpha=0.5, cmap='viridis')
    ax.set_title('3x3控制点网格的Bezier曲面', fontsize=12)
    return fig_to_base64(fig)

def bezier_curve(points, t):
    n = len(points) - 1
    result = np.zeros(2)
    for i in range(n + 1):
        result += points[i] * comb(n, i) * (1 - t)**(n - i) * t**i
    return result

def bezier_surface(points, u, v):
    n, m = points.shape[0] - 1, points.shape[1] - 1
    result = np.zeros(3)
    for i in range(n + 1):
        for j in range(m + 1):
            result += points[i, j] * comb(n, i) * comb(m, j) * (1 - u)**(n - i) * u**i * (1 - v)**(m - j) * v**j
    return result

def comb(n, k):
    return np.math.factorial(n) / (np.math.factorial(k) * np.math.factorial(n - k))

def fig_to_base64(fig):
    canvas = FigureCanvasAgg(fig)
    buf = io.BytesIO()
    canvas.print_png(buf)
    data = base64.b64encode(buf.getvalue()).decode('utf-8')
    plt.close(fig)
    return data

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/get_curves')
def get_curves():
    return jsonify({
        'parametric_curves': get_parametric_curves(),
        'parametric_surfaces': get_parametric_surfaces(),
        'bezier_curve': get_bezier_curve(),
        'bezier_surface': get_bezier_surface()
    })

if __name__ == '__main__':
    app.run(debug=True) 
(3)HTML页面,可视化展示。
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>参数曲线与曲面可视化</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <style>
        body {
            background-color: #f8f9fa;
            padding-top: 20px;
        }
        .container {
            max-width: 1200px;
        }
        .card {
            margin-bottom: 20px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
            border: none;
        }
        .card-header {
            background-color: #007bff;
            color: white;
            font-weight: bold;
        }
        .loading {
            text-align: center;
            padding: 20px;
        }
        .plot-container {
            text-align: center;
            padding: 10px;
        }
        .plot-container img {
            max-width: 100%;
            height: auto;
            border-radius: 5px;
        }
        h1 {
            color: #007bff;
            margin-bottom: 30px;
            text-align: center;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>参数曲线与曲面可视化</h1>
        
        <div class="row">
            <div class="col-md-6">
                <div class="card">
                    <div class="card-header">
                        参数曲线
                    </div>
                    <div class="card-body">
                        <div class="plot-container" id="parametric-curves">
                            <div class="loading">
                                <div class="spinner-border text-primary" role="status">
                                    <span class="visually-hidden">加载中...</span>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            
            <div class="col-md-6">
                <div class="card">
                    <div class="card-header">
                        参数曲面
                    </div>
                    <div class="card-body">
                        <div class="plot-container" id="parametric-surfaces">
                            <div class="loading">
                                <div class="spinner-border text-primary" role="status">
                                    <span class="visually-hidden">加载中...</span>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        
        <div class="row">
            <div class="col-md-6">
                <div class="card">
                    <div class="card-header">
                        Bezier曲线
                    </div>
                    <div class="card-body">
                        <div class="plot-container" id="bezier-curve">
                            <div class="loading">
                                <div class="spinner-border text-primary" role="status">
                                    <span class="visually-hidden">加载中...</span>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            
            <div class="col-md-6">
                <div class="card">
                    <div class="card-header">
                        Bezier曲面
                    </div>
                    <div class="card-body">
                        <div class="plot-container" id="bezier-surface">
                            <div class="loading">
                                <div class="spinner-border text-primary" role="status">
                                    <span class="visually-hidden">加载中...</span>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
    <script>
        // 加载所有图形
        fetch('/get_curves')
            .then(response => response.json())
            .then(data => {
                // 更新参数曲线
                document.getElementById('parametric-curves').innerHTML = 
                    `<img src="data:image/png;base64,${data.parametric_curves}" alt="参数曲线">`;
                
                // 更新参数曲面
                document.getElementById('parametric-surfaces').innerHTML = 
                    `<img src="data:image/png;base64,${data.parametric_surfaces}" alt="参数曲面">`;
                
                // 更新Bezier曲线
                document.getElementById('bezier-curve').innerHTML = 
                    `<img src="data:image/png;base64,${data.bezier_curve}" alt="Bezier曲线">`;
                
                // 更新Bezier曲面
                document.getElementById('bezier-surface').innerHTML = 
                    `<img src="data:image/png;base64,${data.bezier_surface}" alt="Bezier曲面">`;
            })
            .catch(error => {
                console.error('Error:', error);
                document.querySelectorAll('.loading').forEach(el => {
                    el.innerHTML = '<div class="alert alert-danger">加载失败,请刷新页面重试</div>';
                });
            });
    </script>
</body>
</html> 

四、运行结果

五、项目简介

# 参数曲线与曲面可视化项目

## 项目概述

本项目使用Python Flask框架和Matplotlib库,实现了多种参数曲线和曲面的可视化展示,包括Bezier曲线/曲面的算法实现。

## 功能模块

### 1. 参数曲线可视化

- 抛物线

- 星形线

- 心脏线

### 2. 参数曲面可视化

- 球面

- 圆柱面

- 圆台面

- 圆环面

### 3. Bezier曲线/曲面

- 5次Bezier曲线

- 3x3控制点网格的Bezier曲面

## 技术特点

- 使用Flask提供Web服务接口

- Matplotlib生成高质量图形

- 参数方程精确计算曲线/曲面

- 响应式前端展示

## 运行方式

```bash

pip install -r requirements.txt

python app.py

```

访问 http://localhost:5000 查看可视化效果

相关文章:

  • golang 在windows 系统的交叉编译
  • KWDB创作者计划— KWDB技术范式革命:从数据存储到认知进化的架构跃迁
  • Windows 11 LTSC 安装 闹钟和时钟
  • Hutool工具包中`copyProperties`和`toBean`的区别
  • Python自动化测试框架及工具详解
  • Docker学习与实践
  • 【C++教程】进制转换的实现方法
  • Docker的部署和基本操作
  • 2024团体程序设计天梯赛L3-1 夺宝大赛
  • 【ROS2】行为树 BehaviorTree(二):传递参数(黑板和端口)
  • day28图像处理OpenCV
  • 服务器本地搭建
  • FPGA_UART
  • 刷题记录(3)C语言中的字符
  • LlamaIndex学习
  • Fiddler为什么可以看到一次HTTP请求数据?
  • 项目班——0408
  • 【神经网络】python实现神经网络(四)——误差反向传播的基础理论
  • AI与我共创WEB界面
  • 风丘年度活动:2025年横滨汽车工程展览会
  • 竹笋食用不当,小心“鲜”变“险”
  • 今年一季度,上海对东盟进出口总值同比增长7.1%
  • 成功卫冕!孙颖莎4比0战胜蒯曼,获澳门世界杯女单冠军
  • “75后”新任四川泸州市委副书记张伟,已任市政府党组书记
  • 境外机构来华发行熊猫债累计超9500亿元
  • 专业纯粹,安静温暖,上海古籍书店明日重新开张