wiki/mandates/pek/testing/create_bostich_3ds_fixed.py
ValueOn AG 15f0e51bd0 pek
2025-10-24 21:42:47 +02:00

279 lines
10 KiB
Python

#!/usr/bin/env python3
"""
Create proper 3DS file for LEITZ Bostitch 2-hole punch
Fixed format for AutoCAD compatibility
"""
import struct
import math
def _write3dsChunk(f, chunk_id, data):
"""Write a 3DS chunk with proper format"""
chunk_size = len(data) + 6 # 6 bytes for chunk header
f.write(struct.pack('<H', chunk_id)) # Chunk ID (little endian)
f.write(struct.pack('<I', chunk_size)) # Chunk size (little endian)
f.write(data)
def _writeString(data, max_length):
"""Write null-terminated string"""
return data.encode('ascii')[:max_length-1].ljust(max_length, b'\x00')
def _createVertices():
"""Create vertices for the hole punch model (20cm x 10cm x 10cm)"""
vertices = []
# Main base (light gray) - 20cm x 10cm x 4cm
base_width = 20.0
base_depth = 10.0
base_height = 4.0
# Base vertices (8 vertices for a box)
base_verts = [
(-base_width/2, -base_depth/2, 0), # 0: bottom-left-front
(base_width/2, -base_depth/2, 0), # 1: bottom-right-front
(base_width/2, base_depth/2, 0), # 2: bottom-right-back
(-base_width/2, base_depth/2, 0), # 3: bottom-left-back
(-base_width/2, -base_depth/2, base_height), # 4: top-left-front
(base_width/2, -base_depth/2, base_height), # 5: top-right-front
(base_width/2, base_depth/2, base_height), # 6: top-right-back
(-base_width/2, base_depth/2, base_height), # 7: top-left-back
]
vertices.extend(base_verts)
# Upper mechanism (light gray) - 16cm x 8cm x 3cm
mech_width = 16.0
mech_depth = 8.0
mech_height = 3.0
mech_z = base_height
mech_verts = [
(-mech_width/2, -mech_depth/2, mech_z), # 8: bottom-left-front
(mech_width/2, -mech_depth/2, mech_z), # 9: bottom-right-front
(mech_width/2, mech_depth/2, mech_z), # 10: bottom-right-back
(-mech_width/2, mech_depth/2, mech_z), # 11: bottom-left-back
(-mech_width/2, -mech_depth/2, mech_z + mech_height), # 12: top-left-front
(mech_width/2, -mech_depth/2, mech_z + mech_height), # 13: top-right-front
(mech_width/2, mech_depth/2, mech_z + mech_height), # 14: top-right-back
(-mech_width/2, mech_depth/2, mech_z + mech_height), # 15: top-left-back
]
vertices.extend(mech_verts)
# Lever (dark blue) - 12cm x 6cm x 2cm, curved
lever_width = 12.0
lever_depth = 6.0
lever_height = 2.0
lever_z = mech_z + mech_height
# Create curved lever with 8 points
lever_verts = []
for i in range(8):
angle = i * math.pi / 7 # 0 to π for half-circle
x = (lever_width/2) * math.cos(angle)
y = (lever_depth/2) * math.sin(angle)
lever_verts.append((x, y, lever_z))
lever_verts.append((x, y, lever_z + lever_height))
vertices.extend(lever_verts)
# Paper guide (white) - 2cm x 8cm x 0.5cm
guide_width = 2.0
guide_depth = 8.0
guide_height = 0.5
guide_x = base_width/2 + 1.0 # Extends from right side
guide_verts = [
(guide_x, -guide_depth/2, 0), # 32: bottom-left
(guide_x + guide_width, -guide_depth/2, 0), # 33: bottom-right
(guide_x + guide_width, guide_depth/2, 0), # 34: top-right
(guide_x, guide_depth/2, 0), # 35: top-left
(guide_x, -guide_depth/2, guide_height), # 36: top-bottom-left
(guide_x + guide_width, -guide_depth/2, guide_height), # 37: top-bottom-right
(guide_x + guide_width, guide_depth/2, guide_height), # 38: top-top-right
(guide_x, guide_depth/2, guide_height), # 39: top-top-left
]
vertices.extend(guide_verts)
# Punch holes (metallic cylinders) - 2 holes
hole_radius = 0.3
hole_height = 8.0
hole_positions = [(-2.0, 0), (2.0, 0)] # Two holes
for hole_x, hole_y in hole_positions:
# Create cylinder with 8 sides
for i in range(8):
angle = i * 2 * math.pi / 8
x = hole_x + hole_radius * math.cos(angle)
y = hole_y + hole_radius * math.sin(angle)
vertices.append((x, y, mech_z))
vertices.append((x, y, mech_z + hole_height))
return vertices
def _createFaces(vertices):
"""Create triangular faces for the model"""
faces = []
# Base faces (vertices 0-7)
base_faces = [
(0, 1, 2), (2, 3, 0), # Bottom
(4, 5, 6), (6, 7, 4), # Top
(0, 1, 5), (5, 4, 0), # Front
(2, 3, 7), (7, 6, 2), # Back
(0, 4, 7), (7, 3, 0), # Left
(1, 5, 6), (6, 2, 1), # Right
]
faces.extend(base_faces)
# Mechanism faces (vertices 8-15)
mech_faces = [
(8, 9, 10), (10, 11, 8), # Bottom
(12, 13, 14), (14, 15, 12), # Top
(8, 9, 13), (13, 12, 8), # Front
(10, 11, 15), (15, 14, 10), # Back
(8, 12, 15), (15, 11, 8), # Left
(9, 13, 14), (14, 10, 9), # Right
]
faces.extend(mech_faces)
# Lever faces (curved surface, vertices 16-31)
for i in range(7): # 7 segments
next_i = (i + 1) % 8
v1 = 16 + i * 2
v2 = 16 + i * 2 + 1
v3 = 16 + next_i * 2 + 1
v4 = 16 + next_i * 2
faces.append((v1, v2, v3))
faces.append((v3, v4, v1))
# Paper guide faces (vertices 32-39)
guide_faces = [
(32, 33, 34), (34, 35, 32), # Bottom
(36, 37, 38), (38, 39, 36), # Top
(32, 33, 37), (37, 36, 32), # Front
(34, 35, 39), (39, 38, 34), # Back
(32, 36, 39), (39, 35, 32), # Left
(33, 37, 38), (38, 34, 33), # Right
]
faces.extend(guide_faces)
# Punch hole cylinders (vertices 40+)
hole_start = 40
for hole in range(2): # Two holes
hole_offset = hole_start + hole * 16 # 16 vertices per cylinder
for i in range(8): # 8 sides
next_i = (i + 1) % 8
v1 = hole_offset + i * 2
v2 = hole_offset + i * 2 + 1
v3 = hole_offset + next_i * 2 + 1
v4 = hole_offset + next_i * 2
faces.append((v1, v2, v3))
faces.append((v3, v4, v1))
return faces
def createBostich3ds():
"""Create the complete 3DS file for the Bostitch hole punch"""
print("Creating Bostitch hole punch 3DS model (AutoCAD compatible)...")
# Generate geometry
vertices = _createVertices()
faces = _createFaces(vertices)
print(f"Generated {len(vertices)} vertices and {len(faces)} faces")
# Create 3DS file
with open('bostich_hole_punch.3ds', 'wb') as f:
# Write main chunk header
f.write(b'\x4D\x4D') # Magic number
f.write(struct.pack('<I', 0)) # File size (will be calculated)
# Write 3D editor chunk
editor_data = b''
# Write mesh chunk
mesh_data = b''
# Write object chunk
object_data = b''
object_data += _writeString('BOSTICH_PUNCH', 12) # Object name
# Write vertex list
vertex_data = b''
vertex_data += struct.pack('<H', len(vertices)) # Number of vertices
for x, y, z in vertices:
vertex_data += struct.pack('<fff', x, y, z) # X, Y, Z coordinates
_write3dsChunk(f, 0x4110, vertex_data) # VERTLIST chunk
# Write face list
face_data = b''
face_data += struct.pack('<H', len(faces)) # Number of faces
for face in faces:
face_data += struct.pack('<HHH', face[0], face[1], face[2]) # Three vertex indices
face_data += struct.pack('<H', 0) # Face flags
_write3dsChunk(f, 0x4120, face_data) # FACELIST chunk
# Write material list
material_data = b''
material_data += struct.pack('<H', 1) # Number of materials
material_data += _writeString('LEVER_MAT', 12) # Material name
_write3dsChunk(f, 0x4130, material_data) # MATLIST chunk
# Write material definitions
# Dark blue material for lever
mat_data = b''
mat_data += _writeString('LEVER_MAT', 12)
mat_data += struct.pack('<fff', 0.2, 0.2, 0.6) # Diffuse color (dark blue)
mat_data += struct.pack('<fff', 0.1, 0.1, 0.3) # Ambient color
mat_data += struct.pack('<fff', 0.8, 0.8, 0.9) # Specular color
mat_data += struct.pack('<f', 100.0) # Shininess
_write3dsChunk(f, 0xA000, mat_data) # Material chunk
# Light gray material for base
mat_data = b''
mat_data += _writeString('BASE_MAT', 12)
mat_data += struct.pack('<fff', 0.7, 0.7, 0.7) # Diffuse color (light gray)
mat_data += struct.pack('<fff', 0.3, 0.3, 0.3) # Ambient color
mat_data += struct.pack('<fff', 0.2, 0.2, 0.2) # Specular color
mat_data += struct.pack('<f', 50.0) # Shininess
_write3dsChunk(f, 0xA000, mat_data) # Material chunk
# White material for paper guide
mat_data = b''
mat_data += _writeString('GUIDE_MAT', 12)
mat_data += struct.pack('<fff', 0.9, 0.9, 0.9) # Diffuse color (white)
mat_data += struct.pack('<fff', 0.8, 0.8, 0.8) # Ambient color
mat_data += struct.pack('<fff', 0.1, 0.1, 0.1) # Specular color
mat_data += struct.pack('<f', 30.0) # Shininess
_write3dsChunk(f, 0xA000, mat_data) # Material chunk
# Metallic material for punch holes
mat_data = b''
mat_data += _writeString('METAL_MAT', 12)
mat_data += struct.pack('<fff', 0.6, 0.6, 0.6) # Diffuse color (metallic gray)
mat_data += struct.pack('<fff', 0.2, 0.2, 0.2) # Ambient color
mat_data += struct.pack('<fff', 0.9, 0.9, 0.9) # Specular color
mat_data += struct.pack('<f', 200.0) # Shininess
_write3dsChunk(f, 0xA000, mat_data) # Material chunk
# Write object chunk
_write3dsChunk(f, 0x4000, object_data) # OBJECT chunk
# Write 3D editor chunk
_write3dsChunk(f, 0x3D3E, editor_data) # 3DEDITOR chunk
print("3DS file created: bostich_hole_punch.3ds")
print("Dimensions: 20cm x 10cm x 10cm")
print("Materials: Dark blue lever, light gray base, white paper guide, metallic punch holes")
print("Format: AutoCAD compatible 3DS")
if __name__ == "__main__":
createBostich3ds()