Mercurial > hg > octave-lojdl
changeset 17383:f983570ba8b8
Merged with main, after adding temporary directory in latex_render.
author | Andrej Lojdl <andrej.lojdl@gmail.com> |
---|---|
date | Wed, 04 Sep 2013 18:40:34 +0200 |
parents | dc103ce7c8cf (current diff) 3e95b22f5287 (diff) |
children | 609d93683f15 |
files | |
diffstat | 11 files changed, 582 insertions(+), 160 deletions(-) [+] |
line wrap: on
line diff
--- a/NEWS +++ b/NEWS @@ -128,6 +128,25 @@ expression would have searched for a literal '\' followed by 't' and replaced the two characters with the sequence '\', 'n'. + ** A TeX parser has been implemented for the FLTK toolkit and is the default + for any text object including titles and axis labels. The TeX parser is + supported only for display on a monitor, not for printing. + A quick summary of features: + + Code Feature Example Comment + _ subscript H_2O formula for water + ^ exponent y=x^2 formula for parabola + \char symbol \beta Greek symbol beta + \fontname font \fontname{Arial} set Arial font + \fontsize fontsize \fontsize{16} set fontsize 16 + \color[rgb] fontcolor \color[rgb]{1 0 1} set magenta color + \bf bold \bfBold Text bold font + \it italic \itItalic Text italic font + \sl slanted \slOblique Text slanted font + \rm normal \bfBold\rmNormal normal font + {} group {\bf Bold}Normal group objects + e^{i*\pi} = -1 complex example + ** The m-files in the image directory have been overhauled. The principal benefit is that Octave will now no longer automatically
--- a/doc/interpreter/contributors.in +++ b/doc/interpreter/contributors.in @@ -42,9 +42,9 @@ Michael Creel Jeff Cunningham Martin Dalecki +Jacob Dawid Jorge Barros de Abreu Carlo de Falco -Jacob Dawid Thomas D. Dean Philippe Defert Bill Denney @@ -161,21 +161,21 @@ Massimo Lorenzin Emil Lucretiu Hoxide Ma +Colin Macdonald James Macnicol Jens-Uwe Mager -Colin Macdonald Rob Mahurin +Alexander Mamonov Ricardo Marranita Orestes Mas Axel Mathéi Makoto Matsumoto Tatsuro Matsuoka +Christoph Mayer Laurent Mazet G. D. McBain -Alexander Mamonov -Christoph Mayer +Ronald van der Meer Júlio Hoffimann Mendes -Ronald van der Meer Thorsten Meyer Petr Mikulik Mike Miller @@ -229,6 +229,7 @@ E. Joshua Rigler Petter Risholm Matthew W. Roberts +Peter Rosin Andrew Ross Fabio Rossi Mark van Rossum @@ -273,25 +274,25 @@ Ivan Sutoris John Swensen Daisuke Takago +Ariel Tankus Falk Tannhäuser -Ariel Tankus +Duncan Temple Lang Matthew Tenny +Kris Thielemans Georg Thimm -Duncan Temple Lang -Kris Thielemans Olaf Till Christophe Tournery Thomas Treichl Karsten Trulsen Frederick Umminger Utkarsh Upadhyay -Daniel Wagenaar Stefan van der Walt Peter Van Wieren James R. Van Zandt Risto Vanhanen Gregory Vanuxem Ivana Varekova +Daniel Wagenaar Thomas Walter Andreas Weber Olaf Weber
--- a/doc/interpreter/signal.txi +++ b/doc/interpreter/signal.txi @@ -19,18 +19,23 @@ @node Signal Processing @chapter Signal Processing - This chapter describes the signal processing and fast Fourier transform functions available in Octave. Fast Fourier transforms are computed with the @sc{fftw} or @sc{fftpack} libraries depending on how Octave is built. - - - -@DOCSTRING(detrend) @DOCSTRING(fft) +@DOCSTRING(ifft) + +@DOCSTRING(fft2) + +@DOCSTRING(ifft2) + +@DOCSTRING(fftn) + +@DOCSTRING(ifftn) + Octave uses the @sc{fftw} libraries to perform FFT computations. When Octave starts up and initializes the @sc{fftw} libraries, they read a system wide file (on a Unix system, it is typically @file{/etc/fftw/wisdom}) that @@ -45,16 +50,6 @@ @DOCSTRING(fftw) -@DOCSTRING(ifft) - -@DOCSTRING(fft2) - -@DOCSTRING(ifft2) - -@DOCSTRING(fftn) - -@DOCSTRING(ifftn) - @DOCSTRING(fftconv) @DOCSTRING(fftfilt) @@ -71,7 +66,7 @@ @DOCSTRING(unwrap) -@c FIXME -- someone needs to organize these... +@c FIXME: someone needs to organize these ... @DOCSTRING(arch_fit) @@ -87,6 +82,8 @@ @DOCSTRING(blackman) +@DOCSTRING(detrend) + @DOCSTRING(diffpara) @DOCSTRING(durbinlevinson) @@ -107,10 +104,6 @@ @DOCSTRING(periodogram) -@DOCSTRING(rectangle_lw) - -@DOCSTRING(rectangle_sw) - @DOCSTRING(sinetone) @DOCSTRING(sinewave) @@ -125,8 +118,5 @@ @DOCSTRING(synthesis) -@DOCSTRING(triangle_lw) +@DOCSTRING(yulewalker) -@DOCSTRING(triangle_sw) - -@DOCSTRING(yulewalker)
--- a/libgui/qterminal/libqterminal/win32/QWinTerminalImpl.cpp +++ b/libgui/qterminal/libqterminal/win32/QWinTerminalImpl.cpp @@ -96,13 +96,15 @@ static QString translateKey (QKeyEvent *ev) { + QString esc = "\x1b"; QString s; - if (!ev->text ().isEmpty ()) + if (ev->key () == Qt::Key_Delete) + s = esc + "[C\b"; + else if (!ev->text ().isEmpty ()) s = ev->text (); else { - QString esc = "\x1b"; switch (ev->key ()) { @@ -123,21 +125,17 @@ break; case Qt::Key_Home: - s = esc + "[1~"; + s = esc + "[H"; break; case Qt::Key_End: - s = esc + "[4~"; + s = esc + "[F"; break; case Qt::Key_Insert: s = esc + "[2~"; break; - case Qt::Key_Delete: - s = esc + "[3~"; - break; - case Qt::Key_PageUp: s = esc + "[5~"; break; @@ -146,6 +144,10 @@ s = esc + "[6~"; break; + case Qt::Key_Escape: + s = esc; + break; + default: break; }
--- a/libgui/src/octave-gui.cc +++ b/libgui/src/octave-gui.cc @@ -123,6 +123,11 @@ if (term.empty ()) octave_env::putenv ("TERM", "xterm"); +#else + std::string term = octave_env::getenv ("TERM"); + + if (term.empty ()) + octave_env::putenv ("TERM", "cygwin"); #endif // create main window, read settings, and show window
--- a/libinterp/dldfcn/__init_fltk__.cc +++ b/libinterp/dldfcn/__init_fltk__.cc @@ -1392,7 +1392,7 @@ // Determine if we're zooming in or out. const double factor = - (Fl::event_dy () > 0) ? 1.0 + Vwheel_zoom_speed + (Fl::event_dy () > 0) ? 1 / (1.0 - Vwheel_zoom_speed) : 1.0 - Vwheel_zoom_speed; // Get the point we're zooming about.
--- a/libinterp/dldfcn/__magick_read__.cc +++ b/libinterp/dldfcn/__magick_read__.cc @@ -1481,14 +1481,21 @@ return octave_value ("rle"); case Magick::ZipCompression: return octave_value ("deflate"); - case Magick::LZMACompression: - return octave_value ("lzma"); - case Magick::JPEG2000Compression: - return octave_value ("jpeg2000"); - case Magick::JBIG1Compression: - return octave_value ("jbig1"); - case Magick::JBIG2Compression: - return octave_value ("jbig2"); + + // The following are present only in recent versions of GraphicsMagick. + // At the moment the only use of this would be to have imfinfo report + // the compression method. In the future, someone could implement + // the Compression option for imwrite in which case a macro in + // configure.ac will have to check for their presence of this. + // See bug #39913 +// case Magick::LZMACompression: +// return octave_value ("lzma"); +// case Magick::JPEG2000Compression: +// return octave_value ("jpeg2000"); +// case Magick::JBIG1Compression: +// return octave_value ("jbig1"); +// case Magick::JBIG2Compression: +// return octave_value ("jbig2"); default: return octave_value ("undefined"); } @@ -1549,9 +1556,9 @@ } } -// We return a map so this can be used both in imwrite and imfinfo. +// Meant to be shared with both imfinfo and imwrite. static std::map<octave_idx_type, std::string> -disposal_methods () +init_disposal_methods () { // GIF Specifications: // @@ -1578,6 +1585,72 @@ } return methods; } + +static bool +is_valid_exif (const std::string& val) +{ + // Sometimes GM will return the string "unknown" instead of empty + // for an empty value. + return (! val.empty () && val != "unknown"); +} + +static void +fill_exif (octave_scalar_map& map, Magick::Image& img, + const std::string& key) +{ + const std::string attr = img.attribute ("EXIF:" + key); + if (is_valid_exif (attr)) + map.setfield (key, octave_value (attr)); + return; +} + +static void +fill_exif_ints (octave_scalar_map& map, Magick::Image& img, + const std::string& key) +{ + const std::string attr = img.attribute ("EXIF:" + key); + if (is_valid_exif (attr)) + { + // string of the type "float,float,float....." + float number; + ColumnVector values (std::count (attr.begin (), attr.end (), ',') +1); + std::string sub; + std::istringstream sstream (attr); + octave_idx_type n = 0; + while (std::getline (sstream, sub, char (','))) + { + sscanf (sub.c_str (), "%f", &number); + values(n++) = number; + } + map.setfield (key, octave_value (values)); + } + return; +} + +static void +fill_exif_floats (octave_scalar_map& map, Magick::Image& img, + const std::string& key) +{ + const std::string attr = img.attribute ("EXIF:" + key); + if (is_valid_exif (attr)) + { + // string of the type "int/int,int/int,int/int....." + int numerator; + int denominator; + ColumnVector values (std::count (attr.begin (), attr.end (), ',') +1); + std::string sub; + std::istringstream sstream (attr); + octave_idx_type n = 0; + while (std::getline (sstream, sub, ',')) + { + sscanf (sub.c_str (), "%i/%i", &numerator, &denominator); + values(n++) = double (numerator) / double (denominator); + } + map.setfield (key, octave_value (values)); + } + return; +} + #endif DEFUN_DLD (__magick_finfo__, args, , @@ -1609,8 +1682,27 @@ read_file (filename, imvec); if (error_state) return retval; + const octave_idx_type nFrames = imvec.size (); + const std::string format = imvec[0].magick (); - // Matlab has different list of fields for each file format. We don't. + // Here's how this function works. We need to return a struct array, one + // struct for each image in the file (remember, there are image + // that allow for multiple images in the same file). Now, Matlab seems + // to have format specific code so the fields on the struct are different + // for each format. It only has a small subset that is common to all + // of them, the others are undocumented. Because we try to abstract from + // the formats we always return the same list of fields (note that with + // GM we support more than 88 formats. That's way more than Matlab, and + // I don't want to write specific code for each of them). + // + // So what we do is we create an octave_scalar_map, fill it with the + // information for that image, and then insert it into an octave_map. + // Because in the same file, different images may have values for + // different fields, we can't create a field only if there's a value. + // Bad things happen if we merge octave_scalar_maps with different + // fields from the others (suppose for example a TIFF file with 4 images, + // where only the third image has a colormap. + static const char *fields[] = { // These are fields that must always appear for Matlab. @@ -1626,7 +1718,7 @@ // These are format specific or not existent in Matlab. The most // annoying thing is that Matlab may have different names for the - // same thing, in different formats. + // same thing in different formats. "DelayTime", "DisposalMethod", "LoopCount", @@ -1641,29 +1733,33 @@ "ResolutionUnit", "XResolution", "YResolution", + "Software", // sometimes is an Exif tag + "Make", // actually an Exif tag + "Model", // actually an Exif tag + "DateTime", // actually an Exif tag + "ImageDescription", // actually an Exif tag + "Artist", // actually an Exif tag + "Copyright", // actually an Exif tag + "DigitalCamera", + "GPSInfo", + // Notes for the future: GM allows to get many attributes, and even has + // attribute() to obtain arbitrary ones, that may exist in only some + // cases. The following is a list of some methods and into what possible + // Matlab compatible values they may be converted. + // + // colorSpace() -> PhotometricInterpretation + // backgroundColor() -> BackgroundColor + // interlaceType() -> Interlaced, InterlaceType, and PlanarConfiguration + // label() -> Title 0 }; - // Notes for the future: GM allows to get many attributes, and even has - // attribute() to obtain arbitrary ones, that may be set in only some - // cases. The following is a list of some methods and into what possible - // Matlab value they may be converted. - // - // colorSpace() -> PhotometricInterpretation - // backgroundColor() -> BackgroundColor - // interlaceType() -> Interlaced, InterlaceType, and PlanarConfiguration - // label() -> Title - - // Create the right size for the output. - const octave_idx_type nFrames = imvec.size (); + // The one we will return at the end octave_map info (dim_vector (nFrames, 1), string_vector (fields)); - const std::string format (imvec[0].magick ()); - // For each frame in the image (some images contain multiple - // layers, each to be treated like a separate image). So we create - // octave_scalar_map and insert them in the octave_map during the - // loop. Since some fields will never change value, we set the - // template + // Some of the fields in the struct are about file information and will be + // the same for all images in the file. So we create a template, fill in + // those values, and make a copy of the template for each image. octave_scalar_map template_info = (string_vector (fields)); template_info.setfield ("Format", octave_value (format)); @@ -1686,8 +1782,6 @@ return retval; } - std::map<octave_idx_type, std::string> gif_methods = disposal_methods (); - for (octave_idx_type frame = 0; frame < nFrames; frame++) { octave_scalar_map info_frame (template_info); @@ -1738,14 +1832,13 @@ color_type = "undefined"; } } - info_frame.setfield ("ColorType", octave_value (color_type)); - info_frame.setfield ("Colormap", octave_value (cmap)); + info_frame.setfield ("ColorType", octave_value (color_type)); + info_frame.setfield ("Colormap", octave_value (cmap)); } - info_frame.setfield ("Gamma", octave_value (img.gamma ())); { // Not all images have chroma values. In such cases, they'll - // be all zeros. SO rather than send a matrix of zeros, we will + // be all zeros. So rather than send a matrix of zeros, we will // check for that, and send an empty vector instead. RowVector chromaticities (8); double* chroma_fvec = chromaticities.fortran_vec (); @@ -1758,6 +1851,7 @@ info_frame.setfield ("Chromaticities", octave_value (chromaticities)); } + info_frame.setfield ("Gamma", octave_value (img.gamma ())); info_frame.setfield ("XResolution", octave_value (img.xResolution ())); info_frame.setfield ("YResolution", octave_value (img.yResolution ())); info_frame.setfield ("DelayTime", octave_value (img.animationDelay ())); @@ -1765,10 +1859,6 @@ info_frame.setfield ("Quality", octave_value (img.quality ())); info_frame.setfield ("Comment", octave_value (img.comment ())); - info_frame.setfield ("DisposalMethod", - octave_value (format == "GIF"? - gif_methods[img.gifDisposeMethod ()] : "")); - info_frame.setfield ("Compression", magick_to_octave_value (img.compressType ())); info_frame.setfield ("Orientation", @@ -1778,8 +1868,227 @@ info_frame.setfield ("ByteOrder", magick_to_octave_value (img.endian ())); + // It is not possible to know if there's an Exif field so we just + // check for the Exif Version value. If it does exists, then we + // bother about looking for specific fields. + { + Magick::Image& cimg = const_cast<Magick::Image&> (img); + + // These will be in Exif tags but must appear as fields in the + // base struct array, not as another struct in one of its fields. + // This is likely because they belong to the Baseline TIFF specs + // and may appear out of the Exif tag. So first we check if it + // exists outside the Exif tag. + // See Section 4.6.4, table 4, page 28 of Exif specs version 2.3 + // (CIPA DC- 008-Translation- 2010) + static const char *base_exif_str_fields[] = { + "DateTime", + "ImageDescription", + "Make", + "Model", + "Software", + "Artist", + "Copyright", + 0, + }; + static const string_vector base_exif_str (base_exif_str_fields); + static const octave_idx_type n_base_exif_str = base_exif_str.numel (); + for (octave_idx_type field = 0; field < n_base_exif_str; field++) + { + info_frame.setfield (base_exif_str[field], + octave_value (cimg.attribute (base_exif_str[field]))); + fill_exif (info_frame, cimg, base_exif_str[field]); + } + + octave_scalar_map camera; + octave_scalar_map gps; + if (! cimg.attribute ("EXIF:ExifVersion").empty ()) + { + // See Section 4.6.5, table 7 and 8, over pages page 42 to 43 + // of Exif specs version 2.3 (CIPA DC- 008-Translation- 2010) + + // Listed on the Exif specs as being of type ASCII. + static const char *exif_str_fields[] = { + "RelatedSoundFile", + "DateTimeOriginal", + "DateTimeDigitized", + "SubSecTime", + "DateTimeOriginal", + "SubSecTimeOriginal", + "SubSecTimeDigitized", + "ImageUniqueID", + "CameraOwnerName", + "BodySerialNumber", + "LensMake", + "LensModel", + "LensSerialNumber", + "SpectralSensitivity", + // These last two are of type undefined but most likely will + // be strings. Even if they're not GM returns a string anyway. + "UserComment", + "MakerComment", + 0 + }; + static const string_vector exif_str (exif_str_fields); + static const octave_idx_type n_exif_str = exif_str.numel (); + for (octave_idx_type field = 0; field < n_exif_str; field++) + fill_exif (camera, cimg, exif_str[field]); + + // Listed on the Exif specs as being of type SHORT or LONG. + static const char *exif_int_fields[] = { + "ColorSpace", + "ExifImageWidth", // PixelXDimension (CPixelXDimension in Matlab) + "ExifImageHeight", // PixelYDimension (CPixelYDimension in Matlab) + "PhotographicSensitivity", + "StandardOutputSensitivity", + "RecommendedExposureIndex", + "ISOSpeed", + "ISOSpeedLatitudeyyy", + "ISOSpeedLatitudezzz", + "FocalPlaneResolutionUnit", + "FocalLengthIn35mmFilm", + // Listed as SHORT or LONG but with more than 1 count. + "SubjectArea", + "SubjectLocation", + // While the following are an integer, their value have a meaning + // that must be represented as a string for Matlab compatibility. + // For example, a 3 on ExposureProgram, would return + // "Aperture priority" as defined on the Exif specs. + "ExposureProgram", + "SensitivityType", + "MeteringMode", + "LightSource", + "Flash", + "SensingMethod", + "FileSource", + "CustomRendered", + "ExposureMode", + "WhiteBalance", + "SceneCaptureType", + "GainControl", + "Contrast", + "Saturation", + "Sharpness", + "SubjectDistanceRange", + 0 + }; + static const string_vector exif_int (exif_int_fields); + static const octave_idx_type n_exif_int = exif_int.numel (); + for (octave_idx_type field = 0; field < n_exif_int; field++) + fill_exif_ints (camera, cimg, exif_int[field]); + + // Listed as RATIONAL or SRATIONAL + static const char *exif_float_fields[] = { + "Gamma", + "CompressedBitsPerPixel", + "ExposureTime", + "FNumber", + "ShutterSpeedValue", // SRATIONAL + "ApertureValue", + "BrightnessValue", // SRATIONAL + "ExposureBiasValue", // SRATIONAL + "MaxApertureValue", + "SubjectDistance", + "FocalLength", + "FlashEnergy", + "FocalPlaneXResolution", + "FocalPlaneYResolution", + "ExposureIndex", + "DigitalZoomRatio", + // Listed as RATIONAL or SRATIONAL with more than 1 count. + "LensSpecification", + 0 + }; + static const string_vector exif_float (exif_float_fields); + static const octave_idx_type n_exif_float = exif_float.numel (); + for (octave_idx_type field = 0; field < n_exif_float; field++) + fill_exif_floats (camera, cimg, exif_float[field]); + + // Inside a Exif field, it is possible that there is also a + // GPS field. This is not the same as ExifVersion but seems + // to be how we have to check for it. + if (cimg.attribute ("EXIF:GPSInfo") != "unknown") + { + // The story here is the same as with Exif. + // See Section 4.6.6, table 15 on page 68 of Exif specs + // version 2.3 (CIPA DC- 008-Translation- 2010) + + static const char *gps_str_fields[] = { + "GPSLatitudeRef", + "GPSLongitudeRef", + "GPSAltitudeRef", + "GPSSatellites", + "GPSStatus", + "GPSMeasureMode", + "GPSSpeedRef", + "GPSTrackRef", + "GPSImgDirectionRef", + "GPSMapDatum", + "GPSDestLatitudeRef", + "GPSDestLongitudeRef", + "GPSDestBearingRef", + "GPSDestDistanceRef", + "GPSDateStamp", + 0 + }; + static const string_vector gps_str (gps_str_fields); + static const octave_idx_type n_gps_str = gps_str.numel (); + for (octave_idx_type field = 0; field < n_gps_str; field++) + fill_exif (gps, cimg, gps_str[field]); + + static const char *gps_int_fields[] = { + "GPSDifferential", + 0 + }; + static const string_vector gps_int (gps_int_fields); + static const octave_idx_type n_gps_int = gps_int.numel (); + for (octave_idx_type field = 0; field < n_gps_int; field++) + fill_exif_ints (gps, cimg, gps_int[field]); + + static const char *gps_float_fields[] = { + "GPSAltitude", + "GPSDOP", + "GPSSpeed", + "GPSTrack", + "GPSImgDirection", + "GPSDestBearing", + "GPSDestDistance", + "GPSHPositioningError", + // Listed as RATIONAL or SRATIONAL with more than 1 count. + "GPSLatitude", + "GPSLongitude", + "GPSTimeStamp", + "GPSDestLatitude", + "GPSDestLongitude", + 0 + }; + static const string_vector gps_float (gps_float_fields); + static const octave_idx_type n_gps_float = gps_float.numel (); + for (octave_idx_type field = 0; field < n_gps_float; field++) + fill_exif_floats (gps, cimg, gps_float[field]); + + } + } + info_frame.setfield ("DigitalCamera", octave_value (camera)); + info_frame.setfield ("GPSInfo", octave_value (gps)); + } + info.fast_elem_insert (frame, info_frame); } + + if (format == "GIF") + { + static std::map<octave_idx_type, std::string> disposal_methods + = init_disposal_methods (); + string_vector methods (nFrames); + for (octave_idx_type frame = 0; frame < nFrames; frame++) + methods[frame] = disposal_methods[imvec[frame].gifDisposeMethod ()]; + info.setfield ("DisposalMethod", Cell (methods)); + } + else + info.setfield ("DisposalMethod", + Cell (dim_vector (nFrames, 1), octave_value (""))); + retval = octave_value (info); #endif return retval;
--- a/scripts/help/__unimplemented__.m +++ b/scripts/help/__unimplemented__.m @@ -44,6 +44,10 @@ txt = ["Basic video file support is provided in the video package. ", ... "See @url{http://octave.sf.net/video/}."]; + case "exifread" + txt = ["exifread is deprecated. " ... + "The functionality is available in the imfinfo function."]; + case "gsvd" txt = ["gsvd is not currently part of core Octave. ", ... "See the linear-algebra package at ", ... @@ -207,7 +211,6 @@ "dynamicprops", "echodemo", "evalc", - "exifread", "export2wsdlg", "figurepalette", "filebrowser",
--- a/scripts/image/imfinfo.m +++ b/scripts/image/imfinfo.m @@ -109,6 +109,37 @@ ## The orientation of the image with respect to the rows and columns. Value ## is an integer between 1 and 8 as defined in the TIFF 6 specifications, and ## for @sc{Matlab} compatibility. +## +## @item Software +## Name and version of the software or firmware of the camera or image input +## device used to generate the image. +## +## @item Make +## The manufacturer of the recording equipment. This is the manufacture of the +## DSC, scanner, video digitizer or other equipment that generated the image. +## +## @item Model +## The model name or model number of the recording equipment as mentioned +## on the field @qcode{"Make"}. +## +## @item DateTime +## The date and time of image creation as defined by the Exif standard, i.e, +## it is the date and time the file was changed. +## +## @item ImageDescription +## The title of the image as defined by the Exif standard. +## +## @item Artist +## Name of the camera owner, photographer or image creator. +## +## @item Copyright +## Copyright notice of the person or organization claiming rights to the image. +## +## @item DigitalCamera +## A struct with information retrieved from the Exif tag. +## +## @item GPSInfo +## A struct with geotagging information retrieved from the Exif tag. ## @end table ## ## @seealso{imread, imwrite, imshow, imformats}
--- a/scripts/image/imread.m +++ b/scripts/image/imread.m @@ -88,7 +88,7 @@ ## Author: Stefan van der Walt <stefan@sun.ac.za> ## Author: Andy Adler -function varargout = imread (varargin) +function [img, varargout] = imread (varargin) if (nargin < 1) print_usage (); elseif (! ischar (varargin{1})) @@ -104,7 +104,7 @@ filename{2} = varargin{2}; endif - [varargout{1:nargout}] = imageIO (@__imread__, "read", filename, varargin{:}); + [img, varargout{2:nargout}] = imageIO (@__imread__, "read", filename, varargin{:}); endfunction
--- a/scripts/specfun/expint.m +++ b/scripts/specfun/expint.m @@ -20,24 +20,54 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} expint (@var{x}) -## Compute the exponential integral, +## Compute the exponential integral: ## @tex ## $$ -## E_1 (x) = \int_x^\infty {e^{-t} \over t} dt. +## {\rm E_1} (x) = \int_x^\infty {e^{-t} \over t} dt ## $$ ## @end tex ## @ifnottex ## ## @example ## @group -## infinity -## / -## expint (x) = | exp (-t)/t dt -## / -## x +## infinity +## / +## E_1 (x) = | exp (-t)/t dt +## / +## x ## @end group ## @end example +## @end ifnottex ## +## Note: For compatibility, this functions uses the @sc{matlab} definition +## of the exponential integral. Most other sources refer to this particular +## value as @math{E_1 (x)}, and the exponential integral is +## @tex +## $$ +## {\rm Ei} (x) = - \int_{-x}^\infty {e^{-t} \over t} dt. +## $$ +## @end tex +## @ifnottex +## +## @example +## @group +## infinity +## / +## Ei (x) = - | exp (-t)/t dt +## / +## -x +## @end group +## @end example +## @end ifnottex +## +## The two definititions are related, for positive real values of @var{x}, by +## @tex +## $ +## E_1 (-x) = -{\rm Ei} (x) - i\pi. +## $ +## @end tex +## @ifnottex +## @w{@code{E_1 (-x) = -Ei (x) - i*pi}}. ## @end ifnottex ## @end deftypefn @@ -47,98 +77,85 @@ print_usage (); endif - y = expint_E1 (x); - -endfunction + y = x; # Copy over all values, including NaNs -## -*- texinfo -*- -## @deftypefn {Function File} {@var{y} =} expint_E1 (@var{x}) -## Compute the exponential integral, -## @verbatim -## infinity -## / -## expint(x) = | exp(-t)/t dt -## / -## x -## @end verbatim -## @end deftypefn - -function y = expint_E1 (x) + if (isreal (x)) + idx = (x >= 0); + y(idx) = -expint_Ei (-x(idx)); - if (nargin != 1) - print_usage (); - endif - - y = x; - - idx = (imag (x) > 0 & imag (x) != 0); - y(idx) = -expint_Ei (-y(idx)) - i.*pi; + idx = (x < 0); + y(idx) = -expint_Ei (-x(idx)) - i*pi; + else + idx = (imag (x) > 0); + y(idx) = -expint_Ei (-x(idx)) - i*pi; - idx = (imag (x) < 0 & imag (x) != 0); - y(idx) = -expint_Ei (-y(idx)) + i.*pi; + idx = (imag (x) < 0); + y(idx) = -expint_Ei (-x(idx)) + i*pi; - idx = (real (x) >= 0 & imag (x) == 0); - y(idx) = -expint_Ei (-y(idx)); + isreal_idx = (imag (x) == 0); + idx = (isreal_idx & real (x) >= 0); + y(idx) = -expint_Ei (-x(idx)); - idx = (real (x) < 0 & imag (x) == 0); - y(idx) = -expint_Ei (-y(idx)) - i.*pi; + idx = (isreal_idx & real (x) < 0); + y(idx) = -expint_Ei (-x(idx)) - i*pi; + endif endfunction ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} expint_Ei (@var{x}) -## Compute the exponential integral, +## Compute the exponential integral: ## @verbatim -## infinity -## / -## expint_Ei(x) = - | exp(t)/t dt -## / -## -x +## infinity +## / +## expint_Ei (x) = - | exp(-t)/t dt +## / +## -x ## @end verbatim ## @end deftypefn function y = expint_Ei (x) - if (nargin != 1) - print_usage (); - endif - y = zeros (size (x)); F = @(x) exp (-x)./x; - s = prod (size (x)); - for t = 1:s; - if (x(t) < 0 && imag (x(t)) == 0) - y(t) = -quad (F, -x(t), Inf); + for t = 1:numel (x) + xt = x(t); + if (xt < 0 && imag (xt) == 0) + ## Direct integration for most real inputs + y(t) = -quad (F, -xt, Inf, [0, 1e-10]); + elseif (xt > 2 && imag (xt) == 0) + persistent Ei_2 = 4.954234356001890; + y(t) = Ei_2 - quad (F, -xt, -2); + elseif (abs (xt) < 10) + ## Series Expansion for real (range [0,2]) or complex inputs (r < 10) + k = 1; + do + term = xt^k / (k*factorial (k)); + y(t) += term; + until (abs (term) < eps (abs (y(t))) / 2 || k++ >= 100) + y(t) = 0.57721566490153286 + log (xt) + y(t); else - if (abs (x(t)) > 2 && imag (x(t)) == 0) - y(t) = expint_Ei (2) - quad (F, -x(t), -2); + ## FIXME: This expansion is accurate to only 1e-13 at the beginning + ## near 10+i, although it becomes more accurate as the magnitude + ## of xt grows. + if (imag (xt) <= 0) + persistent a1 = 4.03640; + persistent a2 = 1.15198; + persistent b1 = 5.03637; + persistent b2 = 4.19160; + y(t) = -(xt^2 - a1*xt + a2) ... + / ((xt^2 - b1*xt + b2) * (-xt) * exp (-xt)) ... + - i*pi; else - if (abs (x(t)) >= 10) - if (imag (x(t)) <= 0) - a1 = 4.03640; - a2 = 1.15198; - b1 = 5.03637; - b2 = 4.19160; - y(t) = -(x(t).^2 - a1.*x(t) + a2) ... - ./ ((x(t).^2 - b1.*x(t) + b2) .* (-x(t)) .* exp (-x(t))) ... - - i.*pi; - else - y(t) = conj (expint_Ei (conj (x(t)))); - endif; - ## Serie Expansion - else - for k = 1:100; - y(t) = y(t) + x(t).^k ./ (k.*factorial (k)); - endfor - y(t) = 0.577215664901532860606512090082402431 + log (x(t)) + y(t); - endif - endif + y(t) = conj (expint_Ei (conj (xt))); + endif; endif endfor endfunction -%% Test against A&S Table 5.1 + +## Test against A&S Table 5.1 %!test %! x = [5:5:50]'/100; %! gamma = 0.5772156649; @@ -198,7 +215,52 @@ %! y = expint (x); %! assert (y, y_exp, 1e-9); -%% Test input validation +## Series expansion (-2 < x < 0) +## Expected values from Mathematica +%!test +%! x = [-0.1; -0.5; -1; -1.5; -2]; +%! y_exp = [ 1.6228128139692767 - i*pi; +%! -0.45421990486317358 - i*pi; +%! -1.8951178163559368 - i*pi; +%! -3.3012854491297978 - i*pi; +%! -4.9542343560018902 - i*pi]; +%! y = expint (x); +%! assert (y, y_exp, eps (real (y_exp))); + +## (x < -2, x real) +%!test +%! x = [-2.5; -3; -10;-15; -25]; +%! y_exp = [-7.0737658945786007 - i*pi; +%! -9.9338325706254165 - i*pi; +%! -2492.2289762418777 - i*pi; +%! -234955.85249076830 - i*pi; +%! -3.0059509065255486e9 - i*pi]; +%! y = expint (x); +%! assert (y, y_exp, 8*eps (real (y_exp))); + +## Complex values +%!test +%! x = [i; -1-i; 10-i; 10+i]; +%! y_exp = [-0.33740392290096813 - i*0.62471325642771360; +%! -1.7646259855638540 + i*0.75382280207927082; +%! 1.90746381979783120e-6 + i*3.67354374003294739e-6; +%! 1.90746381979783120e-6 - i*3.67354374003294739e-6]; +%! y = expint (x); +%! assert (y, y_exp, 1e-12); + +## Exceptional values (-Inf, Inf, NaN, 0, 0.37250741078) +%!test +%! x = [-Inf; Inf; NaN; 0; -0.3725074107813668]; +%! y_exp = [-Inf - i*pi; +%! -Inf; # should be 0; +%! NaN; +%! Inf; +%! 0 - i*pi]; +%! y = expint (x); +%! assert (y, y_exp, 5*eps); + +## Test input validation %!error expint () %!error expint (1,2) +