Merge branch 'master' of https://github.com/FreeCAD/FreeCAD
This commit is contained in:
commit
9fb882b103
|
@ -2318,17 +2318,17 @@ def circleFrom2PointsRadius(p1, p2, radius):
|
|||
dist_p1p2 = DraftVecUtils.dist(p1, p1)
|
||||
mid = findMidpoint(p1_p2)
|
||||
if dist_p1p2 == 2*radius:
|
||||
circle = Part.Circle(mid, norm, radius)
|
||||
circle = Part.Circle(mid, NORM, radius)
|
||||
if circle: return [circle]
|
||||
else: return None
|
||||
dir = vec(p1_p2); dir.normalize()
|
||||
perpDir = dir.cross(Vector(0,0,1)); perpDir.normailze()
|
||||
perpDir = dir.cross(Vector(0,0,1)); perpDir.normalize()
|
||||
dist = math.sqrt(radius**2 - (dist_p1p2 / 2.0)**2)
|
||||
cen1 = Vector.add(mid, Vector(perpDir).multiply(dist))
|
||||
cen2 = Vector.add(mid, Vector(perpDir).multiply(-dist))
|
||||
circles = []
|
||||
if cen1: circles.append(Part.Circle(cen1, norm, radius))
|
||||
if cen2: circles.append(Part.Circle(cen2, norm, radius))
|
||||
if cen1: circles.append(Part.Circle(cen1, NORM, radius))
|
||||
if cen2: circles.append(Part.Circle(cen2, NORM, radius))
|
||||
if circles: return circles
|
||||
else: return None
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ SET(PathScripts_SRCS
|
|||
PathScripts/centroid_post.py
|
||||
PathScripts/comparams_post.py
|
||||
PathScripts/dumper_post.py
|
||||
PathScripts/rml_post.py
|
||||
PathScripts/TooltableEditor.py
|
||||
PathScripts/PathProfile.py
|
||||
PathScripts/PathPocket.py
|
||||
|
|
|
@ -22,10 +22,14 @@
|
|||
#* *
|
||||
#***************************************************************************
|
||||
|
||||
import FreeCAD,FreeCADGui,Path,PathGui
|
||||
import FreeCAD,Path
|
||||
from PySide import QtCore,QtGui
|
||||
from PathScripts import PathUtils,PathSelection,PathProject
|
||||
|
||||
FreeCADGui = None
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
|
||||
"""Path Drilling object and FreeCAD command"""
|
||||
|
||||
# Qt tanslation handling
|
||||
|
|
|
@ -23,11 +23,11 @@
|
|||
#***************************************************************************
|
||||
''' A CNC machine object to define how code is posted '''
|
||||
|
||||
import FreeCAD,FreeCADGui,Path,PathGui
|
||||
import FreeCAD,Path
|
||||
import PathScripts
|
||||
from PathScripts import PathProject, PathUtils
|
||||
from PySide import QtCore,QtGui
|
||||
import os, sys
|
||||
import os, sys
|
||||
|
||||
# Qt tanslation handling
|
||||
try:
|
||||
|
@ -228,6 +228,7 @@ class CommandPathMachine:
|
|||
|
||||
if FreeCAD.GuiUp:
|
||||
# register the FreeCAD command
|
||||
import FreeCADGui
|
||||
FreeCADGui.addCommand('Path_Machine',CommandPathMachine())
|
||||
|
||||
|
||||
|
|
|
@ -22,10 +22,14 @@
|
|||
#* *
|
||||
#***************************************************************************
|
||||
|
||||
import FreeCAD,FreeCADGui,Path,PathGui
|
||||
import FreeCAD,Path
|
||||
from PySide import QtCore,QtGui
|
||||
from PathScripts import PathUtils
|
||||
|
||||
FreeCADGui = None
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
|
||||
"""Path Pocket object and FreeCAD command"""
|
||||
|
||||
# Qt tanslation handling
|
||||
|
|
|
@ -22,9 +22,13 @@
|
|||
#* *
|
||||
#***************************************************************************
|
||||
|
||||
import FreeCAD,FreeCADGui,Path,PathGui
|
||||
import FreeCAD,Path
|
||||
from PySide import QtCore,QtGui
|
||||
|
||||
FreeCADGui = None
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
|
||||
"""Path Project object and FreeCAD command"""
|
||||
|
||||
# Qt tanslation handling
|
||||
|
|
|
@ -27,9 +27,12 @@ These are a common functions and classes for creating custom post processors.
|
|||
'''
|
||||
|
||||
from PySide import QtCore, QtGui
|
||||
import FreeCADGui
|
||||
import FreeCAD
|
||||
|
||||
FreeCADGui = None
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
|
||||
class OldHighlighter(QtGui.QSyntaxHighlighter):
|
||||
def highlightBlock(self, text):
|
||||
myClassFormat = QtGui.QTextCharFormat()
|
||||
|
@ -76,7 +79,9 @@ class GCodeHighlighter(QtGui.QSyntaxHighlighter):
|
|||
|
||||
|
||||
class GCodeEditorDialog(QtGui.QDialog):
|
||||
def __init__(self, parent = FreeCADGui.getMainWindow()):
|
||||
def __init__(self, parent = None):
|
||||
if parent is None:
|
||||
parent = FreeCADGui.getMainWindow()
|
||||
QtGui.QDialog.__init__(self,parent)
|
||||
|
||||
layout = QtGui.QVBoxLayout(self)
|
||||
|
|
257
src/Mod/Path/PathScripts/rml_post.py
Normal file
257
src/Mod/Path/PathScripts/rml_post.py
Normal file
|
@ -0,0 +1,257 @@
|
|||
#***************************************************************************
|
||||
#* (c) Jon Nordby (jononor@gmail.com) 2015 *
|
||||
#* *
|
||||
#* This file is part of the FreeCAD CAx development system. *
|
||||
#* *
|
||||
#* This program is free software; you can redistribute it and/or modify *
|
||||
#* it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
#* as published by the Free Software Foundation; either version 2 of *
|
||||
#* the License, or (at your option) any later version. *
|
||||
#* for detail see the LICENCE text file. *
|
||||
#* *
|
||||
#* FreeCAD is distributed in the hope that it will be useful, *
|
||||
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
#* GNU Lesser General Public License for more details. *
|
||||
#* *
|
||||
#* You should have received a copy of the GNU Library General Public *
|
||||
#* License along with FreeCAD; if not, write to the Free Software *
|
||||
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
#* USA *
|
||||
#* *
|
||||
#***************************************************************************/
|
||||
|
||||
|
||||
'''
|
||||
FreeCAD Path post-processor to output code for the Roland Modela MDX-## machines.
|
||||
|
||||
The machine speaks RML-1, specified in 'Roland RML-1 Programming Guidelines'
|
||||
https://itp.nyu.edu/classes/cdp-spring2014/files/2014/09/RML1_Manual.pdf
|
||||
http://altlab.org/d/content/m/pangelo/ideas/rml_command_guide_en_v100.pdf
|
||||
|
||||
The format has some overlap with HPGL:
|
||||
https://en.wikipedia.org/wiki/HPGL
|
||||
http://paulbourke.net/dataformats/hpgl/
|
||||
'''
|
||||
|
||||
import FreeCAD
|
||||
import Part
|
||||
import PostUtils
|
||||
|
||||
# to distinguish python built-in open function from the one declared below
|
||||
if open.__module__ == '__builtin__':
|
||||
pythonopen = open
|
||||
|
||||
|
||||
# Entrypoint used by FreeCAD
|
||||
def export(objectslist, filename):
|
||||
"Export objects as Roland Modela code."
|
||||
|
||||
code = ""
|
||||
for obj in objectslist:
|
||||
code += convertobject(obj)
|
||||
|
||||
gfile = pythonopen(filename,"wb")
|
||||
gfile.write(code)
|
||||
gfile.close()
|
||||
|
||||
def convertobject(obj):
|
||||
gcode = obj.Path.toGCode()
|
||||
gcode = parse(gcode)
|
||||
return gcode
|
||||
|
||||
def motoron():
|
||||
return [ "!MC1;" ]
|
||||
def motoroff():
|
||||
return [ "!MC0;" ]
|
||||
def home():
|
||||
return [ "H;" ]
|
||||
|
||||
def setjog():
|
||||
# "!PZ%d,%d;",iz_down,iz_up); // set z down, jog
|
||||
return ""
|
||||
|
||||
def addheader():
|
||||
return [ "PA;PA;" ] # absolute positioning
|
||||
def addfooter():
|
||||
return []
|
||||
|
||||
def mm2cord(mm):
|
||||
mm = float(mm)
|
||||
return int(40.0*mm)
|
||||
|
||||
def feed(x=None, y=None, z=None, state={}):
|
||||
c = []
|
||||
|
||||
if x is not None:
|
||||
x = float(x)
|
||||
state['X'] = x
|
||||
if y is not None:
|
||||
y = float(y)
|
||||
state['Y'] = y
|
||||
if z is not None:
|
||||
z = float(z)
|
||||
state['Z'] = z
|
||||
|
||||
if x is not None and y is not None and z is not None:
|
||||
# 3d motion
|
||||
c.append("Z%d,%d,%d;" % (mm2cord(x), mm2cord(y), mm2cord(z)))
|
||||
elif x is not None and y is not None:
|
||||
# 2d in XY plane
|
||||
c.append("PD%d,%d;" % (mm2cord(x), mm2cord(y)))
|
||||
elif z is not None:
|
||||
pass # XXX: is this used?
|
||||
return c
|
||||
|
||||
def jog(x=None, y=None, z=None, state={}):
|
||||
c = []
|
||||
if x is not None and y is not None:
|
||||
x, y = float(x), float(y)
|
||||
c.append("PU%d,%d;" % (mm2cord(x), mm2cord(y)))
|
||||
state['X'] = x
|
||||
state['Y'] = y
|
||||
if z is not None:
|
||||
z = float(z)
|
||||
c.append("PU;")
|
||||
# TODO: use !ZZ command
|
||||
state['Z'] = z
|
||||
|
||||
return c
|
||||
|
||||
def xyarc(args, state):
|
||||
# no native support in RML/Modela, convert to linear line segments
|
||||
c = []
|
||||
|
||||
lastPoint = FreeCAD.Vector(state['X'], state['Y'])
|
||||
newPoint = FreeCAD.Vector(float(args['X']), float(args['Y']))
|
||||
centerOffset = FreeCAD.Vector(float(args['I']), float(args['J']))
|
||||
center = lastPoint + centerOffset
|
||||
radius = (center - lastPoint).Length
|
||||
xyNormal = FreeCAD.Vector(0, 0, 1)
|
||||
circle = Part.Circle(center, xyNormal, radius)
|
||||
p0 = circle.parameter(lastPoint)
|
||||
p1 = circle.parameter(newPoint)
|
||||
arc = Part.ArcOfCircle(circle, p0, p1)
|
||||
steps = 64 # TODO: specify max error instead
|
||||
points = arc.discretize(steps)
|
||||
# TODO: consider direction
|
||||
#print 'p = Part.ArcOfCircle(Part.Circle(FreeCAD.Vector(%f, %f), FreeCAD.Vector(0, 0, 1), %f), %f, %f)' % (center.x, center.y, radius, p0, p1)
|
||||
for p in points:
|
||||
#print 'p', p.x, p.y
|
||||
c += feed(p.x, p.y, state['Z'], state)
|
||||
return c
|
||||
|
||||
def speed(xy=None, z=None, state={}):
|
||||
c = []
|
||||
print xy, z, state
|
||||
if xy is not None:
|
||||
xy = float(xy)
|
||||
if xy > 0.0 and xy != state['XYspeed']:
|
||||
c.append("VS%.1f;" % xy)
|
||||
state['XYspeed'] = xy
|
||||
if z is not None:
|
||||
z = float(z)
|
||||
if z > 0.0 and z != state['Zspeed']:
|
||||
c.append("!VZ%.1f;" % z)
|
||||
state['Zspeed'] = z
|
||||
return c
|
||||
|
||||
def convertgcode(cmd, args, state):
|
||||
"""Convert a single gcode command to equivalent Roland code"""
|
||||
if cmd == 'G0':
|
||||
# jog
|
||||
return jog(args['X'], args['Y'], args['Z'], state)
|
||||
elif cmd == 'G1':
|
||||
# linear feed
|
||||
c = []
|
||||
# feedrate
|
||||
c += speed(xy=args['F'], z=args['F'], state=state)
|
||||
# motion
|
||||
c += feed(args['X'], args['Y'], args['Z'], state)
|
||||
return c
|
||||
elif cmd == 'G2' or cmd == 'G3':
|
||||
# arc feed
|
||||
c = []
|
||||
# feedrate
|
||||
c += speed(xy=args['F'], state=state)
|
||||
# motion
|
||||
if args['X'] and args['Y'] and args['Z']:
|
||||
# helical motion
|
||||
pass
|
||||
elif args['X'] and args['Y']:
|
||||
# arc in plane
|
||||
c += xyarc(args, state)
|
||||
return c
|
||||
elif cmd == 'G20':
|
||||
# inches mode
|
||||
raise ValueError("rml_post: Inches mode not supported")
|
||||
elif cmd == 'G21':
|
||||
# millimeter mode
|
||||
return ""
|
||||
elif cmd == 'G40':
|
||||
# tool compensation off
|
||||
return ""
|
||||
elif cmd == 'G80':
|
||||
# cancel all cycles (drill normally)
|
||||
return "PU;"
|
||||
elif cmd == 'G81':
|
||||
c = []
|
||||
# feedrate
|
||||
c += speed(z=args['F'], state=state)
|
||||
# motion
|
||||
c += jog(args['X'], args['Y'], state=state)
|
||||
c += feed(args['X'], args['Y'], args['Z'], state)
|
||||
return c
|
||||
elif cmd == 'G90':
|
||||
# absolute mode?
|
||||
return ""
|
||||
elif cmd == 'G98':
|
||||
# feedrate
|
||||
return ""
|
||||
else:
|
||||
raise NotImplementedError("rml_post: GCode command %s not understood" % (cmd,))
|
||||
|
||||
raise Exception("should not be reached. cmd=%s" % (cmd,))
|
||||
|
||||
|
||||
def parse(inputstring):
|
||||
"parse(inputstring): returns a parsed output string"
|
||||
|
||||
state = { 'X': 0.0, 'Y': 0.0, 'Z': 0.0, 'XYspeed': -1.0, 'Zspeed': -1.0 }
|
||||
output = []
|
||||
|
||||
# header
|
||||
output += addheader()
|
||||
output += motoron()
|
||||
|
||||
output += speed(2.0, 1.0, state) # defaults
|
||||
|
||||
# TODO: respect clearance height
|
||||
|
||||
# treat the input line by line
|
||||
lines = inputstring.split("\n")
|
||||
for line in lines:
|
||||
if not line:
|
||||
continue
|
||||
parsed = PostUtils.stringsplit(line)
|
||||
command = parsed['command']
|
||||
print 'cmd', line
|
||||
try:
|
||||
if command:
|
||||
code = convertgcode(command, parsed, state)
|
||||
if not isinstance(code, list):
|
||||
code = [ code ]
|
||||
if len(code) and code[0]:
|
||||
output += code
|
||||
except NotImplementedError, e:
|
||||
print e
|
||||
|
||||
# footer
|
||||
output += motoroff()
|
||||
output += home()
|
||||
output += addfooter()
|
||||
|
||||
return '\n'.join(output)
|
||||
|
||||
print __name__ + " gcode postprocessor loaded."
|
||||
|
Loading…
Reference in New Issue
Block a user