/* * Copyright (c) 2002-2006 Samit Basu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "HandleCommands.hpp" #include "HandleFigure.hpp" #include "Parser.hpp" #include "Scanner.hpp" #include "Token.hpp" #include #include #include #include #include "HandleLineSeries.hpp" #include "HandleObject.hpp" #include "HandleText.hpp" #include "HandleAxis.hpp" #include "HandleImage.hpp" #include #include "HandleList.hpp" #include "HandleSurface.hpp" #include "HandleWindow.hpp" #include "HandleContour.hpp" #include "HandleUIControl.hpp" #include "QTRenderEngine.hpp" #include "Interpreter.hpp" #include // Subplot // labels don't always appear properly. // linestyle/symbol specification // images QWidget *save = NULL; void SaveFocus() { save = qApp->focusWidget(); } void RestoreFocus() { if (save) save->setFocus(); } HandleWindow* Hfigs[MAX_FIGS]; int HcurrentFig = -1; static bool HGInitialized = false; void InitializeHandleGraphics() { if (HGInitialized) return; for (int i=0;ihide(); delete Hfigs[i]; } Hfigs[i] = NULL; } HcurrentFig = -1; } // Magic constant - limits the number of figures you can have... HandleList objectset; void NotifyFigureClosed(unsigned figNum) { // delete Hfigs[figNum]; Hfigs[figNum] = NULL; if (figNum == HcurrentFig) HcurrentFig = -1; // Check for all figures closed bool allClosed = true; for (int i=0;allClosed && ishow(); RestoreFocus(); HcurrentFig = figNum; } static HandleWindow* CurrentWindow() { if (HcurrentFig == -1) NewFig(); return (Hfigs[HcurrentFig]); } static HandleFigure* CurrentFig() { if (HcurrentFig == -1) NewFig(); return (Hfigs[HcurrentFig]->HFig()); } static void SelectFig(int fignum) { if (fignum < 0) throw Exception("Illegal argument to SelectFig"); if (Hfigs[fignum] == NULL) Hfigs[fignum] = new HandleWindow(fignum); SaveFocus(); Hfigs[fignum]->show(); Hfigs[fignum]->raise(); RestoreFocus(); HcurrentFig = fignum; } //! //@Module DRAWNOW Flush the Event Queue //@@Section HANDLE //@@Usage //The @|drawnow| function can be used to process the events in the //event queue of the FreeMat application. The syntax for its use //is //@[ // drawnow //@] //Now that FreeMat is threaded, you do not generally need to call this //function, but it is provided for compatibility. //! bool AnyDirty(bool issueUpdates) { bool retval = false; if (!HGInitialized) return false; for (int i=0;iisDirty())) { retval = true; if (issueUpdates) Hfigs[i]->repaint(); } } return retval; } static bool in_DoDrawNow = false; void DoDrawNow() { if (in_DoDrawNow) return; in_DoDrawNow = true; if (AnyDirty(true)) while (AnyDirty(false)) qApp->processEvents(); in_DoDrawNow = false; } ArrayVector DrawNowFunction(int nargout, const ArrayVector& arg) { GfxEnableRepaint(); DoDrawNow(); GfxDisableRepaint(); return ArrayVector(); } HandleObject* LookupHandleObject(unsigned handle) { return (objectset.lookupHandle(handle-HANDLE_OFFSET_OBJECT)); } HandleFigure* LookupHandleFigure(unsigned handle) { if (Hfigs[handle-HANDLE_OFFSET_FIGURE] != NULL) return Hfigs[handle-HANDLE_OFFSET_FIGURE]->HFig(); else { SelectFig(handle-HANDLE_OFFSET_FIGURE); return Hfigs[handle-HANDLE_OFFSET_FIGURE]->HFig(); } } void ValidateHandle(unsigned handle) { if (handle == 0) return; if (handle >= HANDLE_OFFSET_OBJECT) LookupHandleObject(handle); else LookupHandleFigure(handle); } unsigned AssignHandleObject(HandleObject* hp) { return (objectset.assignHandle(hp)+HANDLE_OFFSET_OBJECT); } void FreeHandleObject(unsigned handle) { objectset.deleteHandle(handle-HANDLE_OFFSET_OBJECT); } //! //@Module FIGURE Figure Window Select and Create Function //@@Section HANDLE //@@Usage //Changes the active figure window to the specified figure //number. The general syntax for its use is //@[ // figure(number) //@] //where @|number| is the figure number to use. If the figure window //corresponding to @|number| does not already exist, a new //window with this number is created. If it does exist //then it is brought to the forefront and made active. //You can use @|gcf| to obtain the number of the current figure. // //Note that the figure number is also the handle for the figure. //While for most graphical objects (e.g., axes, lines, images), the //handles are large integers, for figures, the handle is the same //as the figure number. This means that the figure number can be //passed to @|set| and @|get| to modify the properties of the //current figure, (e.g., the colormap). So, for figure @|3|, for //example, you can use @|get(3,'colormap')| to retrieve the colormap //for the current figure. //! ArrayVector HFigureFunction(int nargout,const ArrayVector& arg) { if (arg.size() == 0) { NewFig(); return singleArrayVector(Array::int32Constructor(HcurrentFig+1)); } else { Array t(arg[0]); int fignum = t.getContentsAsIntegerScalar(); if ((fignum<=0) || (fignum>MAX_FIGS)) throw Exception("figure number is out of range - it must be between 1 and 50"); SelectFig(fignum-1); return ArrayVector(); } } void AddToCurrentFigChildren(unsigned handle) { HandleFigure *fig = CurrentFig(); HPHandles *cp = (HPHandles*) fig->LookupProperty("children"); std::vector children(cp->Data()); // Check to make sure that children does not contain our handle already int i=0; while (iData(children); } //! //@Module AXES Create Handle Axes //@@Section HANDLE //@@Usage //This function has three different syntaxes. The first takes //no arguments, //@[ // h = axes //@] //and creates a new set of axes that are parented to the current //figure (see @|gcf|). The newly created axes are made the current //axes (see @|gca|) and are added to the end of the list of children //for the current figure. //The second form takes a set of property names and values //@[ // h = axes(propertyname,value,propertyname,value,...) //@] //Creates a new set of axes, and then sets the specified properties //to the given value. This is a shortcut for calling //@|set(h,propertyname,value)| for each pair. //The third form takes a handle as an argument //@[ // axes(handle) //@] //and makes @|handle| the current axes, placing it at the head of //the list of children for the current figure. //! ArrayVector HAxesFunction(int nargout, const ArrayVector& arg) { if (arg.size() != 1) { HandleObject *fp = new HandleAxis; unsigned int handle = AssignHandleObject(fp); ArrayVector t(arg); while (t.size() >= 2) { std::string propname(ArrayToString(t[0])); fp->LookupProperty(propname)->Set(t[1]); t.pop_front(); t.pop_front(); } // Get the current figure HandleFigure *fig = CurrentFig(); fp->SetPropertyHandle("parent",HcurrentFig+1); fig->SetPropertyHandle("currentaxes",handle); // Add us to the children... AddToCurrentFigChildren(handle); fp->UpdateState(); return singleArrayVector(Array::uint32Constructor(handle)); } else { unsigned int handle = (unsigned int) ArrayToInt32(arg[0]); HandleObject* hp = LookupHandleObject(handle); if (!hp->IsType("axes")) throw Exception("single argument to axes function must be handle for an axes"); AddToCurrentFigChildren(handle); // Get the current figure CurrentFig()->SetPropertyHandle("currentaxes",handle); CurrentFig()->UpdateState(); return ArrayVector(); } } void HSetChildrenFunction(HandleObject *fp, Array children) { children.promoteType(FM_UINT32); const unsigned *dp = (const unsigned*) children.getDataPointer(); // make sure they are all valid handles for (int i=0;iLookupProperty("children"); std::vector my_children(hp->Data()); for (int i=0;i= HANDLE_OFFSET_OBJECT) { gp = LookupHandleObject(handle); gp->Dereference(); } } // Loop through the new list of children for (int i=0;i= HANDLE_OFFSET_OBJECT) { gp = LookupHandleObject(handle); gp->Reference(); } } // Check for anyone with a zero reference count - it should // be deleted for (int i=0;i= HANDLE_OFFSET_OBJECT) { gp = LookupHandleObject(handle); if (gp->RefCount() <= 0) { if (gp->StringPropertyLookup("type") == "uicontrol") ((HandleUIControl*) gp)->Hide(); FreeHandleObject(handle); delete gp; } } } // Call the generic set function now hp->Set(children); } //! //@Module SET Set Object Property //@@Section HANDLE //@@Usage //This function allows you to change the value associated //with a property. The syntax for its use is //@[ // set(handle,property,value,property,value,...) //@] //where @|property| is a string containing the name of the //property, and @|value| is the value for that property. The //type of the variable @|value| depends on the property being //set. See the help for the properties to see what values //you can set. //! ArrayVector HSetFunction(int nargout, const ArrayVector& arg) { if (arg.size() < 3) throw Exception("set doesn't handle all cases yet!"); int handle = ArrayToInt32(arg[0]); // Lookup the handle HandleObject *fp; if (handle >= HANDLE_OFFSET_OBJECT) fp = LookupHandleObject(handle); else fp = (HandleObject*) LookupHandleFigure(handle); int ptr = 1; while (arg.size() >= (ptr+2)) { // Use the address and property name to lookup the Get/Set handler std::string propname = ArrayToString(arg[ptr]); // Special case 'set' for 'children' - this can change reference counts // Special case 'set' for 'figsize' - this requires help from the OS if (propname == "children") HSetChildrenFunction(fp,arg[ptr+1]); else if ((handle < HANDLE_OFFSET_OBJECT) && (propname == "figsize")) { fp->LookupProperty(propname)->Set(arg[ptr+1]); HandleFigure *fig = (HandleFigure*) fp; fig->SetSize(); } else { try { fp->LookupProperty(propname)->Set(arg[ptr+1]); } catch (Exception &e) { throw Exception(std::string("Got error ") + std::string(e.getMessageCopy()) + std::string(" for property ") + propname); } } ptr+=2; } fp->UpdateState(); if (!fp->IsType("figure") && !fp->IsType("uicontrol")) { HandleFigure *fig = fp->GetParentFigure(); fig->UpdateState(); fig->Repaint(); } return ArrayVector(); } //! //@Module GET Get Object Property //@@Section HANDLE //@@Usage //This function allows you to retrieve the value associated //with a property. The syntax for its use is //@[ // value = get(handle,property) //@] //where @|property| is a string containing the name of the //property, and @|value| is the value for that property. The //type of the variable @|value| depends on the property being //set. See the help for the properties to see what values //you can set. //! ArrayVector HGetFunction(int nargout, const ArrayVector& arg) { if (arg.size() != 2) throw Exception("get doesn't handle all cases yet!"); int handle = ArrayToInt32(arg[0]); std::string propname = ArrayToString(arg[1]); // Lookup the handle HandleObject *fp; if (handle >= HANDLE_OFFSET_OBJECT) fp = LookupHandleObject(handle); else fp = (HandleObject*) LookupHandleFigure(handle); // Use the address and property name to lookup the Get/Set handler return singleArrayVector(fp->LookupProperty(propname)->Get()); } unsigned GenericConstructor(HandleObject* fp, const ArrayVector& arg, bool autoParentGiven = true) { unsigned int handle = AssignHandleObject(fp); ArrayVector t(arg); while (t.size() >= 2) { std::string propname(ArrayToString(t[0])); if (propname == "autoparent") { std::string pval(ArrayToString(t[1])); autoParentGiven = (pval == "on"); } else { try { fp->LookupProperty(propname)->Set(t[1]); } catch (Exception &e) { throw Exception(std::string("Got error ") + std::string(e.getMessageCopy()) + std::string(" for property ") + propname); } } t.pop_front(); t.pop_front(); } if (autoParentGiven) { HandleFigure *fig = CurrentFig(); unsigned current = fig->HandlePropertyLookup("currentaxes"); if (current == 0) { ArrayVector arg2; HAxesFunction(0,arg2); current = fig->HandlePropertyLookup("currentaxes"); } HandleAxis *axis = (HandleAxis*) LookupHandleObject(current); HPHandles *cp = (HPHandles*) axis->LookupProperty("children"); std::vector children(cp->Data()); children.push_back(handle); cp->Data(children); cp = (HPHandles*) fp->LookupProperty("parent"); std::vector parent; parent.push_back(current); cp->Data(parent); axis->UpdateState(); } fp->UpdateState(); return handle; } //! //@Module HLINE Create a line object //@@Section HANDLE //@@Usage //Creates a line object and parents it to the current axis. The //syntax for its use is //@[ // handle = hline(property,value,property,value,...) //@] //where @|property| and @|value| are set. The handle ID for the //resulting object is returned. It is automatically added to //the children of the current axis. //! ArrayVector HLineFunction(int nargout, const ArrayVector& arg) { return singleArrayVector(Array::uint32Constructor(GenericConstructor(new HandleLineSeries,arg))); } //! //@Module HCONTOUR Create a contour object //@@Section HANDLE //@@Usage //Creates a contour object and parents it to the current axis. The //syntax for its use is //@[ // handle = hcontour(property,value,property,value,...) //@] //where @|property| and @|value| are set. The handle ID for the //resulting object is returned. It is automatically added to //the children of the current axis. //! ArrayVector HContourFunction(int nargout, const ArrayVector& arg) { return singleArrayVector(Array::uint32Constructor(GenericConstructor(new HandleContour,arg))); } //! //@Module UICONTROL Create a UI Control object //@@Section HANDLE //@@Usage //Creates a UI control object and parents it to the current figure. The //syntax for its use is //@[ // handle = uicontrol(property,value,property,value,...) //@] //where @|property| and @|value| are set. The handle ID for the //resulting object is returned. It is automatically added to //the children of the current figure. //! ArrayVector HUIControlFunction(int nargout, const ArrayVector& arg, Interpreter *eval) { HandleUIControl *o = new HandleUIControl; o->SetEvalEngine(eval); o->ConstructWidget(CurrentWindow()); unsigned handleID = GenericConstructor(o,arg,false); // Parent the control to the current figure AddToCurrentFigChildren(handleID); HPHandles* cp = (HPHandles*) o->LookupProperty("parent"); std::vector parent; parent.push_back(HcurrentFig+1); cp->Data(parent); return singleArrayVector(Array::uint32Constructor(handleID)); } //! //@Module HIMAGE Create a image object //@@Section HANDLE //@@Usage //Creates a image object and parents it to the current axis. The //syntax for its use is //@[ // handle = himage(property,value,property,value,...) //@] //where @|property| and @|value| are set. The handle ID for the //resulting object is returned. It is automatically added to //the children of the current axis. //! ArrayVector HImageFunction(int nargout, const ArrayVector& arg) { return singleArrayVector(Array::uint32Constructor(GenericConstructor(new HandleImage,arg))); } //! //@Module HTEXT Create a text object //@@Section HANDLE //@@Usage //Creates a text object and parents it to the current axis. The //syntax for its use is //@[ // handle = htext(property,value,property,value,...) //@] //where @|property| and @|value| are set. The handle ID for the //resulting object is returned. It is automatically added to //the children of the current axis. //! ArrayVector HTextFunction(int nargout, const ArrayVector& arg) { return singleArrayVector(Array::uint32Constructor(GenericConstructor(new HandleText,arg))); } //! //@Module HSURFACE Create a surface object //@@Section HANDLE //@@Usage //Creates a surface object and parents it to the current axis. The //syntax for its use is //@[ // handle = hsurface(property,value,property,value,...) //@] //where @|property| and @|value| are set. The handle ID for the //resulting object is returned. It is automatically added to //the children of the current axis. //! ArrayVector HSurfaceFunction(int nargout, const ArrayVector& arg) { return singleArrayVector(Array::uint32Constructor(GenericConstructor(new HandleSurface,arg))); } //! //@Module FIGRAISE Raise a Figure Window //@@Section HANDLE //@@Usage //Raises a figure window indicated by the figure number. The syntax for //its use is //@[ // figraise(fignum) //@] //where @|fignum| is the number of the figure to raise. The figure will //be raised to the top of the GUI stack (meaning that it we be visible). //Note that this function does not cause @|fignum| to become the current //figure, you must use the @|figure| command for that. //! ArrayVector FigRaiseFunction(int nargout, const ArrayVector& args) { if (args.size() == 0) CurrentWindow()->raise(); else { int fignum = ArrayToInt32(args[0]); if ((fignum >= 1) && (fignum < MAX_FIGS+1)) { if (Hfigs[fignum-1]) Hfigs[fignum-1]->raise(); else { Hfigs[fignum-1] = new HandleWindow(fignum-1); Hfigs[fignum-1]->show(); Hfigs[fignum-1]->raise(); } } } return ArrayVector(); } //! //@Module FIGLOWER Lower a Figure Window //@@Section HANDLE //@@Usage //Lowers a figure window indicated by the figure number. The syntax for //its use is //@[ // figlower(fignum) //@] //where @|fignum| is the number of the figure to lower. The figure will //be lowerd to the bottom of the GUI stack (meaning that it we be behind other //windows). Note that this function does not cause @|fignum| to //become the current figure, you must use the @|figure| command for that. //Similarly, if @|fignum| is the current figure, it will remain the current //figure (even though the figure is now behind others). //! ArrayVector FigLowerFunction(int nargout, const ArrayVector& args) { if (args.size() == 0) CurrentWindow()->lower(); else { int fignum = ArrayToInt32(args[0]); if ((fignum >= 1) && (fignum < MAX_FIGS+1)) { if (Hfigs[fignum-1]) Hfigs[fignum-1]->lower(); else { Hfigs[fignum-1] = new HandleWindow(fignum-1); Hfigs[fignum-1]->show(); Hfigs[fignum-1]->lower(); } } } return ArrayVector(); } //! //@Module GCF Get Current Figure //@@Section HANDLE //@@Usage //Returns the figure number for the current figure (which is also its handle, //and can be used to set properties of the current figure using @|set|). //The syntax for its use //is //@[ // figure_number = gcf //@] //where @|figure_number| is the number of the active figure (also the handle of //the figure). // //Note that figures have handles, just like axes, images, plots, etc. However //the handles for figures match the figure number (while handles for other //graphics objects tend to be large, somewhat arbitrary integers). So, to //retrieve the colormap of the current figure, you could //use @|get(gcf,'colormap')|, or to obtain the colormap for figure 3, //use @|get(3,'colormap')|. //! ArrayVector HGCFFunction(int nargout, const ArrayVector& arg) { if (HcurrentFig == -1) NewFig(); return singleArrayVector(Array::uint32Constructor(HcurrentFig+1)); } //! //@Module GCA Get Current Axis //@@Section HANDLE //@@Usage //Returns the handle for the current axis. The syntax for its use //is //@[ // handle = gca //@] //where @|handle| is the handle of the active axis. All object //creation functions will be children of this axis. //! ArrayVector HGCAFunction(int nargout, const ArrayVector& arg) { // Get the current figure... if (HcurrentFig == -1) NewFig(); HandleFigure* fig = CurrentFig(); unsigned current = fig->HandlePropertyLookup("currentaxes"); if (current == 0) { ArrayVector arg2; HAxesFunction(0,arg2); current = fig->HandlePropertyLookup("currentaxes"); } return singleArrayVector(Array::uint32Constructor(current)); } //! //@Module PVALID Validate Property Name //@@Section HANDLE //@@Usage //This function checks to see if the given string is a valid //property name for an object of the given type. The syntax //for its use is //@[ // b = pvalid(type,propertyname) //@] //where @|string| is a string that contains the name of a // valid graphics object type, and //@|propertyname| is a string that contains the name of the //property to test for. //@@Example //Here we test for some properties on an @|axes| object. //@< //pvalid('axes','type') //pvalid('axes','children') //pvalid('axes','foobar') //@> //! ArrayVector HPropertyValidateFunction(int nargout, const ArrayVector& arg) { if (arg.size() != 2) throw Exception("pvalid requires two arguments, an object type name and a property name"); std::string objectname = ArrayToString(arg[0]); HandleObject *fp; if (objectname == "axes") fp = new HandleAxis; else if (objectname == "line") fp = new HandleLineSeries; else if (objectname == "text") fp = new HandleText; else throw Exception("Unrecognized object type name " + objectname); std::string propname = ArrayToString(arg[1]); bool isvalid; isvalid = true; try { fp->LookupProperty(propname); } catch (Exception& e) { isvalid = false; } delete fp; return singleArrayVector(Array::logicalConstructor(isvalid)); } bool PrintBaseFigure(HandleWindow* g, std::string filename, std::string type) { bool retval; HPColor *color = (HPColor*) g->HFig()->LookupProperty("color"); double cr, cg, cb; cr = color->At(0); cg = color->At(1); cb = color->At(2); g->HFig()->SetThreeVectorDefault("color",1,1,1); GfxEnableRepaint(); g->UpdateState(); while (g->isDirty()) qApp->processEvents(); if ((type == "PDF") || (type == "PS") || (type == "EPS")){ QPrinter prnt; if (type == "PDF") prnt.setOutputFormat(QPrinter::PdfFormat); else prnt.setOutputFormat(QPrinter::PostScriptFormat); prnt.setOutputFileName(filename.c_str()); QPainter pnt(&prnt); QTRenderEngine gc(&pnt,0,0,g->width(),g->height()); g->HFig()->PaintMe(gc); retval = true; } else { // Binary print - use grabWidget QPixmap pxmap(QPixmap::grabWidget(g->GetQtWidget())); QImage img(pxmap.toImage()); retval = img.save(filename.c_str(),type.c_str()); } g->HFig()->SetThreeVectorDefault("color",cr,cg,cb); g->UpdateState(); while (g->isDirty()) qApp->processEvents(); GfxDisableRepaint(); return retval; } void CloseHelper(int fig) { if (fig == -1) return; if (Hfigs[fig] == NULL) return; Hfigs[fig]->hide(); delete Hfigs[fig]; Hfigs[fig] = NULL; if (HcurrentFig == fig) HcurrentFig = -1; } //! //@Module CLOSE Close Figure Window //@@Section HANDLE //@@Usage //Closes a figure window, either the currently active window, a //window with a specific handle, or all figure windows. The general //syntax for its use is //@[ // close(handle) //@] //in which case the figure window with the speicified @|handle| is //closed. Alternately, issuing the command with no argument //@[ // close //@] //is equivalent to closing the currently active figure window. Finally //the command //@[ // close('all') //@] //closes all figure windows currently open. //! ArrayVector HCloseFunction(int nargout, const ArrayVector& arg) { if (arg.size() > 1) throw Exception("close takes at most one argument - either the string 'all' to close all figures, or a scalar integer indicating which figure is to be closed."); int action; if (arg.size() == 0) action = 0; else { Array t(arg[0]); if (t.isString()) { string allflag = t.getContentsAsString(); if (allflag == "all") action = -1; else throw Exception("string argument to close function must be 'all'"); } else { int handle = t.getContentsAsIntegerScalar(); if (handle < 1) throw Exception("Invalid figure number argument to close function"); action = handle; } } if (action == 0) { if (HcurrentFig != -1) CloseHelper(HcurrentFig); } else if (action == -1) { for (int i=0;i= 1)) CloseHelper(action-1); } return ArrayVector(); } //! //@Module COPY Copy Figure Window //@@Section HANDLE //@@Usage //Copies the currently active figure window to the clipboard. //The syntax for its use is: //@[ // copy //@] //The resulting figure is copied as a bitmap to the clipboard, //and can then be pasted into any suitable application. //! ArrayVector HCopyFunction(int nargout, const ArrayVector& arg) { if (HcurrentFig == -1) return ArrayVector(); HandleWindow *f = Hfigs[HcurrentFig]; // use grabWidget - doesnt work for openGL yet QClipboard *cb = QApplication::clipboard(); cb->setPixmap(QPixmap::grabWidget(f)); return ArrayVector(); } std::string NormalizeImageExtension(std::string ext) { std::string upperext(ext); std::string lowerext(ext); std::transform(upperext.begin(),upperext.end(),upperext.begin(), (int(*)(int))toupper); std::transform(lowerext.begin(),lowerext.end(),lowerext.begin(), (int(*)(int))tolower); if (upperext == "JPG") return std::string("JPEG"); if ((upperext == "PDF") || (upperext == "PS") || (upperext == "EPS")) return upperext; QList formats(QImageWriter::supportedImageFormats()); for (int i=0;i formats(QImageWriter::supportedImageFormats()); for (int i=0;i //which creates two plots @|printfig1.png|, which is a Portable //Net Graphics file, and @|printfig1.jpg| which is a JPEG file. //@figure printfig1 //! ArrayVector HPrintFunction(int nargout, const ArrayVector& arg) { if (arg.size() != 1) throw Exception("print function takes a single, string argument"); if (!(arg[0].isString())) throw Exception("print function takes a single, string argument"); Array t(arg[0]); if (HcurrentFig == -1) return ArrayVector(); HandleWindow *f = Hfigs[HcurrentFig]; std::string outname(t.getContentsAsString()); int pos = outname.rfind("."); if (pos < 0) throw Exception("print function argument must contain an extension - which is used to determine the format for the output"); std::string original_extension(outname.substr(pos+1,outname.size())); std::string modified_extension = NormalizeImageExtension(original_extension); if (modified_extension.empty()) throw Exception(std::string("unsupported output format ") + original_extension + " for print.\n" + FormatListAsString()); if (!PrintBaseFigure(f,outname,modified_extension)) throw Exception("Printing failed!"); return ArrayVector(); } //! //@Module HPOINT Get Point From Window //@@Section HANDLE //@@Usage //This function waits for the user to click on the current figure //window, and then returns the coordinates of that click. The //generic syntax for its use is //@[ // [x,y] = hpoint //@] //! ArrayVector HPointFunction(int nargout, const ArrayVector& arg) { if (HcurrentFig == -1) return ArrayVector(); HandleWindow *f = Hfigs[HcurrentFig]; f->raise(); f->activateWindow(); f->setFocus(Qt::OtherFocusReason); int x, y; f->GetClick(x,y); Array retval(Array::doubleVectorConstructor(2)); double *d_ip; d_ip = (double*) retval.getReadWriteDataPointer(); d_ip[0] = (double) x; d_ip[1] = (double) y; return singleArrayVector(retval); } //! //@Module IS2DVIEW Test Axes For 2D View //@@Section HANDLE //@@Usage //This function returns @|true| if the current axes are in a //2-D view, and false otherwise. The generic syntax for its //use is //@[ // y = is2dview(x) //@] //where @|x| is the handle of an axes object. //! ArrayVector HIs2DViewFunction(int nargout, const ArrayVector& arg) { if (arg.size() == 0) throw Exception("is2DView expects a handle to axes"); unsigned int handle = (unsigned int) ArrayToInt32(arg[0]); HandleObject* hp = LookupHandleObject(handle); if (!hp->IsType("axes")) throw Exception("single argument to axes function must be handle for an axes"); HandleAxis *axis = (HandleAxis*) hp; return singleArrayVector(Array::logicalConstructor(axis->Is2DView())); } #if 0 class contour_point { public: double x; double y; inline contour_point(double a, double b) : x(a), y(b) {}; }; inline bool operator==(const contour_point& p1, const contour_point& p2) { return ((p1.x == p2.x) && (p1.y == p2.y)); } typedef QList cline; typedef QList lineset; inline cline Reverse(const cline& src) { cline ret; for (int i=src.size()-1;i>=0;i--) ret << src.at(i); return ret; } inline bool Connected(const cline& current, const cline& test) { return ((current.front() == test.front()) || (current.front() == test.back()) || (current.back() == test.front()) || (current.back() == test.back())); } inline void Join(cline& current, const cline& toadd) { if (current.front() == toadd.front()) current = Reverse(toadd) + current; else if (current.front() == toadd.back()) current = toadd + current; else if (current.back() == toadd.front()) current += toadd; else if (current.back() == toadd.back()) current += Reverse(toadd); } #define FOLD(x) MAP((x),row-1) #define FNEW(x) MAP((x),row) #define MAP(x,y) func[(y)+(x)*numy] #define AINTER(a,b) ((val-(a))/((b)-(a))) #define ALEFT(i,j) (((j)-1)+AINTER(FOLD((i)-1),FNEW((i)-1))) #define TOP(i) (((i)-1)+AINTER(FNEW((i)-1),FNEW((i)))) #define BOT(i) (((i)-1)+AINTER(FOLD((i)-1),FOLD((i)))) #define RIGHT(i,j) (((j)-1)+AINTER(FOLD((i)),FNEW((i)))) #define DRAW(a,b,c,d) {allLines << (cline() << contour_point((double)a,(double)b) << contour_point((double)c,(double)d));} ArrayVector ContourCFunction(int nargout, const ArrayVector& arg) { lineset allLines; lineset bundledLines; if (arg.size() < 2) throw Exception("contourc expects two arguments"); double val = ArrayToDouble(arg[1]); if (!arg[0].is2D()) throw Exception("First argument to contourc must be a 2D matrix"); Array m(arg[0]); m.promoteType(FM_DOUBLE); const double *func = (const double *) m.getDataPointer(); int outcnt = 0; int numy = m.rows(); int numx = m.columns(); for (int row=1;row= val) l = l + 1; if (FOLD(col-1) >= val) l = l + 2; if (FNEW(col) >= val) l = l + 4; if (FNEW(col-1) >= val) l = l + 8; switch (l) { case 1: case 14: DRAW(BOT(col),row-1,col,RIGHT(col,row)); break; case 2: case 13: DRAW(col-1,ALEFT(col,row),BOT(col),row-1); break; case 3: case 12: DRAW(col-1,ALEFT(col,row),col,RIGHT(col,row)); break; case 4: case 11: DRAW(TOP(col),row,col,RIGHT(col,row)); break; case 5: case 10: DRAW(BOT(col),row-1,TOP(col),row); break; case 6: case 9: { double x0 = AINTER(FOLD(col-1),FOLD(col)); double x1 = AINTER(FNEW(col-1),FNEW(col)); double y0 = AINTER(FOLD(col-1),FNEW(col-1)); double y1 = AINTER(FOLD(col),FNEW(col)); double y = (x0*(y1-y0)+y0)/(1.0-(x1-x0)*(y1-y0)); double x = y*(x1-x0) + x0; double fx1 = MAP(col-1,row-1)+x*(MAP(col,row-1)-MAP(col-1,row-1)); double fx2 = MAP(col-1,row)+x*(MAP(col,row)-MAP(col-1,row)); double f = fx1 + y*(fx2-fx1); if (f==val) { DRAW(BOT(col),row-1,TOP(col),row); DRAW(col-1,ALEFT(col,row),col,RIGHT(col,row)); } else if (((f > val) && (FNEW(col) > val)) || ((f < val) && (FNEW(col) < val))) { DRAW(col-1,ALEFT(col,row),TOP(col),row); DRAW(BOT(col),row-1,col,RIGHT(col,row)); } else { DRAW(col-1,ALEFT(col,row),BOT(col),row-1); DRAW(TOP(col),row,col,RIGHT(col,row)); } } break; case 7: case 8: DRAW(col-1,ALEFT(col,row),TOP(col),row); break; } } // Now we link the line segments into longer lines. int allcount = allLines.size(); while (!allLines.empty()) { // Start a new line segment cline current(allLines.takeAt(0)); bool lineGrown = true; while (lineGrown) { lineGrown = false; int i = 0; while (iaddGfxFunction("is2dview",HIs2DViewFunction,1,1,"x",NULL); context->addGfxFunction("axes",HAxesFunction,-1,1,NULL); context->addGfxFunction("hline",HLineFunction,-1,1,NULL); context->addGfxFunction("htext",HTextFunction,-1,1,NULL); context->addGfxFunction("himage",HImageFunction,-1,1,NULL); context->addGfxFunction("hcontour",HContourFunction,-1,1,NULL); context->addGfxFunction("surface",HSurfaceFunction,-1,1,NULL); context->addGfxFunction("set",HSetFunction,-1,0,NULL); context->addGfxFunction("get",HGetFunction,2,1,"handle","propname",NULL); context->addGfxFunction("figure",HFigureFunction,1,1,"number",NULL); context->addGfxSpecialFunction("uicontrol",HUIControlFunction,-1,1,NULL); context->addGfxFunction("gca",HGCAFunction,0,1,NULL); context->addGfxFunction("gcf",HGCFFunction,0,1,NULL); context->addGfxFunction("pvalid",HPropertyValidateFunction,2,1,"type","property",NULL); context->addGfxFunction("print",HPrintFunction,-1,0,NULL); context->addGfxFunction("close",HCloseFunction,1,0,"handle",NULL); context->addGfxFunction("copy",HCopyFunction,0,0,NULL); context->addGfxFunction("hpoint",HPointFunction,0,1,NULL); context->addGfxFunction("drawnow",DrawNowFunction,0,0,NULL); context->addGfxFunction("figraise",FigRaiseFunction,1,0,"handle",NULL); context->addGfxFunction("figlower",FigLowerFunction,1,0,"handle",NULL); // context->addFunction("contourc",ContourCFunction,2,1,"z","v",NULL); // context->addSpecialFunction("demo",HDemoFunction,1,1,NULL); InitializeHandleGraphics(); };