「ブロック作品を LeoCAD でつくる3 〜発注その1〜」
https://qiita.com/nanbuwks/items/2208a73c6f9a9787c856
の続きです。
前回は、CAD に落とし込んだ4階建てエレベーターから CSV のパーツリストを作って発注を行いましたが、
パーツが約2100 pcs、種類も約300 の作業を行うにあたっていろいろと問題がありました。
- カートに入れるのが大変。間違いや漏れが多々発生する
- 組み立て時に部分ごとにパーツが別れた状態でないと日効率
今回はこれを解決するための方法を考えます。
submodel
以下のようにLeoCAD内では submodel に分けて管理をしています。
一番上の whole.ldr が全体構成です。
submodel 単位で発注を行い、パーツを分けて組み立てて行きたいですね。
上記表示では Machine1.ldr という名前がついていて、いかにもファイル名ぽいですがこのままだとこのサブモジュールのパーツの把握ができません。
Timeline でパーツのリストが出てきますが、パーツ番号などは表示されず役に立たないです。
Submodels 画面から、Exportを行うい、それぞれを読み込み直して CSV にエクスポートすればなんとかなるかも知れませんが、 Submodel が多いと手間がかかって仕方が無いですね!
ldr フォーマット
LeoCAD のファイルは ldr 形式なのですが、中身はテキストとして読める形式です。今回のブロックエレベータの ldr ファイルは以下のようになってました。
0 FILE whole.ldr
0
0 Name: whole.ldr
0 Author:
1 7 420 -800 300 0 0 -1 0 1 0 1 0 0 weights.ldr
1 7 20 -460 -180 1 0 0 0 1 0 0 0 1 kagos.ldr
1 7 3 0 1 1 0 0 0 1 0 0 0 1 Frames.ldr
1 295 151 -1470 -160 -1 0 0 0 1 0 0 0 -1 Machines.ldr
1 7 37 -198 -122 -1 0 0 0 1 0 0 0 -1 Floor1F.ldr
1 7 37 -518 -122 -1 0 0 0 1 0 0 0 -1 Floor2F.ldr
1 7 37 -818 -122 -1 0 0 0 1 0 0 0 -1 Floor3F.ldr
1 7 37 -1158 -122 -1 0 0 0 1 0 0 0 -1 Floor4F.ldr
0 NOFILE
0 FILE Frames.ldr
0
0 Name: Frames.ldr
0 Author:
1 7 0 -1 -1 1 0 0 0 1 0 0 0 1 KagoWeightSwitchRail.ldr
0 !LEOCAD PIECE PIVOT 130 -176 470 1 0 0 0 1 0 0 0 1
.
.
.
1 7 118.8387 -586.0504 250 -0.882948 0 -0.469472 0.469472 0 -0.882948 0 -1 0 Back-Frame1.ldr
1 7 -123.8575 -556.2504 252 -0.882948 0 0.469471 -0.469472 0 -0.882948 0 -1 0 back-Frame2.ldr
1 7 326 -1173.2727 260.7273 0 0 -1 0 1 0 1 0 0 6541.dat
1 7 306 -1148 261 0 0 1 0 1 0 -1 0 0 63325.dat
1 7 326 -1140.2727 260.7273 0 0 -1 0 1 0 1 0 0 63326.dat
1 7 326 -1087.2727 260.7273 0 0 -1 0 1 0 1 0 0 6541.dat
1 7 306 -1096 261 0 0 1 0 1 0 -1 0 0 63325.dat
1 7 326 -1104.2727 260.7273 0 0 -1 0 1 0 1 0 0 63326.dat
1 7 336 -1162.2727 260.7273 1 0 0 0 1 0 0 0 1 32002.dat
1 7 336 -1079.2727 260.7273 1 0 0 0 1 0 0 0 1 32002.dat
1 7 341 -1121.2727 259.7273 0 -1 0 0 0 -1 1 0 0 32017.dat
1 7 326 -532.2727 260.7273 0 0 -1 0 1 0 1 0 0 6541.dat
1 7 306 -507 261 0 0 1 0 1 0 -1 0 0 63325.dat
.
.
.
ふむ、これは CSV として読んだらうまく加工できそうです。
.
.
.
B列が色コードです。
色コード例
0 | Black |
1 | Blue |
2 | Green |
4 | Red |
5 | Dark Pink |
7 | Light Grey |
10 | Bright Green |
12 | Salmon |
15 | White |
18 | Light Yellow |
25 | Orange |
47 | Trans Clear |
134 | Copper |
226 | Bright Light Yellow |
csv を Spreadsheet に読み込んで手作業をすれば submodel ごとの パーツリストが作れそう・・・ですが手作業がメンドクサイので、python で csv を作るようにしてみました。
python プログラム
chatGPT で作ったもののに手を加えて、以下のようなものを作りました。
2025-9-10 改訂:当初のものはカラーマップがデタラメでした。修正しています。
#!/bin/env python3
import os
import csv
from collections import defaultdict
# 色のマッピング(仮定)
COLOR_MAP = {
'0': 'Black',
'1': 'Blue',
'2': 'Green',
'3': 'Dark_Turquoise',
'4': 'Red',
'5': 'Dark_Pink',
'6': 'Brown',
'7': 'Light_Gray',
'8': 'Dark_Grey',
'9': 'Light_Blue',
'10': 'Bright_Green',
'11': 'Light_Turquoise',
'12':'Salmon',
'15': 'White',
'16': 'Main_Colour',
'18': 'Light Yellow',
'23': 'Dark_Blue_Violet',
'25': 'Orange',
'47': 'Trans Clear',
'134':'Copper',
'226':'Bright Light Yellow',
'368':'Vibrant Yellow'
'3': 'Light Gray',
'4': 'White',
'5': 'Red',
'6': 'Bright Green',
'7': 'Blue',
'8': 'Yellow',
'9': 'Tan',
'10': 'Dark Brown',
'11': 'Light Brown',
'16': 'Dark Blue',
'23': 'Bright Light Orange',
'12':'Salmon',
'15':'White',
'18':'Light Yellow',
'25':'Orange',
'47':'Trans Clear',
'134':'Copper',
'226':'Bright Light Yellow',
'368':'Vibrant Yellow'
# 必要に応じて追加
}
def parse_ldr_file(filepath):
submodels = {}
current_model = None
parts = defaultdict(list)
with open(filepath, 'r', encoding='utf-8') as file:
for line in file:
line = line.strip()
if line.startswith("0 FILE"):
current_model = line.split(" ", 2)[2]
if current_model not in parts:
parts[current_model] = []
elif line.startswith("1 ") and current_model:
tokens = line.split()
part_name = tokens[-1] # 最後のトークンが部品名(例: 3001.dat)
color_code = tokens[1] # 2番目のトークンがカラーコード
parts[current_model].append((part_name, color_code))
# サブモデル名 -> パーツの出現回数とカラーコード(辞書)
submodel_parts = {}
for model_name, part_list in parts.items():
part_counts = defaultdict(lambda: defaultdict(int)) # {part_name: {color_code: count}}
for part_name, color_code in part_list:
part_counts[part_name][color_code] += 1
submodel_parts[model_name] = part_counts
return submodel_parts
def export_to_csv(submodel_parts, output_dir):
os.makedirs(output_dir, exist_ok=True)
for model_name, parts in submodel_parts.items():
base_name = os.path.splitext(model_name)[0]
csv_filename = os.path.join(output_dir, f"{base_name}.csv")
with open(csv_filename, 'w', newline='', encoding='utf-8') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(['Part Name', 'Color Code', 'Color Name', 'Quantity'])
for part_name, color_counts in sorted(parts.items()):
if part_name.endswith('.ldr'):
continue
for color_code, count in sorted(color_counts.items()):
color_name = COLOR_MAP.get(color_code, 'Unknown')
writer.writerow([part_name.rstrip('.dat'), color_code, color_name, count])
print(f"✅ Exported: {csv_filename}")
def main():
input_ldr_file = "20250521.ldr" # <- ここを処理したい LDR ファイルに変更
output_folder = "output_parts_with_colors"
submodel_parts = parse_ldr_file(input_ldr_file)
export_to_csv(submodel_parts, output_folder)
if __name__ == "__main__":
main()
できたcsvファイルです。
$ ls output_parts_with_colors/
12FBoardHolder.csv Floor3F.csv LEFT-RIGHT-Back-VerticalRF.csv 'Merged Floor202409.csv' Vertical-Frame234F.csv kago-4.csv kagos.csv wire.csv
34FBoardHolder.csv Floor4F.csv Left-Frame1F.csv Right-Frame1F.csv Vertical-FrameRF.csv kago-5.csv parts.csv
'BASE&1F.csv' Frames.csv Left-Frame234F.csv Right-Frame234F.csv back-Frame2.csv kago-6か.csv weight1.csv
Back-Frame1.csv Front-RF.csv Left-FrameRF.csv Right-FrameRF.csv back-frame-rf.csv kago-7.csv weight2.csv
Floor.csv KagoWeightSwitchRail.csv Machine1.csv Vertical-Frame-Composite.csv back-frame.csv kago1.csv weight3う.csv
Floor1F.csv LEFT-RIGHT-Back-Vertical1F.csv Machine2.csv Vertical-Frame1F.csv base-Frame.csv kago2.csv weights.csv
Floor2F.csv LEFT-RIGHT-Back-Vertical234F.csv Machines.csv Vertical-Frame2.csv kago-3.csv kago6.csv whole.csv
$ cat output_parts_with_colors/12FBoardHolder.csv
Part Name,Color Code,Color Name,Quantity
32278,7,Blue,2
32316,7,Blue,1
32523,7,Blue,1
32556,7,Blue,4
3704,7,Blue,4
42003,7,Blue,2
4459,7,Blue,10
6632,7,Blue,2
これを元に、発注していきます。
今回は、タオバオで発注してみました。
Chat とメールを併用して交渉。
カスタム設計部品注文用に用意されているアイテムで値段を合わせて注文します。