Closed skanga closed 1 year ago
Use the DXF import functionality and extrude?
@skanga There's an example in a pending PR here: https://github.com/CadQuery/cadquery/pull/668/files#diff-cb972e06b41c528b92f42d1f94c6c205ff15c6e35613bfb32333d9c13f3496acR56
@adam-urbanczyk This works great. You're a rock star - wow! @jmwright Thanks for the reference. That was a great tip.
I found this repo of t-slot profiles - https://github.com/dcowden/dxf/tree/master/8020_shapes
Here is some sample working code using files from that repo
import cadquery as cq
def extrudeObject(dxfFile, extrudeLength):
result = (
cq.importers.importDXF(dxfFile)
.wires()
.toPending()
.extrude(extrudeLength)
)
return result
#result = extrudeObject('dxf/8020_shapes/8020-10Series/2040.dxf', 20)
#result = extrudeObject('dxf/8020_shapes/8020-20Series/20-4040.dxf', 100)
#result = extrudeObject('dxf/8020_shapes/8020-20Series/20-4040.dxf', 100)
result = extrudeObject('dxf/8020_shapes/8020-40Series/40-4040.dxf', 100)
#result = extrudeObject('dxf/8020_shapes/8020-40Series/40-8080.dxf', 100)
#result = extrudeObject('dxf/8020_shapes/8020-45Series/45-9090.dxf', 100)
#result = extrudeObject('dxf/8020_shapes/QF_Series/9035.dxf', 10)
#result = extrudeObject('dxf/8020_shapes/RT_Series/9725.dxf', 10)
#result = extrudeObject('dxf/8020_shapes/RT_Series/9820.dxf', 10)
show_object(result)
Now - 1 more question. Is it possible to cut the ends of the extrusion at say 60 or 45 degree angles?
Say - I want to make a square frame with one of these profiles, using 4 of these sticks with 45 degree corners? Any nice tricks to do that?
You can use this kind of apporach:
res = (
cq.Workplane()
.rect(1,1)
.extrude(5)
.faces('>Z').edges('>X')
.workplane(centerOption='CenterOfMass')
.transformed((0,-45,0)).split(False,True)
)
BTW: @skanga if you have something sharable you could open a PR for cadquery-contrib. I'm sure more CQ users will be interested in modeling examples with alu profiles.
OK - I'm happy to contribute. I'm thinking of this in terms of a DXF parts API which is backed up by dcowden's repo. If you want to use a part you can get it by using the Series and Part parameters. If the dxf isn't already available locally then we can fetch it from that repo.
The only complexity here is to create a consistent part naming scheme from the inconsistent conventions used in that repo. This seems to work for all the parts that I tried. It's a first attempt. Any thoughts?
import cadquery as cq
import os
import urllib.request
import urllib
# Store/cache downloaded files in this folder
localDir = "dxf/"
baseUrl = "https://raw.githubusercontent.com/dcowden/dxf/master/8020_shapes/"
#seriesUrl = "https://github.com/dcowden/dxf/tree/master/8020_shapes"
dxfPath = 'dxf/8020_shapes/{}Series/{}.dxf'
"""
Download dxf file from dcowden's github repo, while accounting for
the naming inconsistencies as shown below:
8020-10Series/1001.dxf
8020-15Series/1501.dxf
8020-20Series/20-2020.dxf
8020-25Series/25-2501.dxf
8020-30Series/30-3030.dxf
8020-40Series/40-4001.dxf
8020-45Series/45-4545.dxf
QF_Series/9000.dxf
RT_Series/9700.dxf
"""
def downloadDxfFile(dxfFile):
dxfSeries = dxfFile.split('-')[0]
if (dxfFile[0].isdigit()):
dxfFolder = "8020-" + dxfSeries + "Series/"
else:
dxfFolder = dxfSeries + "_Series/"
dxfFile = dxfFile + ".dxf"
# Reuse cached copy
if (os.path.exists(localDir + dxfFile)):
return
if (dxfSeries.startswith ("1")) or (not dxfSeries[0].isdigit()):
downloadUrl = baseUrl + dxfFolder + dxfFile.split('-', 1)[1]
else:
downloadUrl = baseUrl + dxfFolder + dxfFile
# Download the file and save it locally
urllib.request.urlretrieve(downloadUrl, localDir + dxfFile)
return localDir + dxfFile
def extrudeObject(dxfFile, extrudeLength):
downloadDxfFile(dxfFile)
dxfSeries = dxfFile.split('-')[0]
fullDxf = dxfPath.format (dxfSeries, dxfFile)
result = (
cq.importers.importDXF(fullDxf)
.wires()
.toPending()
.extrude(extrudeLength)
)
return result
#result = extrudeObject('10-2040', 20)
#result = extrudeObject('15-3030', 20)
#result = extrudeObject('15-1530-ULS', 20)
#result = extrudeObject('20-4040', 100)
#result = extrudeObject('20-4040', 100)
result = extrudeObject('40-4040', 100)
#result = extrudeObject('40-4084-LITE', 100)
#result = extrudeObject('40-8080', 100)
#result = extrudeObject('45-9090', 100)
#result = extrudeObject('QF-9035', 10)
#result = extrudeObject('RT-9725', 10)
#result = extrudeObject('RT-9820', 10)
show_object(result)
Imagine the power of expanding something like this into an online repository of pre-built parts for CQ that anyone can contribute to. Not just for dxf but for anything!
With one simple API call we can import from a potentially large set of parts - just by knowing its name.
Also, having a "parts browser" panel in CQ-editor would be pretty cool - IMHO. There you could navigate to and view a part before you decide to use it.
@skanga nice sleuthing to find those dxfs!
@skanga I get a FileNotFoundError
- probably need to create some directory structure. For your own sanity you might want to consider using requests
and path.py
instead of os
and urllib
.
Strange! I don't think you need to create any dir structure. Indeed, the whole reason for doing the download was to avoid that! Anyway - let me review using requests
andpath.py
instead of os
and urllib
. Being a python noob - I just tried whatever seemed to work on my machine (Windows 10 with Python 3.9)
I also created a "discovery" API to show what series are available and the parts in each series. Is the python Beautiful Soup
library also one to avoid? This code works standalone but in CQ-editor it fails to import BeautifulSoup
at all!
import urllib.request
import urllib
from bs4 import BeautifulSoup
baseUrl = "https://github.com/dcowden/dxf/tree/master/8020_shapes"
def fetchAllSeries():
with urllib.request.urlopen(baseUrl) as response:
html = response.read()
soup = BeautifulSoup(html, 'html.parser')
links = soup.find_all('a', class_="js-navigation-open Link--primary")
results = []
for link in links:
#print(link.text.replace("Series", "").replace("8020-", "").replace("_", ""))
results.append (link.text.replace("Series", "").replace("8020-", "").replace("_", ""))
return results
def fetchSeriesParts(seriesName):
with urllib.request.urlopen(baseUrl) as response:
html = response.read()
soup = BeautifulSoup(html, 'html.parser')
links = soup.find_all('a', class_="js-navigation-open Link--primary")
for link in links:
if (seriesName in link.text.replace("Series", "").replace("8020-", "").replace("_", "")):
break
#print (link.text)
with urllib.request.urlopen(baseUrl + "/" + link.text) as response:
html = response.read()
soup = BeautifulSoup(html, 'html.parser')
links = soup.find_all('a', class_="js-navigation-open Link--primary")
results = []
for link in links:
#print(link.text.replace(".dxf", "")
if (seriesName.startswith ("1")) or (not seriesName[0].isdigit()):
results.append (seriesName + "-" + link.text.replace(".dxf", ""))
else:
results.append (link.text.replace(".dxf", ""))
return results
def fetchAllParts():
allSeries = fetchAllSeries()
results = []
for currSeries in allSeries:
#print (currSeries, fetchSeriesParts(currSeries))
results.append (fetchSeriesParts(currSeries))
return results
print("All Parts:", fetchAllParts())
#print("All Series:", fetchAllSeries())
#print("20 Series:", fetchSeriesParts("20"))
#print("QF Series:", fetchSeriesParts("QF"))
BeautifulSoup isn't from the standard library to avoid having to download and import external library you can maybe look at html.parser module from the standard library (never used it but should do the same work)
Any suggestions on how to model this part in CadQuery?