FreeCAD-macros

Форк
0
/
DxfToSketchLayers.FCMacro 
294 строки · 12.5 Кб
1
# -*- coding: utf-8 -*-
2

3
__Name__ = 'DXF to Sketch Layers'
4
__Comment__ = 'DXF loader to a sketch for each layer or color'
5
__Author__ = 'Julian Todd'
6
__Version__ = '1.0.2'
7
__Date__ = '2019-04-30'
8
__License__ = 'LGPL-2.0-or-later'
9
__Web__ = 'https://github.com/goatchurchprime/transition-CAM/blob/master/dxfimporting/Macro_DXF_to_Sketch_layers.FCMacro'
10
__Wiki__ = ''
11
__Icon__ = ''
12
__Help__ = ''
13
__Status__ = 'stable'
14
__Requires__ = 'FreeCAD >= 0.17'
15
__Communication__ = ''
16
__Files__ = ''
17

18
# This should be a general function available to all macros
19
# (Taken from https://stackoverflow.com/questions/12332975/installing-python-module-within-code )
20
from PySide import QtGui
21
def import_and_install(packagename):
22
    try:
23
        _encoding = QtGui.QApplication.UnicodeUTF8
24
        def tr(context, text):
25
            return QtGui.QApplication.translate(context, text, None, _encoding)
26
    except AttributeError:
27
        def tr(context, text):
28
            return QtGui.QApplication.translate(context, text, None)
29

30
    import importlib
31
    try:
32
        importlib.import_module(packagename)
33
    except ImportError:
34
        cmdlist = ["pip", "install", packagename, "--user"]
35
        answer = QtGui.QMessageBox.question(None,
36
                    tr(__Name__, 'Install %s?' % packagename),
37
        	    tr(__Name__, 'Install %s by executing "%s"?' % (packagename, " ".join(cmdlist))))
38
        if answer == QtGui.QMessageBox.StandardButton.Yes:
39
            import subprocess
40
            proc = subprocess.Popen(cmdlist, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
41
            out, err = proc.communicate()
42
            print(out.decode())
43
            print(err.decode())
44
        else:
45
            raise
46
    globals()[packagename] = importlib.import_module(packagename)
47

48

49
#
50
# Imports and start of code
51
#
52
import_and_install("ezdxf")
53
from PySide import QtGui
54
import math
55
import Draft, Part
56
from FreeCAD import Vector
57
import FreeCAD
58
import FreeCADGui
59

60

61
#
62
# DXF unwrapping and colour converting. 
63
# TODO: Would like this in a separate file.)
64
dxfcolors = ['#000000', '#FF0000', '#FFFF00', '#00FF00',
65
             '#00FFFF', '#0000FF', '#FF00FF', '#000000',
66
             '#808080', '#C0C0C0', '#FF0000', '#FF7F7F',
67
             '#CC0000', '#CC6666', '#990000', '#994C4C',
68
             '#7F0000', '#7F3F3F', '#4C0000', '#4C2626',
69
             '#FF3F00', '#FF9F7F', '#CC3300', '#CC7F66',
70
             '#992600', '#995F4C', '#7F1F00', '#7F4F3F',
71
             '#4C1300', '#4C2F26', '#FF7F00', '#FFBF7F',
72
             '#CC6600', '#CC9966', '#994C00', '#99724C',
73
             '#7F3F00', '#7F5F3F', '#4C2600', '#4C3926',
74
             '#FFBF00', '#FFDF7F', '#CC9900', '#CCB266',
75
             '#997200', '#99854C', '#7F5F00', '#7F6F3F',
76
             '#4C3900', '#4C4226', '#FFFF00', '#FFFF7F',
77
             '#CCCC00', '#CCCC66', '#999900', '#99994C',
78
             '#7F7F00', '#7F7F3F', '#4C4C00', '#4C4C26',
79
             '#BFFF00', '#DFFF7F', '#99CC00', '#B2CC66',
80
             '#729900', '#85994C', '#5F7F00', '#6F7F3F',
81
             '#394C00', '#424C26', '#7FFF00', '#BFFF7F',
82
             '#66CC00', '#99CC66', '#4C9900', '#72994C',
83
             '#3F7F00', '#5F7F3F', '#264C00', '#394C26',
84
             '#3FFF00', '#9FFF7F', '#33CC00', '#7FCC66',
85
             '#269900', '#5F994C', '#1F7F00', '#4F7F3F',
86
             '#134C00', '#2F4C26', '#00FF00', '#7FFF7F',
87
             '#00CC00', '#66CC66', '#009900', '#4C994C',
88
             '#007F00', '#3F7F3F', '#004C00', '#264C26',
89
             '#00FF3F', '#7FFF9F', '#00CC33', '#66CC7F',
90
             '#009926', '#4C995F', '#007F1F', '#3F7F4F',
91
             '#004C13', '#264C2F', '#00FF7F', '#7FFFBF',
92
             '#00CC66', '#66CC99', '#00994C', '#4C9972',
93
             '#007F3F', '#3F7F5F', '#004C26', '#264C39',
94
             '#00FFBF', '#7FFFDF', '#00CC99', '#66CCB2',
95
             '#009972', '#4C9985', '#007F5F', '#3F7F6F',
96
             '#004C39', '#264C42', '#00FFFF', '#7FFFFF',
97
             '#00CCCC', '#66CCCC', '#009999', '#4C9999',
98
             '#007F7F', '#3F7F7F', '#004C4C', '#264C4C',
99
             '#00BFFF', '#7FDFFF', '#0099CC', '#66B2CC',
100
             '#007299', '#4C8599', '#005F7F', '#3F6F7F',
101
             '#00394C', '#26424C', '#007FFF', '#7FBFFF',
102
             '#0066CC', '#6699CC', '#004C99', '#4C7299',
103
             '#003F7F', '#3F5F7F', '#00264C', '#26394C',
104
             '#0042FF', '#7F9FFF', '#0033CC', '#667FCC',
105
             '#002699', '#4C5F99', '#001F7F', '#3F4F7F',
106
             '#00134C', '#262F4C', '#0000FF', '#7F7FFF',
107
             '#0000CC', '#6666CC', '#000099', '#4C4C99',
108
             '#00007F', '#3F3F7F', '#00004C', '#26264C',
109
             '#3F00FF', '#9F7FFF', '#3200CC', '#7F66CC',
110
             '#260099', '#5F4C99', '#1F007F', '#4F3F7F',
111
             '#13004C', '#2F264C', '#7F00FF', '#BF7FFF',
112
             '#6600CC', '#9966CC', '#4C0099', '#724C99',
113
             '#3F007F', '#5F3F7F', '#26004C', '#39264C',
114
             '#BF00FF', '#DF7FFF', '#9900CC', '#B266CC',
115
             '#720099', '#854C99', '#5F007F', '#6F3F7F',
116
             '#39004C', '#42264C', '#FF00FF', '#FF7FFF',
117
             '#CC00CC', '#CC66CC', '#990099', '#994C99',
118
             '#7F007F', '#7F3F7F', '#4C004C', '#4C264C',
119
             '#FF00BF', '#FF7FDF', '#CC0099', '#CC66B2',
120
             '#990072', '#994C85', '#7F005F', '#7F3F0B',
121
             '#4C0039', '#4C2642', '#FF007F', '#FF7FBF',
122
             '#CC0066', '#CC6699', '#99004C', '#994C72',
123
             '#7F003F', '#7F3F5F', '#4C0026', '#4C2639',
124
             '#FF003F', '#FF7F9F', '#CC0033', '#CC667F',
125
             '#990026', '#994C5F', '#7F001F', '#7F3F4F',
126
             '#4C0013', '#4C262F', '#333333', '#5B5B5B',
127
             '#848484', '#ADADAD', '#D6D6D6', '#FFFFFF']
128

129

130
def getlayercol(e, dfile, blockcolnum):
131
    if e.dxf.color == 256:
132
        layer = dfile.layers.get(e.dxf.layer)
133
        colnum = layer.get_dxf_attrib("color", 0)
134
    elif e.dxf.color == 0:
135
        colnum = blockcolnum
136
    else:
137
        colnum = e.dxf.color
138
    return (e.dxf.layer, dxfcolors[colnum])
139

140
def makeentitygroupsrecurse(entitygroupdict, dfile, entities, blockcolnum):
141
    for e in entities:
142
        if e.dxftype() == 'INSERT':
143
            print("INSERT translate", e.dxf.insert, "rotate", e.dxf.rotation, "scale", e.dxf.xscale, e.dxf.yscale)
144
            lblockcolnum = dfile.layers.get(e.dxf.layer).get_color()
145
            makeentitygroupsrecurse(entitygroupdict, dfile, list(dfile.blocks[e.dxf.name]), lblockcolnum)
146
        elif e.dxftype() == 'MTEXT':
147
            pass
148
        elif e.dxftype() == 'TEXT':
149
            pass
150
        else:
151
            layercol = getlayercol(e, dfile, blockcolnum)
152
            entitygroupdict.setdefault(layercol, []).append(e)
153
    return entitygroupdict
154

155
def makeentitygroups(dfile):
156
    entitygroupdict = { }
157
    makeentitygroupsrecurse(entitygroupdict, dfile, dfile.entities, 1)
158
    entitygroups = list(entitygroupdict.items())
159
    layernameorder = dict((n, i)  for i, n in enumerate(l.dxf.name  for l in dfile.layers))
160
    entitygroups.sort(key=lambda X:layernameorder[X[0][0]])
161
    return entitygroups
162

163

164
# See also arbitrary axis algorithm in http://paulbourke.net/dataformats/dxf/dxf10.html
165
# Seems to flip rotation around Y-axis, so only invert the X
166
def arcextrusionfac(e):
167
    if max(abs(e.dxf.extrusion[0]), abs(e.dxf.extrusion[1]), abs(abs(e.dxf.extrusion[2]) - 1)) > 1e-5:
168
        print("Unknown arc extrusion", e.dxf.extrusion)
169
    return 1 if e.dxf.extrusion[2] >= 0 else -1
170

171

172
#
173
# Function to create sketches and inject dxf geometry directly into it 
174
#
175

176
def MakeSketches(addObjectFunc, entitygroups):
177
    cnorm = Vector(0, 0, 1)
178
    sketches = [ ]
179
    for (layer, col), entities in entitygroups:
180
        slayer = str(layer)
181
        if len(slayer) <= 1:
182
            slayer = "layer_"+slayer  # Sketcher name is '_' if it's a 1 character number
183
        sketch = addObjectFunc("Sketcher::SketchObject", slayer)
184
        if sketch.ViewObject is not None:
185
            sketch.ViewObject.Visibility = True
186
            sketch.ViewObject.LineColor = (int(col[1:3],16)/255.0, int(col[3:5],16)/255.0, int(col[5:7],16)/255.0)
187
        print("Making sketch", layer, col)
188
        sketches.append(sketch)
189
        for e in entities:
190
            try:
191
                if e.dxftype() == "LINE":
192
                    if e.dxf.start != e.dxf.end:
193
                        p0 = Vector(e.dxf.start[0], e.dxf.start[1])
194
                        p1 = Vector(e.dxf.end[0], e.dxf.end[1])
195
                        sketch.addGeometry(Part.LineSegment(p0, p1))
196
                
197
                elif e.dxftype() == "CIRCLE":
198
                    exfac = arcextrusionfac(e)
199
                    cen = Vector(e.dxf.center[0]*exfac, e.dxf.center[1])
200
                    sketch.addGeometry(Part.Circle(cen, cnorm, e.dxf.radius))
201
                    
202
                elif e.dxftype() == "ARC":
203
                    exfac = arcextrusionfac(e)
204
                    cen = Vector(e.dxf.center[0]*exfac, e.dxf.center[1])
205
                    circ = Part.Circle(cen, cnorm, e.dxf.radius)
206
                    a0, a1 = e.dxf.start_angle, e.dxf.end_angle
207
                    if exfac == -1:
208
                        a0, a1 = 180-a1, 180-a0
209
                    sketch.addGeometry(Part.ArcOfCircle(circ, math.radians(a0), math.radians(a1)))
210

211
                elif e.dxftype() == "SPLINE":
212
                    cps = [Vector(x[0], x[1])  for x in list(e.control_points)]
213
                    bspl = Part.BSplineCurve(cps,None,None,False,e.dxf.degree,None,e.closed)
214
                    sketch.addGeometry(bspl)
215
                    
216
                elif e.dxftype() == "LWPOLYLINE":
217
                    def lwpgeo(p0, p1, bulge):
218
                        if bulge != 0:
219
                            lv = p1 - p0
220
                            b = abs(bulge)
221
                            d = lv.Length/2
222
                            bd = b*d
223
                            r = (bd + d/b)/2
224
                            sb = (1 if bulge >= 0 else -1)
225
                            pf = (r - bd)/(d*2)
226
                            cnorm = Vector(0, 0, 1)
227
                            lvperp = lv.cross(cnorm)*sb
228
                            cen = p0 + lv*0.5 - lvperp*pf
229
                            circ = Part.Circle(cen, cnorm, r)
230
                            mang = math.atan2(lvperp.y, lvperp.x)
231
                            th2 = math.asin(d/r)
232
                            return(Part.ArcOfCircle(circ, mang-th2, mang+th2))
233
                        else:
234
                            return Part.LineSegment(p0, p1)
235
                            
236
                    p0 = Vector(e[0][0], e[0][1])
237
                    for i in range(1, len(e)):
238
                        p1 = Vector(e[i][0], e[i][1])
239
                        sketch.addGeometry(lwpgeo(p0, p1, e[i-1][4]))
240
                        p0 = p1
241
                    if e.closed:
242
                        sketch.addGeometry(lwpgeo(p0, Vector(e[0][0], e[0][1]), e[-1][4]))
243
                
244
                elif e.dxftype() == "POLYLINE": 
245
                    p0s = Vector(e[0].dxf.location[0], e[0].dxf.location[1])
246
                    p0 = p0s
247
                    for i in range(1, len(e)):
248
                        p1 = Vector(e[i].dxf.location[0], e[i].dxf.location[1])
249
                        if p0 != p1:
250
                            sketch.addGeometry(Part.LineSegment(p0, p1))
251
                        p0 = p1
252
                    if e.is_closed and p0s != p0:
253
                        sketch.addGeometry(Part.LineSegment(p0, p0s))
254
                        
255
                else:
256
                    print("unknown", e.dxftype())
257
                    
258
            except Part.OCCError as err:
259
                print(e, err)
260
    return sketches
261

262

263

264
#
265
# Main entry which finds or creates the document and body
266
#
267
def main():
268
    """Main entry which finds or creates the document and body"""
269
    fname, fnamefilter = QtGui.QFileDialog.getOpenFileName(parent=FreeCADGui.getMainWindow(), caption='Read a DXF file', filter='*.dxf')
270
    if fname:
271
        FreeCAD.Console.PrintMessage('Parsing file {}'.format(fname))
272
        dfile = ezdxf.readfile(fname)
273

274
        unitfacmap = {4:1.0} # 4->mm
275
        unitfac = unitfacmap[dfile.header['$INSUNITS']]  
276
        fac = dfile.header['$DIMALTF']
277
        print("Factor multiply requested (not implemented)", fac, unitfac)
278

279
        entitygroups = makeentitygroups(dfile)
280
        doc = FreeCAD.activeDocument()
281
        if doc is None:
282
            doc = FreeCAD.newDocument()
283
        # Get the active body, if any.
284
        obj = FreeCADGui.activeDocument().ActiveView.getActiveObject('pdbody')
285
        try:
286
            addObjectFunc = obj.newObject
287
        except AttributeError:
288
            addObjectFunc = doc.addObject
289

290
        sketches = MakeSketches(addObjectFunc, entitygroups)
291
        doc.recompute()
292

293
if __name__ == '__main__':
294
    main()
295

296

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.