Add DB9 CAD reference data
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016 Adafruit Industries
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,2 @@
|
||||
# Adafruit_CAD_Parts
|
||||
STEP, Fusion 360, and STL files for various boards, components and parts
|
||||
@@ -0,0 +1,86 @@
|
||||
"""Read pinned STEP B-rep; write reproducible solid/face measurements beside it."""
|
||||
import json
|
||||
import re
|
||||
from pathlib import Path
|
||||
from OCP.STEPControl import STEPControl_Reader
|
||||
from OCP.IFSelect import IFSelect_RetDone
|
||||
from OCP.TopExp import TopExp_Explorer
|
||||
from OCP.TopAbs import TopAbs_SOLID, TopAbs_FACE
|
||||
from OCP.TopoDS import TopoDS
|
||||
from OCP.Bnd import Bnd_Box
|
||||
from OCP.BRepBndLib import BRepBndLib
|
||||
from OCP.BRepAdaptor import BRepAdaptor_Surface
|
||||
from OCP.GeomAbs import GeomAbs_Cylinder, GeomAbs_Plane
|
||||
from OCP.BRepCheck import BRepCheck_Analyzer
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
|
||||
def bounds(s):
|
||||
b = Bnd_Box()
|
||||
BRepBndLib.AddOptimal_s(s, b, False, False)
|
||||
return list(b.Get())
|
||||
|
||||
def xyz(p):
|
||||
return [p.X(), p.Y(), p.Z()]
|
||||
|
||||
r = STEPControl_Reader()
|
||||
assert r.ReadFile(str(HERE / '5988 RS-232 Level Shifter.step')) == IFSelect_RetDone
|
||||
r.TransferRoots()
|
||||
entities = dict(re.findall(r'#(\d+)\s*=\s*(.*?);', (HERE / '5988 RS-232 Level Shifter.step').read_text(), re.S))
|
||||
styles = {}
|
||||
for text in entities.values():
|
||||
if text.startswith('STYLED_ITEM('):
|
||||
refs = re.findall(r'#(\d+)', text)
|
||||
styles[refs[-1]] = refs[:-1]
|
||||
|
||||
def colors(refs, seen=None):
|
||||
seen = set() if seen is None else seen
|
||||
result = []
|
||||
for ref in refs:
|
||||
if ref in seen:
|
||||
continue
|
||||
seen.add(ref)
|
||||
text = entities[ref]
|
||||
if text.startswith('COLOUR_RGB('):
|
||||
result.append(text.replace('\n', ''))
|
||||
else:
|
||||
result.extend(colors(re.findall(r'#(\d+)', text), seen))
|
||||
return result
|
||||
|
||||
e = TopExp_Explorer(r.OneShape(), TopAbs_SOLID)
|
||||
out = []
|
||||
while e.More():
|
||||
s = TopoDS.Solid_s(e.Current())
|
||||
item = dict(id=len(out)+1, bounds=bounds(s), valid=BRepCheck_Analyzer(s).IsValid(), faces=[])
|
||||
f = TopExp_Explorer(s, TopAbs_FACE)
|
||||
while f.More():
|
||||
face = TopoDS.Face_s(f.Current())
|
||||
a = BRepAdaptor_Surface(face)
|
||||
# These unique bodies retain CLOSED_SHELL face order on this pinned import.
|
||||
shell_id = {1: '14428', 12: '14431', 13: '14432', 14: '14433'}.get(item['id'])
|
||||
refs = re.findall(r'#(\d+)', entities[shell_id]) if shell_id else []
|
||||
step_id = refs[len(item['faces'])] if refs else '0'
|
||||
if refs:
|
||||
surface_id = re.findall(r'#(\d+)', entities[step_id])[-1]
|
||||
surface = entities[surface_id]
|
||||
expected = str(a.GetType()).split('_')[-1].upper()
|
||||
assert surface.startswith({'PLANE': 'PLANE(', 'CYLINDER': 'CYLINDRICAL_SURFACE(', 'CONE': 'CONICAL_SURFACE(', 'TORUS': 'TOROIDAL_SURFACE('}[expected])
|
||||
if a.GetType() == GeomAbs_Cylinder:
|
||||
assert abs(float(surface.rsplit(',', 1)[1].rstrip(')')) - a.Cylinder().Radius()) < 1e-8
|
||||
row = dict(id=len(item['faces'])+1, bounds=bounds(face), type=str(a.GetType()), orientation=str(face.Orientation()))
|
||||
row.update(step_id=step_id, colors=colors(styles.get(step_id, [])))
|
||||
if a.GetType() == GeomAbs_Cylinder:
|
||||
c = a.Cylinder()
|
||||
row.update(radius=c.Radius(), location=xyz(c.Location()), axis=xyz(c.Axis().Direction()))
|
||||
elif a.GetType() == GeomAbs_Plane:
|
||||
p = a.Plane()
|
||||
row.update(location=xyz(p.Location()), normal=xyz(p.Axis().Direction()))
|
||||
item['faces'].append(row)
|
||||
f.Next()
|
||||
if shell_id:
|
||||
assert len(item['faces']) == len(refs)
|
||||
out.append(item)
|
||||
e.Next()
|
||||
(HERE / 'geometry.json').write_text(json.dumps(out, indent=2)+'\n')
|
||||
for s in out:
|
||||
print(s['id'], 'valid', s['valid'], 'bounds', [round(v,6) for v in s['bounds']], 'faces', len(s['faces']))
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,207 @@
|
||||
{
|
||||
"front_flange_exposed_faces": {
|
||||
"solid": 12,
|
||||
"faces": [
|
||||
8,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14
|
||||
],
|
||||
"bounds": [
|
||||
0.47499999999999787,
|
||||
27.006999999999998,
|
||||
1.5726202399843388,
|
||||
31.275000000000002,
|
||||
27.407,
|
||||
14.1226202399843
|
||||
],
|
||||
"dimensions": [
|
||||
30.800000000000004,
|
||||
0.40000000000000213,
|
||||
12.549999999999962
|
||||
]
|
||||
},
|
||||
"shell_straight_outer_surface": {
|
||||
"solid": 12,
|
||||
"faces": [
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25
|
||||
],
|
||||
"bounds": [
|
||||
8.035981107410171,
|
||||
28.006999999999998,
|
||||
3.89762023998434,
|
||||
23.71401889258985,
|
||||
32.607,
|
||||
11.79762023998434
|
||||
],
|
||||
"dimensions": [
|
||||
15.678037785179677,
|
||||
4.600000000000001,
|
||||
7.9
|
||||
]
|
||||
},
|
||||
"shell_outer_including_root_and_lip": {
|
||||
"solid": 12,
|
||||
"faces": [
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
81,
|
||||
82,
|
||||
83,
|
||||
84,
|
||||
85,
|
||||
86,
|
||||
87,
|
||||
88,
|
||||
103,
|
||||
104,
|
||||
105,
|
||||
106,
|
||||
107,
|
||||
108,
|
||||
109,
|
||||
110
|
||||
],
|
||||
"bounds": [
|
||||
7.4359811074101705,
|
||||
27.406999999999996,
|
||||
3.29762023998434,
|
||||
24.31401889258985,
|
||||
33.207,
|
||||
12.397620239984342
|
||||
],
|
||||
"dimensions": [
|
||||
16.87803778517968,
|
||||
5.800000000000004,
|
||||
9.100000000000001
|
||||
]
|
||||
},
|
||||
"left_front_hex_post": {
|
||||
"solid": 12,
|
||||
"faces": [
|
||||
53,
|
||||
54,
|
||||
55,
|
||||
56,
|
||||
57,
|
||||
58,
|
||||
59,
|
||||
60,
|
||||
61,
|
||||
89
|
||||
],
|
||||
"bounds": [
|
||||
0.7191887617277004,
|
||||
27.407,
|
||||
5.547620239984319,
|
||||
6.030811238272291,
|
||||
32.207,
|
||||
10.147620239984366
|
||||
],
|
||||
"dimensions": [
|
||||
5.31162247654459,
|
||||
4.800000000000001,
|
||||
4.600000000000048
|
||||
]
|
||||
},
|
||||
"right_front_hex_post": {
|
||||
"solid": 12,
|
||||
"faces": [
|
||||
62,
|
||||
63,
|
||||
64,
|
||||
65,
|
||||
66,
|
||||
67,
|
||||
68,
|
||||
69,
|
||||
70,
|
||||
90
|
||||
],
|
||||
"bounds": [
|
||||
25.71918876172773,
|
||||
27.407,
|
||||
5.547620239984328,
|
||||
31.030811238272328,
|
||||
32.207,
|
||||
10.14762023998434
|
||||
],
|
||||
"dimensions": [
|
||||
5.311622476544599,
|
||||
4.800000000000001,
|
||||
4.600000000000012
|
||||
]
|
||||
},
|
||||
"front_lock_axes": [
|
||||
{
|
||||
"id": 60,
|
||||
"bounds": [
|
||||
1.875,
|
||||
27.407,
|
||||
6.34762023998434,
|
||||
4.875,
|
||||
32.007,
|
||||
9.34762023998434
|
||||
],
|
||||
"type": "GeomAbs_SurfaceType.GeomAbs_Cylinder",
|
||||
"orientation": "TopAbs_Orientation.TopAbs_REVERSED",
|
||||
"step_id": "13822",
|
||||
"colors": [
|
||||
"COLOUR_RGB('Opaque(245,245,246)',0.96078431372549,0.96078431372549,0.964705882352941)"
|
||||
],
|
||||
"radius": 1.5,
|
||||
"location": [
|
||||
3.375,
|
||||
32.207,
|
||||
7.84762023998434
|
||||
],
|
||||
"axis": [
|
||||
0.0,
|
||||
-1.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 69,
|
||||
"bounds": [
|
||||
26.875,
|
||||
27.407,
|
||||
6.34762023998434,
|
||||
29.875,
|
||||
32.007,
|
||||
9.34762023998434
|
||||
],
|
||||
"type": "GeomAbs_SurfaceType.GeomAbs_Cylinder",
|
||||
"orientation": "TopAbs_Orientation.TopAbs_REVERSED",
|
||||
"step_id": "13831",
|
||||
"colors": [
|
||||
"COLOUR_RGB('Opaque(245,245,246)',0.96078431372549,0.96078431372549,0.964705882352941)"
|
||||
],
|
||||
"radius": 1.5,
|
||||
"location": [
|
||||
28.375,
|
||||
32.207,
|
||||
7.84762023998434
|
||||
],
|
||||
"axis": [
|
||||
0.0,
|
||||
-1.0,
|
||||
0.0
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
[
|
||||
{
|
||||
"file": "5988 RS-232 Level Shifter.step",
|
||||
"url": "https://raw.githubusercontent.com/adafruit/Adafruit_CAD_Parts/5b8a21fb5e2e48478faf8901077be812f5224066/5988%20RS-232%20Level%20Shifter/5988%20RS-232%20Level%20Shifter.step",
|
||||
"sha256": "8eab9dc591a985fc987ceec2d7534e5e259263c73bebc64c0c3cd847e135906f"
|
||||
},
|
||||
{
|
||||
"file": "LICENSE",
|
||||
"url": "https://raw.githubusercontent.com/adafruit/Adafruit_CAD_Parts/5b8a21fb5e2e48478faf8901077be812f5224066/LICENSE",
|
||||
"sha256": "f60436644e066301d4c2e8f1f0674a157b1f60e4fd5586717b99dde255cc18cd"
|
||||
},
|
||||
{
|
||||
"file": "README.md",
|
||||
"url": "https://raw.githubusercontent.com/adafruit/Adafruit_CAD_Parts/5b8a21fb5e2e48478faf8901077be812f5224066/README.md",
|
||||
"sha256": "9ed9beac7600623b7b9bd0d02e1fdcd86610ce22966723179e6c6b618e399dce"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,46 @@
|
||||
"""Validate registration and selected face subsets; no board writes."""
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
D = json.loads((HERE / 'geometry.json').read_text())
|
||||
assert len(D) == 15 and all(s['valid'] for s in D)
|
||||
for source in json.loads((HERE / 'sources.json').read_text()):
|
||||
assert hashlib.sha256((HERE / source['file']).read_bytes()).hexdigest() == source['sha256']
|
||||
board = HERE.parent / 'Adafruit RS-232 Full Pinout Level-Shifter Breakout.brd'
|
||||
assert hashlib.sha256(board.read_bytes()).hexdigest() == '6a7b35ef909f5a2d243c326c34db3957aaa01275bf2aac8e0c749ff18162e870'
|
||||
root = ET.parse(board).getroot()
|
||||
b = root.find('drawing/board')
|
||||
jp = b.find("elements/element[@name='JP2']")
|
||||
pkg = b.find("libraries/library[@name='microbuilder']/packages/package[@name='1X12_ROUND_76MIL']")
|
||||
for pad in pkg.findall('pad'):
|
||||
x, y = float(jp.get('x')) + float(pad.get('x')), float(jp.get('y')) + float(pad.get('y'))
|
||||
assert any(abs(f.get('radius', 0)-0.5)<1e-8 and abs(f['location'][0]-x)<1e-8 and abs(f['location'][1]-y)<1e-8 for f in D[0]['faces'])
|
||||
for x in [3.81, 27.94]:
|
||||
assert any(abs(f.get('radius',0)-1.5)<1e-8 and abs(f['location'][0]-x)<1e-8 and abs(f['location'][1]-11.43)<1e-8 for f in D[0]['faces'])
|
||||
assert all(abs(a-b)<1e-8 for a,b in zip(D[0]['bounds'], [0,0,0,31.75,29.337,1.57]))
|
||||
|
||||
subsets = {
|
||||
'front_flange_exposed_faces': [8,11,12,13,14],
|
||||
'shell_straight_outer_surface': list(range(18,26)),
|
||||
'shell_outer_including_root_and_lip': list(range(18,26))+list(range(81,89))+list(range(103,111)),
|
||||
'left_front_hex_post': list(range(53,62))+[89],
|
||||
'right_front_hex_post': list(range(62,71))+[90],
|
||||
}
|
||||
result = {}
|
||||
for name, ids in subsets.items():
|
||||
faces = [D[11]['faces'][i-1] for i in ids]
|
||||
assert all(any('Opaque(245,245,246)' in c for c in f['colors']) for f in faces)
|
||||
bounds = [min(f['bounds'][i] for f in faces) for i in range(3)] + [max(f['bounds'][i] for f in faces) for i in range(3,6)]
|
||||
result[name] = dict(solid=12, faces=ids, bounds=bounds, dimensions=[bounds[i+3]-bounds[i] for i in range(3)])
|
||||
left, right = [D[11]['faces'][i-1] for i in [60,69]]
|
||||
assert abs(right['location'][0]-left['location'][0]-25)<1e-8
|
||||
assert left['radius'] == right['radius'] == 1.5
|
||||
result['front_lock_axes'] = [left, right]
|
||||
(HERE / 'measurements.json').write_text(json.dumps(result,indent=2)+'\n')
|
||||
print('PASS: source hashes, 15 valid solids, all 12 Eagle header centres, PCB bounds, mounting holes, metal-appearance subsets and front lock cylinders.')
|
||||
for name, row in result.items():
|
||||
if isinstance(row,dict):
|
||||
print(name, [round(v,6) for v in row['bounds']], 'size', [round(v,6) for v in row['dimensions']])
|
||||
Reference in New Issue
Block a user