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