0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

複数の質点のトータル重量重心位置をPythonで3Dプロットする

Posted at

どんな工作物でも,各パーツの重量と重心位置のバランスは大切です!

何を設計するに際しても,(例えばアームロボットなど)
工作物の重量を把握し,全体の重量バランスを検討する必要があります.

下図のように,Pythonでサクッと計算・可視化して確認できるといいですよね.

スクリーンショット 2025-07-05 9.20.09.jpg

このプログラムでのポイントは,
1.最初に何個の質量の総和を求めたいのか,個数を指定できる
2.質量と3次元空間の座標値をダイアログボックスにて入力できる
3.3次元プロットで可視化
 ①個別の質量は,青丸印で表示
 ②トータルの質量は,赤丸印で表示
 ③質量に応じて丸印の大きさが異なる
 ④質量と重心位置の座標値をプロット内に表示

実行方法は,コマンドプロンプト(Macではターミナル)で以下を実行

python3 calc_total_cg.py
calc_total_cg.py
# coding: utf-8
import tkinter as tk
from tkinter import simpledialog, messagebox
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

def get_mass_points_from_dialog():
    """
    Accepts mass point information as input from dialog boxes.
    Returns:
        list: A list of [mass, x, y, z] for each mass point.
    """
    mass_points = []
    while True:
        try:
            # Ask the user for the number of mass points
            num_points_str = simpledialog.askstring("Mass Point Input", "Enter the number of mass points (e.g., 3):")
            if num_points_str is None: # If canceled
                return None
            num_points = int(num_points_str)
            if num_points <= 0:
                raise ValueError("The number of mass points must be a positive integer.")
            break
        except ValueError as e:
            messagebox.showerror("Input Error", str(e))
        except TypeError: # If NoneType (e.g., Cancel button pressed)
            return None

    for i in range(num_points):
        while True:
            try:
                # Enter mass and coordinates for each mass point
                input_str = simpledialog.askstring(f"Mass Point {i+1} Input",
                                                    f"Enter mass (kg) and coordinates (x, y, z) for mass point {i+1}, separated by commas.\nExample: 10, 1.0, 2.0, 3.0")
                if input_str is None: # If canceled
                    return None
                parts = [float(p.strip()) for p in input_str.split(',')]
                if len(parts) != 4:
                    raise ValueError("Please enter 4 values: mass and 3 coordinates (x, y, z).")
                mass, x, y, z = parts
                if mass < 0:
                    raise ValueError("Mass cannot be negative.")
                mass_points.append([mass, x, y, z])
                break
            except ValueError as e:
                messagebox.showerror("Input Error", str(e))
            except Exception as e:
                messagebox.showerror("Error", f"An unexpected error occurred: {e}")
    return mass_points

def calculate_center_of_gravity(mass_points):
    """
    Calculates the center of gravity for multiple mass points.
    Args:
        mass_points (list): A list of [mass, x, y, z] for each mass point.
    Returns:
        tuple: (Total Mass, CoG_x, CoG_y, CoG_z)
               or None (if no input).
    """
    if not mass_points:
        return None

    total_mass = sum(mp[0] for mp in mass_points)
    if total_mass == 0:
        messagebox.showwarning("Calculation Warning", "Total mass is 0, so CoG cannot be calculated.")
        return 0, 0, 0, 0 # If total mass is 0, return origin or handle as an error

    sum_mx = sum(mp[0] * mp[1] for mp in mass_points)
    sum_my = sum(mp[0] * mp[2] for mp in mass_points)
    sum_mz = sum(mp[0] * mp[3] for mp in mass_points)

    cog_x = sum_mx / total_mass
    cog_y = sum_my / total_mass
    cog_z = sum_mz / total_mass

    return total_mass, cog_x, cog_y, cog_z

def plot_3d_points(mass_points, cog_info):
    """
    Plots mass points and the center of gravity in 3D space.
    Args:
        mass_points (list): A list of [mass, x, y, z] for each mass point.
        cog_info (tuple): (Total Mass, CoG_x, CoG_y, CoG_z).
    """
    fig = plt.figure(figsize=(10, 8))
    ax = fig.add_subplot(111, projection='3d')

    # Calculate max individual mass for scaling reference
    max_individual_mass = max(mp[0] for mp in mass_points) if mass_points else 1

    # Plot each mass point
    for i, mp in enumerate(mass_points):
        mass, x, y, z = mp
        # Scale blue marker size relative to its mass.
        # Max marker size for individual points is about 200, min is 20.
        # This makes sure smaller points are still visible.
        marker_size = max(20, (mass / max_individual_mass) * 200)
        ax.scatter(x, y, z, color='blue', s=marker_size, label=f'Mass Point {i+1}' if i == 0 else "", alpha=0.7)
        ax.text(x, y, z, f'M: {mass}kg\n({x:.1f},{y:.1f},{z:.1f})', color='blue')

    # Plot the total center of gravity
    if cog_info:
        total_mass, cog_x, cog_y, cog_z = cog_info
        # Scale red marker size based on total mass, significantly larger than individual points.
        # This uses the total mass relative to the max individual mass for a more intuitive scale.
        # Minimum size 100, larger points will be scaled up from there.
        cog_marker_size = max(100, (total_mass / max_individual_mass) * 300)
        ax.scatter(cog_x, cog_y, cog_z, color='red', marker='o', s=cog_marker_size, label='Center of Gravity', edgecolor='black', linewidth=0.8)
        ax.text(cog_x, cog_y, cog_z, f'Total Mass: {total_mass:.2f}kg\nCoG: ({cog_x:.2f},{cog_y:.2f},{cog_z:.2f})', color='red', fontsize=10, ha='right')

    ax.set_xlabel('X-axis')
    ax.set_ylabel('Y-axis')
    ax.set_zlabel('Z-axis')
    ax.set_title('Mass Points and Center of Gravity in 3D Space')
    ax.legend()
    ax.grid(True)
    plt.show()

# Hide the Tkinter root window
root = tk.Tk()
root.withdraw()

# Get mass point data
mass_points_data = get_mass_points_from_dialog()

if mass_points_data:
    # Calculate CoG
    center_of_gravity_info = calculate_center_of_gravity(mass_points_data)

    if center_of_gravity_info is not None:
        # Plot the results
        plot_3d_points(mass_points_data, center_of_gravity_info)
    else:
        messagebox.showinfo("Information", "No mass point data entered. Exiting process.")
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?