Upstream Snapshot bb87928bce Import upstream snapshot 80e710700aac9573a2230f74f7ce9e094833a0bc
Upstream: https://github.com/Rhoban/onshape-to-robot
Upstream-Commit: 80e710700aac9573a2230f74f7ce9e094833a0bc
Upstream-Branch: master
2026-08-28 15:42:31 +08:00

158 lines
5.9 KiB
Python

def main():
import numpy as np
import math
import commentjson as json
import os
import sys, os
from dotenv import load_dotenv, find_dotenv
from colorama import Fore, Back, Style
load_dotenv(find_dotenv(usecwd=True))
if len(sys.argv) < 2:
print("Usage: onshape-to-robot-pure-shape {STL file} [prefix=PureShapes]")
else:
fileName = sys.argv[1]
robotDir = os.path.dirname(fileName)
configFile = os.path.join(robotDir, "config.json")
prefix = "PureShapes"
if len(sys.argv) > 2:
prefix = sys.argv[2]
from .onshape_api.client import Client
client = Client(logging=False, creds=configFile)
parts = fileName.split(".")
parts[-1] = "part"
partFileName = ".".join(parts)
parts[-1] = "scad"
scadFileName = ".".join(parts)
with open(partFileName, "r", encoding="utf-8") as stream:
part = json.load(stream)
partid = part["partId"]
result = client.get_sketches(
part["documentId"],
part["documentMicroversion"],
part["elementId"],
part["configuration"],
)
scad = '% scale(1000) import("' + os.path.basename(fileName) + '");\n'
sketchDatas = []
for sketch in result["sketches"]:
if sketch["sketch"].startswith(prefix):
parts = sketch["sketch"].split(" ")
if len(parts) >= 2:
sketch["thickness"] = float(parts[1])
else:
print(
Fore.RED
+ 'ERROR: The sketch name should contain extrusion size (e.g "PureShapes 5.3")'
+ Style.RESET_ALL
)
exit(0)
sketchDatas.append(sketch)
if len(sketchDatas):
print(
Fore.GREEN
+ "* Found "
+ str(len(sketchDatas))
+ " PureShapes sketches"
+ Style.RESET_ALL
)
for sketchData in sketchDatas:
# Retrieving sketch transform matrix
m = sketchData["transformMatrix"]
mm = [m[0:4], m[4:8], m[8:12], m[12:16]]
mm[0][3] *= 1000
mm[1][3] *= 1000
mm[2][3] *= 1000
scad += "\n"
scad += "// Sketch " + sketchData["sketch"] + "\n"
scad += "multmatrix(" + str(mm) + ") {" + "\n"
scad += "thickness = %f;\n" % sketchData["thickness"]
scad += "translate([0, 0, -thickness]) {\n"
boxes = {}
def boxSet(id, pointName, point):
if id not in boxes:
boxes[id] = {}
boxes[id][pointName] = point
for entry in sketchData["geomEntities"]:
if entry["entityType"] == "circle":
center = entry["center"]
scad += " translate([%f, %f, 0]) {\n" % (
center[0] * 1000,
center[1] * 1000,
)
scad += " cylinder(r=%f,h=thickness);\n" % (
entry["radius"] * 1000
)
scad += " }\n"
if entry["entityType"] == "point":
parts = entry["id"].split(".")
if len(parts) == 3:
if parts[1] == "top" and parts[2] == "start":
boxSet(parts[0], "A", entry["point"])
if parts[1] == "top" and parts[2] == "end":
boxSet(parts[0], "B", entry["point"])
if parts[1] == "bottom" and parts[2] == "start":
boxSet(parts[0], "C", entry["point"])
if parts[1] == "bottom" and parts[2] == "end":
boxSet(parts[0], "D", entry["point"])
for id in boxes:
if len(boxes[id]) == 4:
A, B = np.array(boxes[id]["A"]), np.array(boxes[id]["B"])
C, D = np.array(boxes[id]["C"]), np.array(boxes[id]["D"])
AB = B - A
# Making sure that the orientation of the square is correct
AB90 = np.array([-AB[1], AB[0]])
side = AB90.dot(C - A)
width = np.linalg.norm(B - A)
height = np.linalg.norm(B - D)
if side < 0:
A, B, C, D = C, D, A, B
AB = B - A
alpha = np.rad2deg(math.atan2(AB[1], AB[0]))
scad += " translate([%f, %f, 0]) {\n" % (
A[0] * 1000,
A[1] * 1000,
)
scad += " rotate([0, 0, " + str(alpha) + "]) {" + "\n"
scad += " cube([%f, %f, thickness]);\n" % (
width * 1000,
height * 1000,
)
scad += " }\n"
scad += " }\n"
scad += "}\n"
scad += "}\n"
with open(scadFileName, "w", encoding="utf-8") as stream:
stream.write(scad)
directory = os.path.dirname(fileName)
os.system(
"cd " + directory + "; openscad " + os.path.basename(scadFileName)
)
else:
print(
Fore.RED
+ "ERROR: Can't find pure shape sketch in this part"
+ Style.RESET_ALL
)
if __name__ == "__main__":
main()