Use plot module for graphs
This commit is contained in:
parent
1eb738fc3f
commit
a375f6b4a9
|
@ -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 + " = ")
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue
Block a user