Use plot module for graphs

This commit is contained in:
jrheinlaender 2012-11-15 19:20:15 +04:30 committed by wmayer
parent 1eb738fc3f
commit a375f6b4a9
3 changed files with 40 additions and 186 deletions

View File

@ -137,12 +137,16 @@ class SegmentFunction:
xvals = set([self.segments[0].start + s * offset for s in range(pointsX)])
starts = set([self.segments[i].start for i in range(len(self.segments))])
xvals = xvals.union(starts) # Make sure we have a point on each segment start
result = []
xresult = []
yresult = []
for xval in sorted(xvals):
if xval in starts:
result.append( (xval, self.lowervalue(xval)) ) # create double point at segment border
result.append( (xval, self.value(xval)) )
return result
# create double point at segment border
xresult.append(xval)
yresult.append(self.lowervalue(xval))
xresult.append(xval)
yresult.append(self.value(xval))
return (xresult, yresult)
def output(self):
FreeCAD.Console.PrintMessage(self.name + " = ")

View File

@ -20,30 +20,11 @@
# * *
# ******************************************************************************/
import os, tempfile
import FreeCAD, FreeCADGui # FreeCAD just required for debug printing to the console...
import WebGui
from SegmentFunction import SegmentFunction
from ShaftFeature import ShaftFeature
from ShaftDiagram import Diagram
htmlHeader = """
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=utf-8">
<TITLE></TITLE>
<META NAME="GENERATOR" CONTENT="FreeCAD shaft design wizard">
</HEAD>
<BODY LANG="en-US" DIR="A4">
<P>
"""
htmlFooter = """
</P>
</BODY>
</HTML>
"""
class ShaftSegment:
length = 0.0
diameter = 0.0
@ -64,11 +45,6 @@ class Shaft:
#featureWindow = None
# The diagrams
diagrams = {} # map of function name against Diagram object
# Directory for diagram files
tmpdir = ""
# HTML browser
haveBrowser = False
#htmlWindow = None
# Calculation of shaft
Qy = 0 # force in direction of y axis
Qz = 0 # force in direction of z axis
@ -77,8 +53,6 @@ class Shaft:
Mtz = 0 # torsion moment around z axis
def __init__(self, doc):
# Create a temporary directory
self.tmpdir = tempfile.mkdtemp()
self.sketch = ShaftFeature(doc)
def getLengthTo(self, index):
@ -129,30 +103,16 @@ class Shaft:
self.diagrams[self.Qy.name].update(self.Qy, self.getLengthTo(len(self.segments)) / 1000.0)
else:
# Create diagram
self.diagrams[self.Qy.name] = Diagram(self.tmpdir)
self.diagrams[self.Qy.name] = Diagram()
self.diagrams[self.Qy.name].create("Shear force", self.Qy, self.getLengthTo(len(self.segments)) / 1000.0, "x", "mm", 1000.0, "Q_y", "N", 1.0, 10)
if self.Mbz.name in self.diagrams:
# Update diagram
self.diagrams[self.Mbz.name].update(self.Mbz, self.getLengthTo(len(self.segments)) / 1000.0)
else:
# Create diagram
self.diagrams[self.Mbz.name] = Diagram(self.tmpdir)
self.diagrams[self.Mbz.name] = Diagram()
self.diagrams[self.Mbz.name].create("Bending moment", self.Mbz, self.getLengthTo(len(self.segments)) / 1000.0, "x", "mm", 1000.0, "M_{b,z}", "Nm", 1.0, 10)
if self.haveBrowser is False:
# Create HTML file with the diagrams
htmlFile = os.path.join(self.tmpdir, "diagrams.html")
file = open(htmlFile, "w")
file.write(htmlHeader)
for fname in self.diagrams.iterkeys():
plotFile = os.path.join(self.tmpdir, (fname + ".png"))
file.write("<IMG SRC=\"%s\" NAME=\"%s\" ALIGN=MIDDLE WIDTH=450 HEIGHT=320 BORDER=0>\n" % (plotFile, fname))
file.write(htmlFooter)
file.close()
WebGui.openBrowser(htmlFile)
self.haveBrowser = True
# Once the diagram is created, it will take care of refreshing the HTML view
def equilibrium(self):
# Build equilibrium equations
forces = {0.0:0.0} # dictionary of (location : outer force)
@ -247,12 +207,3 @@ class Shaft:
if (i < len(var) - 1) and (i != 0):
FreeCAD.Console.PrintMessage(" + ")
FreeCAD.Console.PrintMessage("\n")
def __del__(self):
"Remove the temporary directory"
for fname in self.diagrams.iterkeys():
os.remove(os.path.join(self.tmpdir, (fname + ".dat")))
os.remove(os.path.join(self.tmpdir, (fname + ".pyxplot")))
os.remove(os.path.join(self.tmpdir, (fname + ".png")))
os.remove(os.path.join(self.tmpdir, "diagrams.html"))
os.rmdir(self.tmpdir)

View File

@ -20,12 +20,9 @@
# * *
# ******************************************************************************/
import os, subprocess
from PyQt4 import QtCore, QtGui
import FreeCAD, FreeCADGui
header = " ### FREECAD SHAFT WIZARD ###\n #\n"
class Diagram:
function = 0 # This is assumed to be always a SegmentFunction
fname = "y(x)"
@ -37,26 +34,14 @@ class Diagram:
yunit = ""
yscale = 1.0
numxpoints = 10
points = []
# process object of pyxplot running in the background
pyxplot = None
# Filesystem watcher
graphicsFile = ""
timer = 0
watcher = 0
updatePending = False
def __init__(self, tmpdir):
self.tmpdir = tmpdir
# Set up watcher and timer
self.watcher = QtCore.QFileSystemWatcher()
self.watcher.fileChanged.connect(self.updateFinished)
self.timer = QtCore.QTimer()
self.timer.setInterval(100)
self.timer.timeout.connect(self.pollFile)
xpoints = []
ypoints = []
# Plot object
thePlot = None
def create(self, title, function, xlength, xname, xunit, xscale, yname, yunit, yscale, numxpoints):
# Initialize
import Plot
self.title = title
self.function = function
self.xlength = xlength
@ -67,12 +52,20 @@ class Diagram:
self.yunit = yunit
self.yscale = yscale
self.numxpoints = numxpoints
self.graphicsFile = os.path.join(self.tmpdir, self.function.name + '.png')
# Create a plot window
win = Plot.figure(title)
# Get the plot object from the window
self.thePlot = Plot.getPlot()
# Format the plot object
Plot.xlabel("$%s$ [%s]" % (xname, xunit))
Plot.ylabel("$%s$ [%s]" % (yname, yunit))
Plot.grid(True)
# Calculate points
self.points = self.function.evaluate(self.xlength, self.numxpoints)
# Write files
self.write()
(self.xpoints, self.ypoints) = self.function.evaluate(self.xlength, self.numxpoints)
# Create plot
self.plot()
def update(self, function = None, xlength = None):
if function is not None:
@ -80,113 +73,19 @@ class Diagram:
if xlength is not None:
self.xlength = xlength
# Calculate points
self.points = self.function.evaluate(self.xlength, self.numxpoints)
# Write files
self.write()
def write(self):
"Write diagram files"
# Check if pyxplot is still running in the background
if (self.pyxplot is not None) and (self.pyxplot.poll() is None):
# Process hasn't terminated yet, set flag to update again
# as soon as the graphicsFile has been written by the current pyxplot process
self.updatePending = True
return
# Get max and min values
(xmin, xmax) = self.minmaxX()
(ymin, ymax) = self.minmaxY()
# Create data file
dataFile = os.path.join(self.tmpdir, (self.function.name + ".dat"))
file = open(dataFile, "w")
file.write(header)
file.write(" # File automatically exported by FreeCAD Shaft Wizard\n")
file.write(" # This file contains xy data, filled with following columns:\n")
file.write(" # 1: %s [%s]\n" % (self.xname, self.xunit))
file.write(" # 2: %s [%s]\n" % (self.yname, self.yunit))
file.write(" #\n")
for (x, y) in self.points:
file.write("%f %f\n" % (x * self.xscale, y * self.yscale))
file.close()
# Create pyxplot file
commandFile = os.path.join(self.tmpdir, (self.function.name + ".pyxplot"))
file = open(commandFile, "w")
file.write(header)
file.write(" # File automatically exported by FreeCAD Shaft Wizard\n")
file.write(" # This file contains a script to plot xy data.\n")
file.write(" # To use it execute:\n")
file.write(" #\n")
file.write(" # pyxplot %s\n" % (commandFile))
file.write(" #\n")
file.write(" #################################################################\n")
# Write general options
file.write("set numeric display latex\n")
file.write("set terminal png\n")
file.write("set output '%s'\n" % (self.graphicsFile))
file.write("set nokey\n")
file.write("set grid\n")
file.write("# X axis\n")
file.write("set xlabel '$%s$ [%s]'\n" % (self.xname, self.xunit))
file.write("set xrange [%f:%f]\n" % ((xmin * self.xscale * 1.05, xmax * self.xscale * 1.05)))
file.write("set xtic\n")
file.write("# Y axis\n")
file.write("set ylabel '$%s$ [%s]'\n" % (self.yname, self.yunit))
file.write("set yrange [%f:%f]\n" % ((ymin * self.yscale * 1.05, ymax * self.yscale * 1.05)))
file.write("set ytic\n")
file.write("# Line styles\n")
file.write("set style 1 line linetype 1 linewidth 2 colour rgb (0):(0):(0)\n")
file.write("# Title\n")
file.write("set title '%s'" % self.title)
# Write plot call
file.write("# Plot\n")
file.write("plot '%s' using 1:2 axes x1y1 with lines style 1\n" % (dataFile))
# Close file
file.close()
# Run pyxplot on the files, but don't wait for execution to finish
# Instead, set timer to poll for the process to finish
try:
self.pyxplot = subprocess.Popen(["pyxplot", commandFile])
# Poll the process to add a watcher as soon as it has created the graphics file
if len(self.watcher.files()) == 0:
self.timer.start()
except OSError:
FreeCAD.Console.PrintError("Can't execute pyxplot. Maybe it is not installed?\n")
self.updatePending = False
def pollFile(self):
# Check if process has finished
if self.pyxplot.poll() is None:
return
# Check if the graphics file has appeared and then set a watcher on it
if not os.path.isfile(self.graphicsFile):
return
# We don't need the timer any more now
self.timer.stop()
FreeCADGui.SendMsgToActiveView('Refresh')
self.watcher.addPath(self.graphicsFile)
def updateFinished(self, filePath):
# filePath is not important because we are only watching a single file
# FIXME: Will give a warning in the console if the active window is not the HTML page
FreeCADGui.SendMsgToActiveView('Refresh')
if self.updatePending is True:
self.write()
def minmaxX(self):
xpoints = []
for (x, y) in self.points:
xpoints.append(x)
return (min(xpoints), max(xpoints))
def minmaxY(self):
ypoints = []
for (x, y) in self.points:
ypoints.append(y)
return (min(ypoints), max(ypoints))
(self.xpoints, self.ypoints) = self.function.evaluate(self.xlength, self.numxpoints)
# Create plot
self.plot()
def plot(self):
plots = self.thePlot.series
if plots:
# Remove line from plot
axes = plots[0].axes
axes.lines.pop(plots[0].lid)
# Remove serie from list
del self.thePlot.series[0]
self.thePlot.update()
self.thePlot.plot(self.xpoints, self.ypoints)