From a375f6b4a9a2858323acb211acfac1575dab1f66 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 15 Nov 2012 19:20:15 +0430 Subject: [PATCH] Use plot module for graphs --- .../PartDesign/WizardShaft/SegmentFunction.py | 12 +- src/Mod/PartDesign/WizardShaft/Shaft.py | 53 +----- .../PartDesign/WizardShaft/ShaftDiagram.py | 161 ++++-------------- 3 files changed, 40 insertions(+), 186 deletions(-) diff --git a/src/Mod/PartDesign/WizardShaft/SegmentFunction.py b/src/Mod/PartDesign/WizardShaft/SegmentFunction.py index 629c2acda..a9e7c501e 100644 --- a/src/Mod/PartDesign/WizardShaft/SegmentFunction.py +++ b/src/Mod/PartDesign/WizardShaft/SegmentFunction.py @@ -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 + " = ") diff --git a/src/Mod/PartDesign/WizardShaft/Shaft.py b/src/Mod/PartDesign/WizardShaft/Shaft.py index ff5da1afc..8dffa008a 100644 --- a/src/Mod/PartDesign/WizardShaft/Shaft.py +++ b/src/Mod/PartDesign/WizardShaft/Shaft.py @@ -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 = """ - - - - - - - - -

-""" -htmlFooter = """ -

- - -""" - 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("\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) diff --git a/src/Mod/PartDesign/WizardShaft/ShaftDiagram.py b/src/Mod/PartDesign/WizardShaft/ShaftDiagram.py index 715453d8a..74962dded 100644 --- a/src/Mod/PartDesign/WizardShaft/ShaftDiagram.py +++ b/src/Mod/PartDesign/WizardShaft/ShaftDiagram.py @@ -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)