evolvotron-0.8.3/0000755000175000017500000000000015230700302012373 5ustar karlkarlevolvotron-0.8.3/tools/0000755000175000017500000000000015230700302013533 5ustar karlkarlevolvotron-0.8.3/tools/license/0000755000175000017500000000000015230700302015155 5ustar karlkarlevolvotron-0.8.3/tools/license/stripheader0000755000175000017500000000043415230700302017416 0ustar karlkarl#!/bin/bash # Used this to remove old header style before using headache for f in `find ../.. -name '*.cpp' -o -name '*.h'` ; do cat $f | awk '{if (go) print $0;if ($0=="*********************************************************************/") go=1;}' > $f.tmp ; mv $f.tmp $f ; done evolvotron-0.8.3/tools/license/config0000644000175000017500000000017415230700302016347 0ustar karlkarl# C/CPP source ".*\\.[ch]" -> frame open:"/*" line:"*" close:"*/" | ".*\\.cpp" -> frame open:"/*" line:"*" close:"*/" evolvotron-0.8.3/tools/license/boilerplate0000644000175000017500000000122715230700302017404 0ustar karlkarlCopyright 2012 Tim Day This file is part of Evolvotron Evolvotron 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 3 of the License, or (at your option) any later version. Evolvotron 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 Evolvotron. If not, see . evolvotron-0.8.3/tools/license/apply0000755000175000017500000000021015230700302016221 0ustar karlkarl#!/bin/bash # Run this here to update license on all files headache -c config -h boilerplate `find ../.. -name '*.cpp' -o -name '*.h'` evolvotron-0.8.3/text_to_markup.py0000755000175000017500000001464215230700302016024 0ustar karlkarl#!/usr/bin/env python2 # Convert Tim-style text to html or qml # # The Rules: # - Lines with all upper case words to h2 or h3 capwords depending on next line underlining (first to h1/title though) # (must be 3 chars or more) # (todo: relax to not all upper case... no need to capwords if not) # - Other text to p, blank lines break a p # - Lines beginning with "- " (NB space) to ul/li (bulleted) # - Lines beginning with "-?" (no space) to ul/li (?) with
at end of first line # - Words delim to xxx # "$ " at start of line indicates one line of code (add
too) import sys import string import re def line_of_dashes(n): r="" for i in xrange(n): r+="-" return r def line_of_equals(n): r="" for i in xrange(n): r+="=" return r class TextToMarkup: def __init__(self,m,s): self.startup=1 # True self.scope_p=0 # False self.scope_ul=0 # False self.scope_li=0 # False self.done_title=0 # False self.skipnextline=0 # False self.mode=m self.stringify=s def dispose(self,l): if self.stringify: self.output.write("\"") # Actually, they should all have been "-ed anyway for c in l: if c=="\"": self.output.write("\\\"") else: self.output.write(c) self.output.write("\\n\"\n") else: self.output.write(l+"\n") def process_word(self,w): r="" if len(w)<3: # Special case allows "<" or "<>" without turning italic for i in xrange(len(w)): if w[i]=="<": r+="<" elif w[i]==">": r+=">" else: r+=w[i] else: for i in xrange(len(w)): if w[i]=="<": r+="" elif w[i]==">": r+="" elif w[i]=='"': r+=""" elif w[i]=="&": r+="&" else: r+=w[i] return r def process_paragraph_text(self,txt): is_code=0 # False specialbreak=0 # False r=" " if txt[0]=="-": if txt[1]==" ": txt=txt[2:] else: specialbreak=1 # True if self.scope_ul and self.scope_li: r+="" self.scope_li=0 # False if not self.scope_ul: r+="") self.scope_ul=0 # False self.dispose("

") self.scope_p=0 # False elif len(self.currline): self.dispose("

") self.dispose(self.process_paragraph_text(self.currline)) self.scope_p=1 # True else: self.dispose("") if self.mode=="html": self.dispose("") self.dispose("") ######################################### if __name__=='__main__': mode=None stringify=0 # False for i in xrange(1,len(sys.argv)): if sys.argv[i]=="-qml": mode="qml" if sys.argv[i]=="-html": mode="html" elif sys.argv[i]=="-s": stringify=1 # True t2m=TextToMarkup(mode,stringify) # "html" and "qml" are alternatives. Should be stringify option. t2m.process(sys.stdin,sys.stdout) evolvotron-0.8.3/text_to_markup.b0000755000175000017500000001107415230700302015611 0ustar karlkarl#!/usr/bin/boron /* Convert Tim-style text to html or qml The Rules: - Lines with all upper case words to h2 or h3 capwords depending on next line underlining (first to h1/title though) (must be 3 chars or more) (todo: relax to not all upper case... no need to capwords if not) - Other text to p, blank lines break a p - Lines beginning with "- " (NB space) to ul/li (bulleted) - Lines beginning with "-?" (no space) to ul/li (?) with
at end of first line - Words delim to xxx "$ " at start of line indicates one line of code (add
too) */ line_of_dashes: func [n] [ slice "----------------------------------------" n ] line_of_equals: func [n] [ slice "========================================" n ] emit: :print emit-stringify: func [text] [ prin '"' ; Actually, they should all have been quoted anyway. prin construct text ['"' {\"}] print {\n"} ] process_word: func [w] [ either lt? size? w 3 [ ; Special case allows "<" or "<>" without turning italic construct w ['<' "<" '>' ">"] ][ construct w ['<' "" '>' "" '"' """ '&' "&"] ] ] scope_p: scope_ul: scope_li: none process_paragraph_text: func [txt /extern scope_ul scope_li] [ is_code: specialbreak: false r: copy " " switch first txt [ '-' [ either eq? ' ' second txt [ txt: skip txt 2 ][ specialbreak: true ] if all [scope_ul scope_li] [ append r "" scope_li: false ] ifn scope_ul [ append r "

" scope_ul: false ] emit "

" scope_p: false ] ] not empty? currline [ emit "

" emit process_paragraph_text currline scope_p: true ] true [ emit "" ] ] if skipnextline [ skipnextline: false nextline: read-line ] currline: nextline nextline: read-line ] if eq? mode 'html [ emit "" emit "" ] evolvotron-0.8.3/sourceforge/0000755000175000017500000000000015230700302014716 5ustar karlkarlevolvotron-0.8.3/sourceforge/README.md0000644000175000017500000000157615230700302016206 0ustar karlkarlNotes ===== Source tarball -------------- Source releases are in .tar.gz files and unpack to an unversioned evolvotron/ directory. - Note that the configure file provided is *not* autotools based, but is a script invoking qmake. - See the evolvotron/README file build re build dependencies and setup of QTDIR environment Debian-world packages --------------------- For some (not all) releases, prebuilt .deb packages for a variety of systems are created to sanity-check packaging feasibility (currently using the "yada" tool). If a release folder on SourceForge's file hosting doesn't include .debs, look back through the immediately preceeding releases for one. These .debs provided as they may be useful to some, but most users should prefer their distributions' "offical" packaging where one exists. [See also.](http://www.bottlenose.demon.co.uk/share/evolvotron/download.htm) evolvotron-0.8.3/project.b0000644000175000017500000000150215230700302014202 0ustar karlkarlsources_cpp: func [path /local it] [ files: read path remove-each it files [ne? %.cpp skip tail it -4] sources_from path files ] application: does [ include_from [%libfunction %libevolvotron] libs_from %. [%evolvotron %function] unix [libs %boost_program_options] win32 [libs %boost_program_options-x64] qt [widgets] ] lib %function [ include_from %libfunction sources_cpp %libfunction ] lib %evolvotron [ qt/no-link [widgets] include_from [%libfunction %libevolvotron] sources_cpp %libevolvotron ] exe %evolv [ application sources [%evolvotron/icons.qrc] sources_cpp %evolvotron win32 [sources [%dist/app.rc]] ] exe %evolv_mutate [ application sources_cpp %evolvotron_mutate ] exe %evolv_render [ application sources_cpp %evolvotron_render ] evolvotron-0.8.3/mktgz0000755000175000017500000000040515230700302013454 0ustar karlkarl#!/bin/bash # Execute this to package up evolvotron as a .tar.gz VER=`./VERSION` APP_DIR=$PWD # Clone into a temporary directory to get a clean project. cd /tmp git clone $APP_DIR evolvotron-$VER tar czf evolvotron-$VER.tar.gz --exclude .git evolvotron-$VER evolvotron-0.8.3/mkdeb0000755000175000017500000000677315230700302013420 0ustar karlkarl#!/bin/bash # Before using this you probably need to install # sudo pbuilder yada devscripts lintian cdebootstrap # and maybe dpkg-sig. Also: # set up for sudo # set up pbuilder's /etc/pbuilderrc (maybe no attention needed these days) # sudo pbuilder create --distribution squeeze # and/or update with # sudo pbuilder update # Expect a lot of warnings re LOGNAME - see Debian bug Bug#275118 # TODO: DEBEMAIL VER=`./VERSION` TARBALL=evolvotron-${VER}.tar.gz if [ ! -s ${TARBALL} ] ; then echo "Could't find ${TARBALL}" ; exit ; fi export DISTRIBUTION=`lsb_release -s -c` echo "*** Will package ${TARBALL} for distribution \"${DISTRIBUTION}\"" echo -n "*** Starting in 5 seconds..." for t in 5 4 3 2 1 ; do sleep 1 ; echo -n "." ; done PROJECT=`echo $TARBALL | sed 's/-.*//'` TARBALLORIG="${PROJECT}_${VER}.orig.tar.gz" REV="1${DISTRIBUTION}1" WORKDIR=pkg_${VER}-${REV} rm -r -f ${WORKDIR} mkdir ${WORKDIR} cd ${WORKDIR} cp ../${TARBALL} ${TARBALLORIG} tar xvfz ${TARBALLORIG} mv ${PROJECT} ${PROJECT}-${VER} cd ${PROJECT}-${VER} sed -i "s/${VER}/${VER}-${REV}/g" VERSION mkdir debian dch --create --package evolvotron --distribution stable --newversion ${VER}-${REV} "Created by mkdeb script" cat << EOF > debian/packages Source: evolvotron Section: graphics Priority: extra Maintainer: Tim Day Standards-Version: 3.6.1 Upstream-Source: Home-Page: Description: Interactive evolutionary texture generator Copyright: GPL Copyright 2009 Tim Day Build-Depends: qt4-qmake,qt4-dev-tools,libqt4-dev,libqt4-xml,libboost-dev,libboost-program-options-dev,yada Build: sh export QTDIR=/usr/share/qt4 # Note: yada install deals with DEB_BUILD_OPTIONS 'nostrip' if [ "${DEB_BUILD_OPTIONS#*noopt}" != "$DEB_BUILD_OPTIONS" ]; then ./configure "CONFIG -= release" "CONFIG += debug" else ./configure # No noticeable advantage in overriding qt optimisation options fi make Clean: sh make distclean || make clean || true Package: evolvotron Architecture: any Depends: [] Suggests: gimp Description: Interactive evolutionary texture generator A "generative art" application to evolve images/textures/patterns through an iterative process of random mutation and user-selection driven evolution. If you like lava lamps, and never got bored with the Mandelbrot Set, this could be the software for you. Install: sh yada install -bin evolvotron/evolvotron yada install -bin evolvotron_mutate/evolvotron_mutate yada install -bin evolvotron_render/evolvotron_render yada install -bin evolvotron/evolvotron yada install -doc evolvotron.html yada install -doc BUGS TODO NEWS USAGE yada install -man man/man1/evolvotron.1 yada install -man man/man1/evolvotron_mutate.1 yada install -man man/man1/evolvotron_render.1 Menu: ?package(evolvotron): needs="X11" section="Applications/Graphics" title="Evolvotron" hints="Bitmap" command="/usr/bin/evolvotron" longtitle="Evolutionary art program" EOF yada rebuild cd .. dpkg-source -b ${PROJECT}-${VER} ${TARBALLORIG} # Alternative but inferior approach is apparently to do # dpkg-buildpackage -rfakeroot mkdir result echo "Building package" sudo pbuilder build --allow-untrusted --buildresult ./result ${PROJECT}_${VER}-${REV}.dsc sudo chown ${USER}:${USER} result/* RESULT=`(cd .. ; find ${WORKDIR} -name '*.deb')` echo "Results: ${RESULT}" echo "Don't forget to lintian ${RESULT}" echo 'Also dpkg-sig --sign builder -k $DPKGSIG_KEYID any .deb files' evolvotron-0.8.3/man/0000755000175000017500000000000015230700302013146 5ustar karlkarlevolvotron-0.8.3/man/man1/0000755000175000017500000000000015230700302014002 5ustar karlkarlevolvotron-0.8.3/man/man1/evolvotron_render.10000644000175000017500000000417715230700302017651 0ustar karlkarl.TH EVOLVOTRON_RENDER 1 "16 Oct 2009" "www.timday.com" "Evolvotron" .SH NAME evolvotron_render \- Render an evolvotron function tree to an image. .SH SYNOPSIS evolvotron_render [options] .I imagefile.[png|ppm] .SH DESCRIPTION .B evolvotron_render reads an evolvotron image function from its standard input and renders it to an image in the file specified (suffix determines type, defaults to ppm if not recognised). Image functions can be obtained by saving them from the evolvotron application, or using evolvotron_mutate. See the evolvotron manual (accessible from the evolvotron application's Help menu) for more information on image functions. .SH COMMAND-LINE OPTIONS .TP 0.5i .B \-f, \-\-frames .I frames Generates multi-frame animations. .fnnnnnn is inserted into the specified filename (before the filetype suffix, if any). You can use this on functions which weren't evolved in animation mode, but there's no guarantee they have any interesting time/z variation. .TP 0.5i .B \-h, \-\-help Display a summary of command-line options and exit. .TP 0.5i .B \-j, \-\-jitter Enable sample jittering. .TP 0.5i .B \-m, \-\-multisample .I multisample Enables antialiased rendering. This specifies the size of the sub-pixel sampling grid, so 1 provides the default one-sample-per-pixel behaviour, while 4 provides 16 samples per pixel on a 4x4 grid. Unlike the main evolvotron application, there is no upper limit, but of course rendering time increases as the square of this number. .TP 0.5i .B \-o, \-\-output .I imagefile.[ppm|png] This option is an alternative to specifying the output filename as a positional argument. .TP 0.5i .B \-s, \-\-size .I widthxheight Specify resolution of output image. Defaults to 512x512. .TP 0.5i .B \-v, \-\-verbose Verbose mode; useful for monitoring progress of large renders. .SH EXAMPLES evolvotron_mutate \-g | evolvotron_render \-s 1024x1024 function.ppm .SH AUTHOR .B evolvotron_render was written by Tim Day (www.timday.com) and is released under the conditions of the GNU General Public License. See the file LICENSE supplied with the source code for details. .SH SEE ALSO evolvotron(1), evolvotron_mutate(1) evolvotron-0.8.3/man/man1/evolvotron_mutate.10000644000175000017500000000322115230700302017656 0ustar karlkarl.TH EVOLVOTRON_MUTATE 1 "16 Oct 2009" "www.timday.com" "Evolvotron" .SH NAME evolvotron_mutate \- Render an evolvotron function tree to an image. .SH SYNOPSIS evolvotron_mutate < function_in.xml > function_out.xml evolvotron_mutate \-g > function_out.xml .SH DESCRIPTION .B evolvotron_mutate either mutates an existing image function read from standard input, or (with the \-g option) creates a new image function. In either case the output image function is written to standard output. The mutation parameters and function weightings are the same as used by .B evolvotron in its default reset state. See the evolvotron user manual (accessible from the evolvotron application's Help menu) for more information on image functions. .SH COMMANDLINE OPTIONS .TP 0.5i .B \-g, \-\-genesis Specifies that no function should be read from standard input. The output function is created at random. .TP 0.5i .B \-h, \-\-help Display information on command line arguments and exit. .TP 0.5i .B \-l, \-\-linear Created functions (if they are rendered as animations) will sweep z linearly (rather than sinusoidally). .TP 0.5i .B \-p, \-\-spheremap Created functions will be tagged as spheremaps. .TP 0.5i .B \-v, \-\-verbose Enables some additional logging to standard error. .SH EXAMPLES evolvotron_mutate \-g | tee function0.xml | evolvotron_render function0.ppm evolvtron_mutate < function0.xml > function1.xml .SH AUTHOR .B evolvotron_mutate was written by Tim Day (www.timday.com) and is released under the conditions of the GNU General Public License. See the file LICENSE supplied with the source code for details. .SH SEE ALSO evolvotron(1), evolvotron_render(1) evolvotron-0.8.3/man/man1/evolvotron.10000644000175000017500000001277115230700302016311 0ustar karlkarl.TH EVOLVOTRON 1 "16 Oct 2009" "www.timday.com" "Evolvotron" .SH NAME evolvotron \- Creates generative art by an interactive evolutionary process. .SH SYNOPSIS evolvotron [Qt options] [options] .SH DESCRIPTION .B evolvotron is interactive "generative art" software to evolve images/textures/patterns through an iterative process of random mutation and user-selection driven evolution. Basically it displays a grid of random images; you click on one you like and the rest of the grid is refilled with variants of the one you picked. This man page describes only the command line options. A more complete manual fully describing usage via the application's GUI is accessible from the application's "Help" menu once it is running. .SH GENERAL OPTIONS .TP 0.5i .B \-a, \-\-autocool Enable autocooling by default. .TP 0.5i .B \-F, \-\-fullscreen Start in "fullscreen" mode (window manager permitting). [Press "Esc" key to revert to normal windowed mode]. .TP 0.5i .B \-g, \-\-grid .I colsxrows Number of columns in image display grid (defaults to 5x6). .TP 0.5i .B \-h, \-\-help Display a summary of command-line options and exit. .TP 0.5i .B \-j, \-\-jitter Enable sample jittering. .TP 0.5i .B \-m, \-\-multisample .I multisample Enables antialiased rendering. Valid values are 1,2,3,4. This specifies the size of the sub-pixel sampling grid, so 1 provides the default one-sample-per-pixel behaviour, while 4 provides 16 samples per pixel on a 4x4 grid. .TP .B \-M, \-\-menuhide Start with menu and status bars suppressed. [Press "Esc" key to display them]. .TP 0.5i .B \-p, \-spheremap Create spheremaps instead of planar textures. NB The middle-mouse adjustments will not behave as expected in this mode. .TP 0.5i .B \-S, \-\-startup .I filename Specify a function file to be loaded on startup. This option can be used multiple times, and any positional arguments will also be interpreted as such. Loaded functions are placed on the grid from left to right, top to bottom; if multiple functions in excess of what is needed to fill the grid cells are provided, the extras will be ignored. If the grid is not fully filled with startup functions, the remaining cells are filled at random normally. Note that resetting the application will reload the specified function files again. Also note that using this option multiple times has the potential to generate a lot of loading error dialogs if e.g the path to all the files is wrong. .TP 0.5i .B \-U, \-\-shuffle Use in conjunction with \-S / \-\-startup options, randomly shuffles the order the specified startup images are displayed in. A fresh shuffle will be also be used when the application is reset. .SH ANIMATION OPTIONS .TP 0.5i .B \-f, \-\-frames .I frames Number of frames to animate (defaults to 1 i.e no animaton) .TP 0.5i .B \-l, \-\-linear Vary z linearly with time rather than sinusoidally over animation period. .TP 0.5i .B \-s, \-\-fps .I framerate Specify rate at which animations are displayed (as an integer number of frames per second). Defaults to 8. .SH POWER-USER / DEBUG OPTIONS .TP 0.5i .B \-D, \-\-debug Debug mode. Currently simply sets function weightings so virtually all function nodes are FunctionNoiseOneChannel. This is really only useful to developers in conjunction with the \-F/\-u options. .TP 0.5i .B \-E, \-\-enlarement-threadpool Use a separate thread pool for computing enlargements. Using this option ensures computation of enlargements continue to make some progress even while the main grid is being actively worked on. However, this will be at the expense of main grid rendering performance. Without this option, enlargements' final high-resolution renderings are invariably lower priority than computation for images in the main grid. See also the \-N option to control the priority of threads in this pool. .TP 0.5i .B \-n, \-\-nice .I niceness Niceness of compute threads relative to the main application thread (defaults to 4). .TP 0.5i .B \-N, \-\-Nice .I niceness Niceness (relative to the main application thread) of compute threads dealing with enlargements (defaults to 8). Only effective in conjunction with a separate enlargement threadool (\-\-E option). .TP 0.5i .I QtOptions The Qt GUI system recognizes an number of additional options (for example, standard X11 things like \-geometry x; consult the Qt documentation for more information). Note that these don't use the Gnu "double minus" option style used for evolvotron options. .TP 0.5i .B \-t, \-\-threads .I threads Number of compute threads in a thread pool (defaults to number of CPUs) .TP 0.5i .B \-u, \-\-unwrapped Use with the \-F option to stop the specified function from being wrapped by a random colouring and spatial transform node. .TP 0.5i .B \-v, \-\-verbose Verbose mode. Probably most useful for getting a list of supported function names for use with the \-\-F option. .TP 0.5i .B \-x, \-\-favourite .I functionname Force a specific function type to be used at the top level of all new image function trees (wrapped by random colour and spatial transforms, unless the \-\-unwrapped option is also specified). This can also be controlled from the "Favourite" dialog. .SH EXAMPLES evolvotron \-F FunctionSpiralLinear evolvotron \-F FunctionKaleidoscope \-u .SH AUTHOR .B evolvotron was written by Tim Day (www.timday.com) and is released under the conditions of the GNU General Public License. For further details see the application's "About" dialog (accessible from the "Help" menu), or the file LICENSE supplied with the source code. .SH SEE ALSO evolvotron_mutate(1), evolvotron_render(1) evolvotron-0.8.3/main.pro0000644000175000017500000000030715230700302014041 0ustar karlkarlTEMPLATE = subdirs # See https://wiki.qt.io/SUBDIRS_-_handling_dependencies re parallelisation. CONFIG += ordered SUBDIRS = libfunction libevolvotron evolvotron evolvotron_render evolvotron_mutate evolvotron-0.8.3/libfunction/0000755000175000017500000000000015230700302014707 5ustar karlkarlevolvotron-0.8.3/libfunction/xyz.h0000644000175000017500000001604315230700302015716 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class XYZ. */ #ifndef _xyz_h_ #define _xyz_h_ #include "useful.h" #include "xy.h" class Random01; //! Class to hold vectors in 3D cartesian co-ordinates. /*! Direct access to the x,y,z members is not permitted. */ class XYZ { protected: real _rep[3]; public: //@{ //! Accessor. real x() const { return _rep[0]; } real y() const { return _rep[1]; } real z() const { return _rep[2]; } const XY xy() const { return XY(x(),y()); } void x(real v) { _rep[0]=v; } void y(real v) { _rep[1]=v; } void z(real v) { _rep[2]=v; } //@} //! Null constructor. /*! NB The components are not cleared to zero. */ XYZ() {} //! Initialise from an XY and a z component. XYZ(const XY& p,real vz) { _rep[0]=p.x(); _rep[1]=p.y(); _rep[2]=vz; } //! Initialise from separate components. XYZ(real vx,real vy,real vz) { _rep[0]=vx; _rep[1]=vy; _rep[2]=vz; } //! Trivial destructor. ~XYZ() {} //! Subtract a vector void operator-=(const XYZ& v) { _rep[0]-=v._rep[0]; _rep[1]-=v._rep[1]; _rep[2]-=v._rep[2]; } //! Add a vector void operator+=(const XYZ& v) { _rep[0]+=v._rep[0]; _rep[1]+=v._rep[1]; _rep[2]+=v._rep[2]; } //! Multiply by scalar void operator*=(real k) { _rep[0]*=k; _rep[1]*=k; _rep[2]*=k; } //! Divide by scalar. /*! Implemented assuming one divide and three multiplies is faster than three divides. */ void operator/=(real k) { const real ik(1.0/k); (*this)*=ik; } //! Assignment. void assign(const XYZ& v) { x(v.x()); y(v.y()); z(v.z()); } //! Negation. const XYZ operator-() const { return XYZ(-x(),-y(),-z()); } //! Return the square of the magnitude. real magnitude2() const { return x()*x()+y()*y()+z()*z(); } //! Return the magnitude. real magnitude() const { return sqrt(magnitude2()); } //! Returns sum of x, y and z components. real sum_of_components() const { return x()+y()+z(); } //! Return the vector normalised. const XYZ normalised() const; //! Normalise this vector. void normalise(); //! Returns true if an origin centred cuboid with this vectors semi-axes contains the argument. bool origin_centred_rect_contains(const XYZ& p) const { return (-x()<=p.x() && p.x()<=x() && -y()<=p.y() && p.y()<=y() && -z()<=p.z() && p.z()<=z()); } //! Write the vector. std::ostream& write(std::ostream&) const; //! Helper for common case of creating an instance filled with a common value. static const XYZ fill(real v) { return XYZ(v,v,v); } }; //! Cross product. inline const XYZ operator*(const XYZ& a,const XYZ& b) { return XYZ( a.y()*b.z()-a.z()*b.y(), a.z()*b.x()-a.x()*b.z(), a.x()*b.y()-a.y()*b.x() ); } //! Dot product. /*! Perhaps a curious choice of operator but it works for me. */ inline real operator%(const XYZ& a,const XYZ& b) { return a.x()*b.x()+a.y()*b.y()+a.z()*b.z(); } //! Vector addition. inline const XYZ operator+(const XYZ& a,const XYZ& b) { return XYZ(a.x()+b.x(),a.y()+b.y(),a.z()+b.z()); } //! Vector subtraction. inline const XYZ operator-(const XYZ& a,const XYZ& b) { return XYZ(a.x()-b.x(),a.y()-b.y(),a.z()-b.z()); } //! Multiplication by scalar. inline const XYZ operator*(real k,const XYZ& v) { XYZ ret(v); ret*=k; return ret; } //! Multiplication by scalar. inline const XYZ operator*(const XYZ& v,real k) { XYZ ret(v); ret*=k; return ret; } //! Division by scalar. inline const XYZ operator/(const XYZ& v,real k) { return v*(1.0/k); } //! Modulus all components by 1.0 inline const XYZ modulusf(const XYZ& p) { return XYZ ( modulusf(p.x(),1.0), modulusf(p.y(),1.0), modulusf(p.z(),1.0) ); } //! Componentwise modulus inline const XYZ modulusf(const XYZ& p,const XYZ& q) { return XYZ ( modulusf(p.x(),q.x()), modulusf(p.y(),q.y()), modulusf(p.z(),q.z()) ); } /*! If magnitude is zero we return zero vector. */ inline const XYZ XYZ::normalised() const { const real m=magnitude(); return (m==0.0 ? XYZ(0.0,0.0,0.0) : (*this)/m); } inline void XYZ::normalise() { (*this)=normalised(); } //! Stream output operator. /*! Calls write(). */ inline std::ostream& operator<<(std::ostream& out,const XYZ& v) { return v.write(out); } //! Generates a random point in the cube bounded by (0,0,0) and (1.0,1.0,1.0) class RandomXYZInUnitCube : public XYZ { public: //! Constructor. RandomXYZInUnitCube(Random01&); }; //! Generates random points in a recnangular box centred on the origin class RandomXYZInBox : public XYZ { public: //! Constructor. RandomXYZInBox(Random01& rng,const XYZ& bounds); }; //! Generates a random point in or on a unit-radius sphere centred on the origin. class RandomXYZInSphere : public XYZ { public: //! Constructor. RandomXYZInSphere(Random01& rng,real radius); }; //! Generates a random point on the surface of a unit-radius sphere class RandomXYZSphereNormal : public XYZ { public: //! Constructor. RandomXYZSphereNormal(Random01& rng); }; //! Generates a random point in or on an origin-centred ellipsoid with semi-axes of the specified size. class RandomXYZInEllipsoid : public XYZ { public: //! Constructor. RandomXYZInEllipsoid(Random01& rng,const XYZ& axes); }; //! Generates a random point in or on a disc in the XY plane of the specified radius. class RandomXYZInXYDisc : public XYZ { public: //! Constructor. RandomXYZInXYDisc(Random01& rng,real radius); }; #endif evolvotron-0.8.3/libfunction/xyz.cpp0000644000175000017500000000570215230700302016251 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation for class XYZ. */ #include "xyz.h" #include "random.h" #include "xy.h" /*! Outputs whitespace-separated co-ordinates. */ std::ostream& XYZ::write(std::ostream& out) const { return out << x() << " " << y() << " " << z(); } RandomXYZInUnitCube::RandomXYZInUnitCube(Random01& rng) :XYZ() { x(rng()); y(rng()); z(rng()); } RandomXYZInBox::RandomXYZInBox(Random01& rng,const XYZ& bounds) :XYZ() { x(-bounds.x()+2.0*bounds.x()*rng()); y(-bounds.y()+2.0*bounds.y()*rng()); z(-bounds.z()+2.0*bounds.z()*rng()); } RandomXYZInSphere::RandomXYZInSphere(Random01& rng,real radius) :XYZ(0.0,0.0,0.0) { if (radius!=0.0) { do { x(2.0*rng()-1.0); y(2.0*rng()-1.0); z(2.0*rng()-1.0); } while (magnitude2()>1.0); (*this)*=radius; } } RandomXYZSphereNormal::RandomXYZSphereNormal(Random01& rng) :XYZ(0.0,0.0,0.0) { real m2; do { assign(RandomXYZInSphere(rng,1.0)); m2=magnitude2(); } while (m2==0.0); (*this)/=sqrt(m2); } /*! Must handle case of individual axes being zero. */ RandomXYZInEllipsoid::RandomXYZInEllipsoid(Random01& rng,const XYZ& axes) :XYZ() { do { assign(RandomXYZInBox(rng,axes)); } while ( (axes.x()==0.0 ? 0.0 : sqr(x()/axes.x())) +(axes.y()==0.0 ? 0.0 : sqr(y()/axes.y())) +(axes.z()==0.0 ? 0.0 : sqr(z()/axes.z())) >1.0 ); } RandomXYZInXYDisc::RandomXYZInXYDisc(Random01& rng,real radius) :XYZ(0.0,0.0,0.0) { if (radius!=0.0) { do { x(2.0*rng()-1.0); y(2.0*rng()-1.0); } while (magnitude2()>1.0); (*this)*=radius; } } evolvotron-0.8.3/libfunction/xy.h0000644000175000017500000001136415230700302015525 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class XY. */ #ifndef _xy_h_ #define _xy_h_ #include "useful.h" //! Class to hold vectors in 2D cartesian co-ordinates. /*! Direct access to the x,y members is not permitted. */ class XY { protected: real _rep[2]; public: //@{ //! Accessor. real x() const { return _rep[0]; } real y() const { return _rep[1]; } void x(real v) { _rep[0]=v; } void y(real v) { _rep[1]=v; } //@} //! Null constructor. /*! NB The components are not cleared to zero. */ XY() {} //! Initialise from separate components. XY(real vx,real vy) { _rep[0]=vx; _rep[1]=vy; } //! Trivial destructor. ~XY() {} //! Subtract a vector void operator-=(const XY& v) { _rep[0]-=v._rep[0]; _rep[1]-=v._rep[1]; } //! Add a vector void operator+=(const XY& v) { _rep[0]+=v._rep[0]; _rep[1]+=v._rep[1]; } //! Multiply by scalar void operator*=(real k) { _rep[0]*=k; _rep[1]*=k; } //! Divide by scalar. /*! Implemented assuming one divide and two multiplies is faster than two divides. */ void operator/=(real k) { const real ik(1.0/k); (*this)*=ik; } //! Assignment. void assign(const XY& v) { x(v.x()); y(v.y()); } //! Negation. const XY operator-() const { return XY(-x(),-y()); } //! Return the square of the magnitude. real magnitude2() const { return x()*x()+y()*y(); } //! Return the magnitude. real magnitude() const { return sqrt(magnitude2()); } //! Returns sum of x and y components. real sum_of_components() const { return x()+y(); } //! Return the vector normalised. const XY normalised() const; //! Normalise this vector. void normalise(); //! Returns true if an origin centred rectangle with this vectors' semi-axes contains the argument. bool origin_centred_rect_contains(const XY& p) const { return (-x()<=p.x() && p.x()<=x() && -y()<=p.y() && p.y()<=y()); } //! Write the vector. std::ostream& write(std::ostream&) const; //! Helper for common case of creating an instance filled with a common value. static const XY fill(real v) { return XY(v,v); } }; //! Dot product. /*! Perhaps a curious choice of operator but it works for me. */ inline real operator%(const XY& a,const XY& b) { return a.x()*b.x()+a.y()*b.y(); } //! Vector addition. inline const XY operator+(const XY& a,const XY& b) { return XY(a.x()+b.x(),a.y()+b.y()); } //! Vector subtraction. inline const XY operator-(const XY& a,const XY& b) { return XY(a.x()-b.x(),a.y()-b.y()); } //! Multiplication by scalar. inline const XY operator*(real k,const XY& v) { XY ret(v); ret*=k; return ret; } //! Multiplication by scalar. inline const XY operator*(const XY& v,real k) { XY ret(v); ret*=k; return ret; } //! Division by scalar. inline const XY operator/(const XY& v,real k) { return v*(1.0/k); } /*! If magnitude is zero we return zero vector. */ inline const XY XY::normalised() const { const real m=magnitude(); return (m==0.0 ? XY(0.0,0.0) : (*this)/m); } inline void XY::normalise() { (*this)=normalised(); } //! Stream output operator. /*! Calls write(). */ inline std::ostream& operator<<(std::ostream& out,const XY& v) { return v.write(out); } #endif evolvotron-0.8.3/libfunction/xy.cpp0000644000175000017500000000307315230700302016056 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation for class XY. */ #include "xy.h" /*! Outputs whitespace-separated co-ordinates. */ std::ostream& XY::write(std::ostream& out) const { return out << x() << " " << y(); } evolvotron-0.8.3/libfunction/useful.h0000644000175000017500000001170615230700302016370 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief File containing all the author's favourite little helpers. */ #ifndef _useful_h_ #define _useful_h_ #include #include #include #define _USE_MATH_DEFINES #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //! Convenience typedef. typedef unsigned int uint; //! Convenience typedef. typedef unsigned short ushort; //! Convenience typedef. typedef unsigned char uchar; //! float turns out to not be sufficient for some noise-amplifying ops (e.g gradient type things) so choice of double is deliberate. typedef double real; //! Maximum of 2 arguments. template inline const T maximum(T a,T b) {return (a>b ? a : b);} //! Maximum of 3 arguments. template inline const T maximum(T a,T b,T c) {return maximum(a,maximum(b,c));} //! Maximum of 4 arguments. template inline const T maximum(T a,T b,T c,T d) {return maximum(maximum(a,b),maximum(c,d));} //! Minimum of 2 arguments template inline const T minimum(T a,T b) {return (a inline const T minimum(T a,T b,T c) {return minimum(a,minimum(b,c));} //! Minimum of 4 arguments template inline const T minimum(T a,T b,T c,T d) {return minimum(minimum(a,b),minimum(c,d));} //! Returns argument multiplied by itself. template inline const T sqr(T a) {return a*a;} //! Returns result of clamping first argument to range specified by second and third. template inline const T clamped(T v,T lo,T hi) {return (vhi ? hi : v));} //! Clamps v to lie between lo and hi template inline void clamp(T& v,T lo,T hi) {v=(vhi ? hi : v));} //! Exchanges values of a and b. template inline void exchange(T& a,T& b) {const T x(a);a=b;b=x;} //! Print fatal error message and exit. extern void fatal_error(const char*); //! Print fatal error message and exit. inline void fatal_error(const std::string& s) { fatal_error(s.c_str()); } //! Call this for fatal internal error type messages. extern void fatal_internal_error(const char* src_file,uint src_line); //! Called if constraint macro fails. extern void constraint_violation(const char* test,const char* src_file,uint src_line); //! Use this to provide assert-like behaviour which is never disabled. #define constraint(TEST) {if (!TEST) {constraint_violation(#TEST,__FILE__,__LINE__);}} //! Sane modulus function always returning a number in the range [0,y) inline real modulusf(real x,real y) { if (y<0.0) y=-y; real r=fmod(x,y); if (r<0.0) r+=y; return r; } //! Sane modulus function always returning a number in the range [0,y-1] inline uint modulusi(int x,int y) { if (y<0) y=-y; int r=x%y; if (r<0) r+=y; assert(r>=0); return r; } //! Triangle function: like modulus, but starts ramping down instead of discontinuity at y. /*! Always has slope 1. Setting y=1 ensures x in [0,1] */ inline real trianglef(real x,real y) { if (y<0.0) y=-y; if (x<0.0) x=-x; real r=fmod(x,2.0*y); if (r>y) r=2.0*y-r; return r; } //! Use this to divert clog to supress verbose logging. Needs longer life than scope of main(). extern std::ofstream sink_ostream; #endif evolvotron-0.8.3/libfunction/useful.cpp0000644000175000017500000000403615230700302016721 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ #include "useful.h" /*! \file \brief Code for useful little helper functions.. */ void fatal_error(const char* msg) { std::cerr << "\n*** Fatal error: " << msg << " ***\n"; exit(1); } void fatal_internal_error(const char* src_file,uint src_line) { std::cerr << "\n*** Fatal internal error in " << src_file << " at line " << src_line << " ***\n"; exit(1); } void constraint_violation(const char* test,const char* src_file,uint src_line) { std::cerr << "\n*** Constraint \"" << test << "\" violated in file" << src_file << " at line " << src_line << " ***\n"; exit(1); } std::ofstream sink_ostream("/dev/null"); evolvotron-0.8.3/libfunction/update_register_all_functions0000755000175000017500000000166615230700302022754 0ustar karlkarl#!/bin/bash rm -f register_all_functions.cpp cat <> register_all_functions.cpp /* AUTO GENERATED FILE. DO NOT EDIT */ /* Should be updated by update_register_all_functions script when new functions are added */ #include "register_all_functions.h" #include "function_boilerplate.h" EOF HEADERS=`grep -l FUNCTION_BEGIN *.h | sed 's/function_boilerplate.h//'` for f in $HEADERS ; do sed -f stripcomments.sed "$f" \ | grep FUNCTION_BEGIN \ | sed 's/FUNCTION_BEGIN(//' \ | sed 's/,.*//' \ | awk '{printf("REGISTER_DCL(%s);\n",$0);}' \ >> register_all_functions.cpp done cat <> register_all_functions.cpp void register_all_functions(FunctionRegistry& r) { EOF for f in $HEADERS ; do sed -f stripcomments.sed "$f" \ | grep FUNCTION_BEGIN \ | sed 's/FUNCTION_BEGIN(//' \ | sed 's/,.*//' \ | awk '{printf(" register_%s(r);\n",$0);}' \ >> register_all_functions.cpp done cat <> register_all_functions.cpp } EOF evolvotron-0.8.3/libfunction/transform.h0000644000175000017500000001236315230700302017100 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class Transform. */ #ifndef _transform_h_ #define _transform_h_ #include "useful.h" #include "xyz.h" //! Class representing 3d linear transforms. /*! Not much functionality currently because is used mainly to pass info around for warp functionality */ class Transform { public: //! Default constructor. NB Doesn't set up identity or anything. Transform(); //! Copy constructor. Transform(const Transform&); //! Constructor specifying column vectors. Transform(const XYZ& t,const XYZ& x,const XYZ& y,const XYZ& z); //! Constructor specifying column-wise elements. Transform(const std::vector& v,uint starting_element=0); //! virtual destructor in case of extension virtual ~Transform(); //@{ //! Accessor const XYZ& translate() const { return _translate; } const XYZ& basis_x() const { return _basis_x; } const XYZ& basis_y() const { return _basis_y; } const XYZ& basis_z() const { return _basis_z; } void translate(const XYZ &t) { _translate=t; } void basis_x(const XYZ &x) { _basis_x=x; } void basis_y(const XYZ &y) { _basis_y=y; } void basis_z(const XYZ &z) { _basis_z=z; } //@} //! Get column-wise element values as a vector const std::vector get_columns() const; //! Transform a point const XYZ transformed(const XYZ& p) const; //! Transform a point with no translation const XYZ transformed_no_translate(const XYZ& p) const; //! Concatenate transforms Transform& concatenate_on_right(const Transform& t); //! Concatenate transforms Transform& concatenate_on_left(const Transform& t); protected: //@{ //! Translation component (column vector in matrix). XYZ _translate; XYZ _basis_x; XYZ _basis_y; XYZ _basis_z; }; inline const XYZ operator*(const Transform& t,const XYZ& p) { return t.basis_x()*p.x() +t.basis_y()*p.y() +t.basis_z()*p.z() +t.translate(); } inline std::ostream& operator<<(std::ostream& out,const Transform& t) { return out << t.translate() << ";" << t.basis_x() << "," << t.basis_y() << "," << t.basis_z(); } class TransformIdentity : public Transform { public: TransformIdentity() { translate(XYZ(0.0,0.0,0.0)); basis_x(XYZ(1.0,0.0,0.0)); basis_y(XYZ(0.0,1.0,0.0)); basis_z(XYZ(0.0,0.0,1.0)); } }; class TransformTranslate : public Transform { public: TransformTranslate(const XYZ& t) { translate(t); basis_x(XYZ(1.0,0.0,0.0)); basis_y(XYZ(0.0,1.0,0.0)); basis_z(XYZ(0.0,0.0,1.0)); } }; class TransformScale : public Transform { public: TransformScale(const XYZ& s) { translate(XYZ(0.0,0.0,0.0)); basis_x(XYZ(s.x(),0.0,0.0)); basis_y(XYZ(0.0,s.y(),0.0)); basis_z(XYZ(0.0,0.0,s.z())); } TransformScale(real s) { translate(XYZ(0.0,0.0,0.0)); basis_x(XYZ(s,0.0,0.0)); basis_y(XYZ(0.0,s,0.0)); basis_z(XYZ(0.0,0.0,s)); } }; class TransformRotateX : public Transform { public: TransformRotateX(real a) { const real sa=sin(a); const real ca=cos(a); translate(XYZ(0.0,0.0,0.0)); basis_x(XYZ(1.0,0.0,0.0)); basis_y(XYZ(0.0, ca , sa )); basis_z(XYZ(0.0,-sa , ca )); } }; class TransformRotateY : public Transform { public: TransformRotateY(real a) { const real sa=sin(a); const real ca=cos(a); translate(XYZ(0.0,0.0,0.0)); basis_x(XYZ( ca ,0.0,-sa )); basis_y(XYZ(0.0,1.0,0.0)); basis_z(XYZ( sa ,0.0, ca )); } }; class TransformRotateZ : public Transform { public: TransformRotateZ(real a) { const real sa=sin(a); const real ca=cos(a); translate(XYZ(0.0,0.0,0.0)); basis_x(XYZ( ca , sa ,0.0)); basis_y(XYZ(-sa , ca ,0.0)); basis_z(XYZ(0.0,0.0,1.0)); } }; #endif evolvotron-0.8.3/libfunction/transform.cpp0000644000175000017500000000667415230700302017443 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation for class Transform. */ #include "transform.h" Transform::Transform() {} Transform::Transform(const Transform& t) :_translate(t.translate()) ,_basis_x(t.basis_x()) ,_basis_y(t.basis_y()) ,_basis_z(t.basis_z()) {} Transform::Transform(const XYZ& t,const XYZ& x,const XYZ& y,const XYZ& z) :_translate(t) ,_basis_x(x) ,_basis_y(y) ,_basis_z(z) {} Transform::Transform(const std::vector& v,uint s) { _translate.x(v[s+ 0]);_translate.y(v[s+ 1]);_translate.z(v[s+ 2]); _basis_x.x( v[s+ 3]);_basis_x.y( v[s+ 4]);_basis_x.z( v[s+ 5]); _basis_y.x( v[s+ 6]);_basis_y.y( v[s+ 7]);_basis_y.z( v[s+ 8]); _basis_z.x( v[s+ 9]);_basis_z.y( v[s+10]);_basis_z.z( v[s+11]); } Transform::~Transform() {} const std::vector Transform::get_columns() const { std::vector ret(12); ret[ 0]=_translate.x();ret[ 1]=_translate.y();ret[ 2]=_translate.z(); ret[ 3]=_basis_x.x() ;ret[ 4]=_basis_x.y() ;ret[ 5]=_basis_x.z(); ret[ 6]=_basis_y.x() ;ret[ 7]=_basis_y.y() ;ret[ 8]=_basis_y.z(); ret[ 9]=_basis_z.x() ;ret[10]=_basis_z.y() ;ret[11]=_basis_z.z(); return ret; } const XYZ Transform::transformed(const XYZ& p) const { return _translate+_basis_x*p.x()+_basis_y*p.y()+_basis_z*p.z(); } const XYZ Transform::transformed_no_translate(const XYZ& p) const { return _basis_x*p.x()+_basis_y*p.y()+_basis_z*p.z(); } Transform& Transform::concatenate_on_right(const Transform& t) { const XYZ bx(transformed_no_translate(t.basis_x())); const XYZ by(transformed_no_translate(t.basis_y())); const XYZ bz(transformed_no_translate(t.basis_z())); const XYZ tr(transformed(t.translate())); translate(tr); basis_x(bx); basis_y(by); basis_z(bz); return *this; } Transform& Transform::concatenate_on_left(const Transform& t) { const XYZ bx(t.transformed_no_translate(basis_x())); const XYZ by(t.transformed_no_translate(basis_y())); const XYZ bz(t.transformed_no_translate(basis_z())); const XYZ tr(t.transformed(translate())); translate(tr); basis_x(bx); basis_y(by); basis_z(bz); return *this; } evolvotron-0.8.3/libfunction/stripcomments.sed0000644000175000017500000000006415230700302020313 0ustar karlkarl:loop s-\(.*\)/\*.*\*/-\1- t loop /\/\*/!b N b loop evolvotron-0.8.3/libfunction/register_all_functions.h0000644000175000017500000000336315230700302021631 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief File declaring function to register all functions. NB The corresponding register_all_functions.cpp is AUTO GENERATED by update_register_all_functions script. */ #ifndef _libevolvotron_register_all_functions_h_ #define _libevolvotron_register_all_functions_h_ #include "useful.h" class FunctionRegistry; extern void register_all_functions(FunctionRegistry&); #endif evolvotron-0.8.3/libfunction/register_all_functions.cpp0000644000175000017500000002213615230700302022163 0ustar karlkarl/* AUTO GENERATED FILE. DO NOT EDIT */ /* Should be updated by update_register_all_functions script when new functions are added */ #include "register_all_functions.h" #include "function_boilerplate.h" REGISTER_DCL(FunctionComposePair); REGISTER_DCL(FunctionComposeTriple); REGISTER_DCL(FunctionConstant); REGISTER_DCL(FunctionIdentity); REGISTER_DCL(FunctionPostTransform); REGISTER_DCL(FunctionPreTransform); REGISTER_DCL(FunctionAdd); REGISTER_DCL(FunctionMultiply); REGISTER_DCL(FunctionDivide); REGISTER_DCL(FunctionMax); REGISTER_DCL(FunctionMin); REGISTER_DCL(FunctionModulus); REGISTER_DCL(FunctionExp); REGISTER_DCL(FunctionSin); REGISTER_DCL(FunctionCos); REGISTER_DCL(FunctionChooseStrip); REGISTER_DCL(FunctionChooseStripBlend); REGISTER_DCL(FunctionChooseSphere); REGISTER_DCL(FunctionChooseRect); REGISTER_DCL(FunctionChooseFrom2InCubeMesh); REGISTER_DCL(FunctionChooseFrom3InCubeMesh); REGISTER_DCL(FunctionChooseFrom2InSquareGrid); REGISTER_DCL(FunctionChooseFrom3InSquareGrid); REGISTER_DCL(FunctionChooseFrom2InTriangleGrid); REGISTER_DCL(FunctionChooseFrom3InTriangleGrid); REGISTER_DCL(FunctionChooseFrom3InDiamondGrid); REGISTER_DCL(FunctionChooseFrom3InHexagonGrid); REGISTER_DCL(FunctionChooseFrom2InBorderedHexagonGrid); REGISTER_DCL(FunctionFilter2D); REGISTER_DCL(FunctionFilter3D); REGISTER_DCL(FunctionAverageSamples); REGISTER_DCL(FunctionStreak); REGISTER_DCL(FunctionAverageRing); REGISTER_DCL(FunctionFilterRing); REGISTER_DCL(FunctionConvolveSamples); REGISTER_DCL(FunctionAccumulateOctaves); REGISTER_DCL(FunctionFriezeGroupHopFreeZ); REGISTER_DCL(FunctionFriezeGroupHopClampZ); REGISTER_DCL(FunctionFriezeGroupHopBlendClampZ); REGISTER_DCL(FunctionFriezeGroupHopBlendFreeZ); REGISTER_DCL(FunctionFriezeGroupJumpFreeZ); REGISTER_DCL(FunctionFriezeGroupJumpClampZ); REGISTER_DCL(FunctionFriezeGroupJumpBlendClampZ); REGISTER_DCL(FunctionFriezeGroupJumpBlendFreeZ); REGISTER_DCL(FunctionFriezeGroupSidleFreeZ); REGISTER_DCL(FunctionFriezeGroupSidleClampZ); REGISTER_DCL(FunctionFriezeGroupSpinhopFreeZ); REGISTER_DCL(FunctionFriezeGroupSpinhopClampZ); REGISTER_DCL(FunctionFriezeGroupSpinhopBlendClampZ); REGISTER_DCL(FunctionFriezeGroupSpinhopBlendFreeZ); REGISTER_DCL(FunctionFriezeGroupSpinjumpFreeZ); REGISTER_DCL(FunctionFriezeGroupSpinjumpClampZ); REGISTER_DCL(FunctionFriezeGroupSpinsidleFreeZ); REGISTER_DCL(FunctionFriezeGroupSpinsidleClampZ); REGISTER_DCL(FunctionFriezeGroupStepFreeZ); REGISTER_DCL(FunctionFriezeGroupStepClampZ); REGISTER_DCL(FunctionCross); REGISTER_DCL(FunctionGeometricInversion); REGISTER_DCL(FunctionReflect); REGISTER_DCL(FunctionDerivative); REGISTER_DCL(FunctionDerivativeGeneralised); REGISTER_DCL(FunctionGradient); REGISTER_DCL(FunctionGradientGeneralised); REGISTER_DCL(FunctionDivergence); REGISTER_DCL(FunctionCurl); REGISTER_DCL(FunctionScalarLaplacian); REGISTER_DCL(FunctionMandelbrotChoose); REGISTER_DCL(FunctionMandelbrotContour); REGISTER_DCL(FunctionJuliaChoose); REGISTER_DCL(FunctionJuliaContour); REGISTER_DCL(FunctionJuliabrotChoose); REGISTER_DCL(FunctionJuliabrotContour); REGISTER_DCL(FunctionKaleidoscope); REGISTER_DCL(FunctionKaleidoscopeZRotate); REGISTER_DCL(FunctionKaleidoscopeTwist); REGISTER_DCL(FunctionWindmill); REGISTER_DCL(FunctionWindmillZRotate); REGISTER_DCL(FunctionWindmillTwist); REGISTER_DCL(FunctionMagnitudes); REGISTER_DCL(FunctionMagnitude); REGISTER_DCL(FunctionCone); REGISTER_DCL(FunctionExpCone); REGISTER_DCL(FunctionSeparateZ); REGISTER_DCL(FunctionIterate); REGISTER_DCL(FunctionNoiseOneChannel); REGISTER_DCL(FunctionMultiscaleNoiseOneChannel); REGISTER_DCL(FunctionNoiseThreeChannel); REGISTER_DCL(FunctionMultiscaleNoiseThreeChannel); REGISTER_DCL(FunctionPixelize); REGISTER_DCL(FunctionVoxelize); REGISTER_DCL(FunctionPixelizeHex); REGISTER_DCL(FunctionOrthoSphereShaded); REGISTER_DCL(FunctionOrthoSphereShadedBumpMapped); REGISTER_DCL(FunctionOrthoSphereReflect); REGISTER_DCL(FunctionOrthoSphereReflectBumpMapped); REGISTER_DCL(FunctionShadow); REGISTER_DCL(FunctionShadowGeneralised); REGISTER_DCL(FunctionCartesianToSpherical); REGISTER_DCL(FunctionSphericalToCartesian); REGISTER_DCL(FunctionEvaluateInSpherical); REGISTER_DCL(FunctionSpiralLinear); REGISTER_DCL(FunctionSpiralLogarithmic); REGISTER_DCL(FunctionTartanSelectFree); REGISTER_DCL(FunctionTartanSelect); REGISTER_DCL(FunctionTartanSelectRepeat); REGISTER_DCL(FunctionTartanMixFree); REGISTER_DCL(FunctionTartanMixRepeat); REGISTER_DCL(FunctionIsotropicScale); REGISTER_DCL(FunctionPreTransformGeneralised); REGISTER_DCL(FunctionPostTransformGeneralised); REGISTER_DCL(FunctionTransformQuadratic); REGISTER_DCL(FunctionRotate); REGISTER_DCL(FunctionTop); REGISTER_DCL(FunctionTransformGeneralised); REGISTER_DCL(FunctionTransform); void register_all_functions(FunctionRegistry& r) { register_FunctionComposePair(r); register_FunctionComposeTriple(r); register_FunctionConstant(r); register_FunctionIdentity(r); register_FunctionPostTransform(r); register_FunctionPreTransform(r); register_FunctionAdd(r); register_FunctionMultiply(r); register_FunctionDivide(r); register_FunctionMax(r); register_FunctionMin(r); register_FunctionModulus(r); register_FunctionExp(r); register_FunctionSin(r); register_FunctionCos(r); register_FunctionChooseStrip(r); register_FunctionChooseStripBlend(r); register_FunctionChooseSphere(r); register_FunctionChooseRect(r); register_FunctionChooseFrom2InCubeMesh(r); register_FunctionChooseFrom3InCubeMesh(r); register_FunctionChooseFrom2InSquareGrid(r); register_FunctionChooseFrom3InSquareGrid(r); register_FunctionChooseFrom2InTriangleGrid(r); register_FunctionChooseFrom3InTriangleGrid(r); register_FunctionChooseFrom3InDiamondGrid(r); register_FunctionChooseFrom3InHexagonGrid(r); register_FunctionChooseFrom2InBorderedHexagonGrid(r); register_FunctionFilter2D(r); register_FunctionFilter3D(r); register_FunctionAverageSamples(r); register_FunctionStreak(r); register_FunctionAverageRing(r); register_FunctionFilterRing(r); register_FunctionConvolveSamples(r); register_FunctionAccumulateOctaves(r); register_FunctionFriezeGroupHopFreeZ(r); register_FunctionFriezeGroupHopClampZ(r); register_FunctionFriezeGroupHopBlendClampZ(r); register_FunctionFriezeGroupHopBlendFreeZ(r); register_FunctionFriezeGroupJumpFreeZ(r); register_FunctionFriezeGroupJumpClampZ(r); register_FunctionFriezeGroupJumpBlendClampZ(r); register_FunctionFriezeGroupJumpBlendFreeZ(r); register_FunctionFriezeGroupSidleFreeZ(r); register_FunctionFriezeGroupSidleClampZ(r); register_FunctionFriezeGroupSpinhopFreeZ(r); register_FunctionFriezeGroupSpinhopClampZ(r); register_FunctionFriezeGroupSpinhopBlendClampZ(r); register_FunctionFriezeGroupSpinhopBlendFreeZ(r); register_FunctionFriezeGroupSpinjumpFreeZ(r); register_FunctionFriezeGroupSpinjumpClampZ(r); register_FunctionFriezeGroupSpinsidleFreeZ(r); register_FunctionFriezeGroupSpinsidleClampZ(r); register_FunctionFriezeGroupStepFreeZ(r); register_FunctionFriezeGroupStepClampZ(r); register_FunctionCross(r); register_FunctionGeometricInversion(r); register_FunctionReflect(r); register_FunctionDerivative(r); register_FunctionDerivativeGeneralised(r); register_FunctionGradient(r); register_FunctionGradientGeneralised(r); register_FunctionDivergence(r); register_FunctionCurl(r); register_FunctionScalarLaplacian(r); register_FunctionMandelbrotChoose(r); register_FunctionMandelbrotContour(r); register_FunctionJuliaChoose(r); register_FunctionJuliaContour(r); register_FunctionJuliabrotChoose(r); register_FunctionJuliabrotContour(r); register_FunctionKaleidoscope(r); register_FunctionKaleidoscopeZRotate(r); register_FunctionKaleidoscopeTwist(r); register_FunctionWindmill(r); register_FunctionWindmillZRotate(r); register_FunctionWindmillTwist(r); register_FunctionMagnitudes(r); register_FunctionMagnitude(r); register_FunctionCone(r); register_FunctionExpCone(r); register_FunctionSeparateZ(r); register_FunctionIterate(r); register_FunctionNoiseOneChannel(r); register_FunctionMultiscaleNoiseOneChannel(r); register_FunctionNoiseThreeChannel(r); register_FunctionMultiscaleNoiseThreeChannel(r); register_FunctionPixelize(r); register_FunctionVoxelize(r); register_FunctionPixelizeHex(r); register_FunctionOrthoSphereShaded(r); register_FunctionOrthoSphereShadedBumpMapped(r); register_FunctionOrthoSphereReflect(r); register_FunctionOrthoSphereReflectBumpMapped(r); register_FunctionShadow(r); register_FunctionShadowGeneralised(r); register_FunctionCartesianToSpherical(r); register_FunctionSphericalToCartesian(r); register_FunctionEvaluateInSpherical(r); register_FunctionSpiralLinear(r); register_FunctionSpiralLogarithmic(r); register_FunctionTartanSelectFree(r); register_FunctionTartanSelect(r); register_FunctionTartanSelectRepeat(r); register_FunctionTartanMixFree(r); register_FunctionTartanMixRepeat(r); register_FunctionIsotropicScale(r); register_FunctionPreTransformGeneralised(r); register_FunctionPostTransformGeneralised(r); register_FunctionTransformQuadratic(r); register_FunctionRotate(r); register_FunctionTop(r); register_FunctionTransformGeneralised(r); register_FunctionTransform(r); } evolvotron-0.8.3/libfunction/random.h0000644000175000017500000000656115230700302016350 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces for class Random and derived classes. */ #ifndef _random_h_ #define _random_h_ #include "useful.h" //! Abstract base class for random number generation class Random { public: //! Constructor (nothing to do in base class) Random() {} //! Trivial destructor. virtual ~Random() {} //! Return a random number. /*! \warning Returns double instead of real because suspect NegExp can return Inf otherwise. */ virtual double operator()() =0; }; //! Generates random numbers in the range [0,1). class Random01 : public Random { public: //! Constructor Random01(uint seed); //! Trivial destructor virtual ~Random01(); //! Return next number in sequence. virtual double operator()(); private: //! Base generator boost::mt19937 _rng; //! Distribution boost::uniform_real<> _dist; //! Actual generator boost::variate_generator > _gen; }; //! Return negative-exponentially distributed random numbers. class RandomNegExp : public Random { protected: //! Underlying generator. Random01 _generator; //! Mean value of distribution. double _mean; public: //! Construct generator of numbers with mean value m. RandomNegExp(uint seed,double m) :_generator(seed) ,_mean(m) {} //! Trivial destructor. virtual ~RandomNegExp() {} //! Return next number in sequence. virtual double operator()() { return -_mean*log(1.0-_generator()); } }; template void random_shuffle(boost::ptr_vector& v,Random01& r01) { boost::ptr_vector nv; while (!v.empty()) { const uint n=static_cast(r01()*v.size()); nv.transfer(nv.end(),v.begin()+n,v); } v.transfer(v.end(),nv.begin(),nv.end(),nv); } template void random_shuffle(std::vector& v,Random01& r01) { size_t a, b; for (auto i = v.size(); i > 1; --i) { a = i - 1; b = static_cast(r01() * i); if (a != b) std::swap(v[a], v[b]); } } #endif evolvotron-0.8.3/libfunction/random.cpp0000644000175000017500000000317715230700302016703 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of class Random and derived classes. */ #include "random.h" Random01::Random01(uint seed) :Random() ,_rng(seed) ,_dist(0.0,1.0) ,_gen(_rng,_dist) {} Random01::~Random01() {} double Random01::operator()() { return _gen(); } evolvotron-0.8.3/libfunction/noise.h0000644000175000017500000000346515230700302016205 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interface to Noise class. */ #ifndef _noise_h_ #define _noise_h_ #include "useful.h" #include "xyz.h" //! Perlin noise generator. class Noise { public: //! Constructor. Noise(uint seed); //! Return noise value at a point. real operator()(const XYZ& p) const; protected: //! Number of table entries. enum {N=256}; int _p[N+N+2]; XYZ _g[N+N+2]; //void setup(const XYZ&,int,int&,int&,real&,real&); }; #endif evolvotron-0.8.3/libfunction/noise.cpp0000644000175000017500000000727115230700302016537 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of Noise class */ #include "noise.h" #include "random.h" Noise::Noise(uint seed) { // We use our own random number generator so saved pictures will be the same when reloaded! // (Besides, one isn't actually conveniently available) Random01 r_01(seed); // Create an array of random gradient vectors uniformly on the unit sphere int i; for (i=0;i0;i-=2) { int j=((int)(r_01()*N)); int k=_p[i]; _p[i]=_p[j]; _p[j]=k; } // Extend g and p arrays to allow for faster indexing for (i=0;i} if [ -e ${F}.h ] ; then echo "${F}.h already exists" ; exit ; fi if [ -e ${F}.cpp ] ; then echo "${F}.cpp already exists" ; exit ; fi cat > ${F}.h < ${F}.cpp <. */ /**************************************************************************/ /*! \file \brief Interface for class MutationParameters. */ #ifndef _mutation_parameters_h_ #define _mutation_parameters_h_ #include "useful.h" #include "random.h" class FunctionNode; class FunctionRegistration; class FunctionRegistry; //! Class encapsulating mutation parameters. /*! For example, magnitude of variations, probability of leaves being dropped. Also provides a random number generator. */ class MutationParameters { private: const std::unique_ptr _function_registry; protected: //! A random number generator. /*! Declared mutable so we can pass const MutationParameters& around and still do useful work with it. */ mutable Random01 _r01; //! Negative-exponential generator might be useful too. mutable RandomNegExp _r_negexp; //! Specifies the base magnitude of random changes the function parameters. real _base_magnitude_parameter_variation; //! Specifies the base probability of a the parameter set being completely reset. real _base_probability_parameter_reset; //! Specifies the base probability of a child being dropped and replaced with a new random stub. real _base_probability_glitch; //! Specifies the base probability of all child nodes being reordered. real _base_probability_shuffle; //! Specifies the base probability of a random stub being inserted before a child. real _base_probability_insert; //! Specifies the base probability of a node being replaced with an alternate type. real _base_probability_substitute; //! Specifies the proportion of basic node types. real _proportion_basic; //! Specifies the proportion of Constant nodes vs Position type nodes. real _proportion_constant; //! Specifies the probability of a using a FunctionNodePositionTransformed instead of FunctionNodePosition real _identity_supression; //! The maximum number of iterations an iterative function node can have initially. uint _max_initial_iterations; //! The base probability of the number of iterations changing by plus or minus 1. real _base_probability_iterations_change_step; //! The base probability of the number of iterations changing by times or divide 2. real _base_probability_iterations_change_jump; //! Individual weighting modifiers for each function type /*! Will only be applied to random functions we're asked for. The bulk of nodes are created by FunctionNode and are boring to keep the branching ratio down. \todo Implement a branching ratio query method. */ std::map _function_weighting; //! Total of function weights, for normalisation. real _function_weighting_total; //! Map from [0,1] to a function registration, taking weights into account. std::map _function_pick; //! What state a reset should return autocool to. const bool _autocool_reset_state; //! Whether autocooling is being applied. bool _autocool_enable; //! Number of generations at which parameters will be half cooled. uint _autocool_halflife; //! Count of number of generations for decay cooling. uint _autocool_generations; //! Just use SingleChannelNoise for almost all functions (useful for debugging). const bool _debug_mode; void recalculate_function_stuff(); public: //! Trivial constructor. MutationParameters(uint seed,bool ac,bool debug_mode); //! Trivial destructor. virtual ~MutationParameters(); //! Accessor. const FunctionRegistry& function_registry() const { return *_function_registry; } //! Reset to initial values. void reset(); //! Multiply most parameters by the given factor void general_cool(real f); //! Returns a reference to the random number generator. /*! Need this for e.g RandomXYZInSphere constructor. */ Random01& rng01() const { return _r01; } //! Return a number in the range [0,1) real r01() const { return _r01(); } real rnegexp() const { return _r_negexp(); } //! Accessor, with decay. real effective_magnitude_parameter_variation() const { return base_magnitude_parameter_variation()*decay_factor(); } //! Accessor. real base_magnitude_parameter_variation() const { return _base_magnitude_parameter_variation; } //! Accessor. void base_magnitude_parameter_variation(real v) { _base_magnitude_parameter_variation=v; report_change(); } //! Accessor, with decay. real effective_probability_parameter_reset() const { return base_probability_parameter_reset()*decay_factor(); } //! Accessor. real base_probability_parameter_reset() const { return _base_probability_parameter_reset; } //! Accessor. void base_probability_parameter_reset(real v) { _base_probability_parameter_reset=v; report_change(); } //! Accessor, with decay. real effective_probability_glitch() const { return base_probability_glitch()*decay_factor(); } //! Accessor. real base_probability_glitch() const { return _base_probability_glitch; } //! Accessor. void base_probability_glitch(real v) { _base_probability_glitch=v; report_change(); } //! Accessor, with decay. real effective_probability_shuffle() const { return base_probability_shuffle()*decay_factor(); } //! Accessor. real base_probability_shuffle() const { return _base_probability_shuffle; } //! Accessor. void base_probability_shuffle(real v) { _base_probability_shuffle=v; report_change(); } //! Accessor, with decay. real effective_probability_insert() const { return base_probability_insert()*decay_factor(); } //! Accessor. real base_probability_insert() const { return _base_probability_insert; } //! Accessor. void base_probability_insert(real v) { _base_probability_insert=v; report_change(); } //! Accessor. real effective_probability_substitute() const { return base_probability_substitute()*decay_factor(); } //! Accessor. real base_probability_substitute() const { return _base_probability_substitute; } //! Accessor. void base_probability_substitute(real v) { _base_probability_substitute=v; report_change(); } //! Accessor. real proportion_constant() const { return _proportion_constant; } //! Accessor. void proportion_constant(real v) { _proportion_constant=v; report_change(); } //! Accessor. real identity_supression() const { return _identity_supression; } //! Accessor. void identity_supression(real v) { _identity_supression=v; report_change(); } //! Accessor. uint max_initial_iterations() const { return _max_initial_iterations; } //! Accessor. void max_initial_iterations(uint v) { _max_initial_iterations=v; report_change(); } //! Accessor, with decay. real effective_probability_iterations_change_step() const { return base_probability_iterations_change_step()*decay_factor(); } //! Accessor. real base_probability_iterations_change_step() const { return _base_probability_iterations_change_step; } //! Accessor. void base_probability_iterations_change_step(real v) { _base_probability_iterations_change_step=v; report_change(); } //! Accessor, with decay. real effective_probability_iterations_change_jump() const { return base_probability_iterations_change_jump()*decay_factor(); } //! Accessor. real base_probability_iterations_change_jump() const { return _base_probability_iterations_change_jump; } //! Accessor. void base_probability_iterations_change_jump(real v) { _base_probability_iterations_change_jump=v; report_change(); } //! Accessor. real proportion_basic() const { return _proportion_basic; } //! Accessor. void proportion_basic(real p) { _proportion_basic=p; report_change(); } //! Accessor. bool autocool_enable() const { return _autocool_enable; } //! Accessor. void autocool_enable(bool v) { _autocool_enable=v; std::clog << "Autocooling " << (autocool_enable() ? "ON" : "OFF") << "\n"; report_change(); } //! Accessor. int autocool_halflife() const { return _autocool_halflife; } //! Accessor. void autocool_halflife(int v) { _autocool_halflife=v; report_change(); } //! Accessor int autocool_generations() const { return _autocool_generations; } //! Accessor. void autocool_generations(int v) { _autocool_generations=v; report_change(); } //! Accessor. void autocool_generations_increment() { _autocool_generations++; report_change(); } //! Calculate branching ratio for above calls /* Call user should be checking this and diluting with boring nodes to keep it under control */ real random_function_branching_ratio() const; //! This returns a new random bit of tree. /*! Setting the "exciting" flag avoids the most basic node types, but only at the top level of the stub tree. */ std::unique_ptr random_function_stub(bool exciting) const; void change_function_weighting(const FunctionRegistration* fn,real w); void randomize_function_weightings_for_classifications(uint classification_mask); real get_weighting(const FunctionRegistration* fn); protected: //! Compute current decay factor real decay_factor() const; //! Return a random function appropriately biased by current settings std::unique_ptr random_function() const; //! Return a random function registration, appropriately biased by current settings const FunctionRegistration* random_weighted_function_registration() const; //! Intended for Qt-world subclass to override to emit signal. virtual void report_change(); }; #endif evolvotron-0.8.3/libfunction/mutation_parameters.cpp0000644000175000017500000001673615230700302021513 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of class MutationParameters. */ #include "mutation_parameters.h" #include "function_registration.h" #include "function_registry.h" #include "function_constant.h" #include "function_identity.h" #include "function_transform.h" MutationParameters::MutationParameters(uint seed,bool ac,bool debug_mode) :_function_registry(new FunctionRegistry()) ,_r01(seed) ,_r_negexp(seed,1.0) ,_autocool_reset_state(ac) ,_debug_mode(debug_mode) { reset(); } MutationParameters::~MutationParameters() {} void MutationParameters::reset() { _autocool_enable=_autocool_reset_state; _autocool_halflife=20; _autocool_generations=0; _base_magnitude_parameter_variation=0.25; _base_probability_parameter_reset=0.05; _base_probability_glitch=0.05; _base_probability_shuffle=0.05; _base_probability_insert=0.05; _base_probability_substitute=0.05; _proportion_basic=0.6; _proportion_constant=0.5; _identity_supression=1.0; //! \todo Could do with _max_initial_iterations being higher (64?) for fractal type things but it slows things down too much. _max_initial_iterations=16; _base_probability_iterations_change_step=0.25; _base_probability_iterations_change_jump=0.02; _function_weighting.clear(); for (FunctionRegistry::const_iterator it = _function_registry->begin(); it != _function_registry->end(); it++) { const FunctionRegistration* fn = it->second; if (_debug_mode) { real initial_weight=(fn->name == "FunctionNoiseOneChannel" ? 1.0 : 1.0/1024.0); _function_weighting.insert(std::make_pair(fn,initial_weight)); } else { real initial_weight=1.0; if (fn->classification & FnIterative) initial_weight=1.0/1024.0; // Ouch iterative functions are expensive if (fn->classification & FnFractal) initial_weight=1.0/1024.0; // Yuk fractals are ugly _function_weighting.insert(std::make_pair(fn,initial_weight)); } } recalculate_function_stuff(); report_change(); } real MutationParameters::decay_factor() const { assert(_autocool_halflife!=0); return (_autocool_enable ? pow(0.5,_autocool_generations/static_cast(_autocool_halflife)) : 1.0); } void MutationParameters::general_cool(real f) { _base_magnitude_parameter_variation*=f; _base_probability_parameter_reset*=f; _base_probability_glitch*=f; _base_probability_shuffle*=f; _base_probability_insert*=f; _base_probability_substitute*=f; _base_probability_iterations_change_step*=f; _base_probability_iterations_change_jump*=f; report_change(); } /*! This returns a random bit of image tree. It needs to be capable of generating any sort of node we have. \warning Too much probability of highly branching nodes could result in infinite sized stubs. \todo Compute (statistically) the expected number of nodes in a stub. */ std::unique_ptr MutationParameters::random_function_stub(bool exciting) const { // Base mutations are Constant or Identity types. // (Identity can be Identity or PositionTransformed, proportions depending on identity_supression parameter) const real base=proportion_basic(); const real r=(exciting ? base+(1.0-base)*r01() : r01()); if (r<(1.0-proportion_constant())*identity_supression()*base) { return FunctionTransform::stubnew(*this,false); } else if (r<(1.0-proportion_constant())*base) { return FunctionIdentity::stubnew(*this,false); } else if (r MutationParameters::random_function() const { const FunctionRegistration* fn_reg=random_weighted_function_registration(); return (*(fn_reg->stubnew_fn))(*this,false); } const FunctionRegistration* MutationParameters::random_weighted_function_registration() const { const real r=r01(); const std::map::const_iterator it=_function_pick.lower_bound(r); // Just in case last key isn't quite 1.0 if (it!=_function_pick.end()) { return (*it).second; } else { return (*(_function_pick.rbegin())).second; } } real MutationParameters::random_function_branching_ratio() const { real weighted_args=0.0; for ( std::map::const_iterator it=_function_weighting.begin(); it!=_function_weighting.end(); it++ ) { weighted_args += (*it).second*(*it).first->args; } return weighted_args/_function_weighting_total; } void MutationParameters::change_function_weighting(const FunctionRegistration* fn,real w) { _function_weighting[fn]=w; recalculate_function_stuff(); report_change(); } void MutationParameters::randomize_function_weightings_for_classifications(uint classification_mask) { for ( std::map::iterator it=_function_weighting.begin(); it!=_function_weighting.end(); it++ ) { if (classification_mask==0 || classification_mask==static_cast(-1) || ((*it).first->classification & classification_mask)) { const int i=static_cast(floor(11.0*r01())); (*it).second=pow(2,-i); } } recalculate_function_stuff(); report_change(); } real MutationParameters::get_weighting(const FunctionRegistration* fn) { std::map::const_iterator it=_function_weighting.find(fn); assert(it!=_function_weighting.end()); return (*it).second; } void MutationParameters::recalculate_function_stuff() { _function_weighting_total=0.0; for ( std::map::const_iterator it=_function_weighting.begin(); it!=_function_weighting.end(); it++ ) _function_weighting_total+=(*it).second; real normalised=0.0; _function_pick.clear(); for ( std::map::const_iterator it=_function_weighting.begin(); it!=_function_weighting.end(); it++ ) { normalised+=(*it).second/_function_weighting_total; _function_pick.insert(std::make_pair(normalised,(*it).first)); } } void MutationParameters::report_change() {} evolvotron-0.8.3/libfunction/margin.h0000644000175000017500000000364215230700302016342 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class Margin */ #ifndef _margin_h_ #define _margin_h_ #include "useful.h" //! Utility class for outputting the margin for a given level of indentation. class Margin { //! Levels of indentation const uint _n; public: //! Constructor. Margin(uint n) :_n(n) {} //! Output some spaces for each level of indentation. std::ostream& write(std::ostream& out) const; }; //! Make Margin usable using << operator. inline std::ostream& operator<<(std::ostream& out,const Margin& m) { return m.write(out); } #endif evolvotron-0.8.3/libfunction/margin.cpp0000644000175000017500000000305415230700302016672 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation for class Margin */ #include "margin.h" std::ostream& Margin::write(std::ostream& out) const { for (uint i=0;i<_n;i++) out << " "; return out; } evolvotron-0.8.3/libfunction/libfunction.pro0000644000175000017500000000030715230700302017745 0ustar karlkarlTEMPLATE = lib TARGET = function # Have to override this or we get "liblibfunction" include (../common.pro) CONFIG += staticlib CONFIG += c++11 HEADERS += $$files(*.h) SOURCES += $$files(*.cpp) evolvotron-0.8.3/libfunction/hex.h0000644000175000017500000000323715230700302015651 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Helper functions for hexagons. */ #include "useful.h" #include "xy.h" //! Returns cartesian coords of given hex-grid const XY hex_coord(int x,int y); //! Finds integer hex-grid coordinates of hex containing cartesian px,py extern const std::pair nearest_hex(real px,real py); evolvotron-0.8.3/libfunction/hex.cpp0000644000175000017500000000442115230700302016200 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of helper functions for hexagons. */ #include "hex.h" //! Co-ordinates of hexagon with given hex-grid coords const XY hex_coord(int x,int y) { const real k=sqrt(3.0)/2.0; return XY( x*k, y+((x&1) ? 0.5 : 0.0) ); } const std::pair nearest_hex(real px,real py) { // Initial guess at which hex we're in: const real k=sqrt(3.0)/2.0; const int nx=static_cast(rintf(px/k)); const int ny=static_cast ( (nx&1) ? rintf(py-0.5) : rintf(py) ); int hx=nx; int hy=ny; const XY ph=hex_coord(nx,ny); real m2b=(XY(px,py)-ph).magnitude2(); for (int dy=-1;dy<=1;dy++) for (int dx=-1;dx<=1;dx++) if (!(dy==0 && dx==0)) { const real m2=(XY(px,py)-hex_coord(nx+dx,ny+dy)).magnitude2(); if (m2. */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for specific Function classes. As much as possible of the implementation should be pushed into the FunctionBoilerplate template. */ #ifndef _functions_transform_h_ #define _functions_transform_h_ #include "useful.h" #include "function_boilerplate.h" #include "transform.h" //------------------------------------------------------ //! Function class returning simply scaled position FUNCTION_BEGIN(FunctionIsotropicScale,1,0,false,0) //! Return the evaluation of arg(0) at the transformed position argument. virtual const XYZ evaluate(const XYZ& p) const { return param(0)*p; } FUNCTION_END(FunctionIsotropicScale) //------------------------------------------------------------------------------------------ //! Function class returning leaf node evaluated at position transfomed by a 12-component linear transform. /*! Unlike FunctionPreTransform, the basis vectors for the transform are not fixed but determined from leaf functions */ FUNCTION_BEGIN(FunctionPreTransformGeneralised,0,5,false,0) //! Return the evaluation of arg(0) at the transformed position argument. virtual const XYZ evaluate(const XYZ& p) const { const Transform transform(arg(1)(p),arg(2)(p),arg(3)(p),arg(4)(p)); return arg(0)(transform.transformed(p)); } FUNCTION_END(FunctionPreTransformGeneralised) //------------------------------------------------------------------------------------------ //! Function class returning leaf node evaluated at given position; result is then transfomed by a 12-component linear transform. /*! Unlike FunctionPostTransform, the basis vectors for the transform are not fixed but determined from leaf functions */ FUNCTION_BEGIN(FunctionPostTransformGeneralised,0,5,false,0) //! Return the evaluation of arg(0) at the transformed position argument. virtual const XYZ evaluate(const XYZ& p) const { const Transform transform(arg(1)(p),arg(2)(p),arg(3)(p),arg(4)(p)); return transform.transformed(arg(0)(p)); } FUNCTION_END(FunctionPostTransformGeneralised) //------------------------------------------------------------------------------------------ //! Transforms position transformed by a 30 paramter quadratic transform. /*! This used to be a core function but it doesn't look that great. */ FUNCTION_BEGIN(FunctionTransformQuadratic,30,0,false,0) //! Return p transformed. virtual const XYZ evaluate(const XYZ& p) const { const XYZ translate(param( 0),param( 1),param( 2)); const XYZ basis_x (param( 3),param( 4),param( 5)); const XYZ basis_y (param( 6),param( 7),param( 8)); const XYZ basis_z (param( 9),param(10),param(11)); const XYZ basis_xy (param(12),param(13),param(14)); const XYZ basis_xz (param(15),param(16),param(17)); const XYZ basis_yz (param(18),param(19),param(20)); const XYZ basis_xx (param(21),param(22),param(23)); const XYZ basis_yy (param(24),param(25),param(26)); const XYZ basis_zz (param(27),param(28),param(29)); return translate +basis_x*p.x()+basis_y*p.y()+basis_z*p.z() +basis_xy*(p.x()*p.y())+basis_xz*(p.x()*p.z())+basis_yz*(p.y()*p.z()) +basis_xx*(p.x()*p.x())+basis_yy*(p.y()*p.y())+basis_zz*(p.z()*p.z()); } FUNCTION_END(FunctionTransformQuadratic) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionRotate,0,1,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const XYZ a(arg(0)(p)*M_PI); const TransformRotateX rx(a.x()); const TransformRotateY ry(a.y()); const TransformRotateZ rz(a.z()); return rx*(ry*(rz*p)); } FUNCTION_END(FunctionRotate) //------------------------------------------------------------------------------------------ #endif evolvotron-0.8.3/libfunction/functions_transform.cpp0000644000175000017500000000307615230700302021524 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of specific Function classes. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "functions_transform.h" evolvotron-0.8.3/libfunction/functions_tartan.h0000644000175000017500000001267415230700302020453 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Functions inspired by tartan patterns. */ #ifndef _functions_tartan_h_ #define _functions_tartan_h_ #include "useful.h" #include "function_boilerplate.h" //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionTartanSelectFree,10,6,false,FnStructure) //! Evaluate function. /*! Sign of one 1D function's dot product determines one bit, ditto for another bit. 2 bits used to select from 4 possibilities. There's no guarantee of a repetitive pattern unless the generator functions are. */ virtual const XYZ evaluate(const XYZ& p) const { const XYZ p0(p.x(),param(0),param(1)); const XYZ p1(param(2),p.y(),param(3)); const XYZ d0(param(4),param(5),param(6)); const XYZ d1(param(7),param(8),param(9)); const int b0=(arg(0)(p0)%XYZ(d0)>0.0); const int b1=(arg(1)(p1)%XYZ(d1)>0.0); const int which=2+b0+2*b1; assert(2<=which && which<6); return arg(which)(p); } FUNCTION_END(FunctionTartanSelectFree) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionTartanSelect,14,6,false,FnStructure) //! Evaluate function. /*! Similar to function free except the generators repeat. */ virtual const XYZ evaluate(const XYZ& p) const { const real x=(param(0)>0.0 ? modulusf(p.x(),param(1)) : trianglef(p.x(),param(1))); const real y=(param(2)>0.0 ? modulusf(p.y(),param(3)) : trianglef(p.y(),param(3))); const XYZ p0(x,param(4),param(5)); const XYZ p1(param(6),y,param(7)); const XYZ d0(param(8),param(9),param(10)); const XYZ d1(param(11),param(12),param(13)); const int b0=(arg(0)(p0)%XYZ(d0)>0.0); const int b1=(arg(1)(p1)%XYZ(d1)>0.0); const int which=2+b0+2*b1; assert(2<=which && which<6); return arg(which)(p); } FUNCTION_END(FunctionTartanSelect) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionTartanSelectRepeat,14,6,false,FnStructure) //! Evaluate function. /*! Similar to above function except the invoked functions repeat too. */ virtual const XYZ evaluate(const XYZ& p) const { const real x=(param(0)>0.0 ? modulusf(p.x(),param(1)) : trianglef(p.x(),param(1))); const real y=(param(2)>0.0 ? modulusf(p.y(),param(3)) : trianglef(p.y(),param(3))); const XYZ p0(x,param(4),param(5)); const XYZ p1(param(6),y,param(7)); const XYZ d0(param(8),param(9),param(10)); const XYZ d1(param(11),param(12),param(13)); const int b0=(arg(0)(p0)%XYZ(d0)>0.0); const int b1=(arg(1)(p1)%XYZ(d1)>0.0); const int which=2+b0+2*b1; assert(2<=which && which<6); return arg(which)(XYZ(x,y,p.z())); } FUNCTION_END(FunctionTartanSelectRepeat) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionTartanMixFree,4,2,false,0) //! Evaluate function. /*! As above, but mix 2 functions. */ virtual const XYZ evaluate(const XYZ& p) const { const XYZ p0(p.x(),param(0),param(1)); const XYZ p1(param(2),p.y(),param(3)); const XYZ warp(arg(0)(p0)); const XYZ weft(arg(1)(p1)); return 0.5*(warp+weft); } FUNCTION_END(FunctionTartanMixFree) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionTartanMixRepeat,8,2,false,0) //! Evaluate function. /*! As above, but mix 2 functions. */ virtual const XYZ evaluate(const XYZ& p) const { const real x=(param(0)>0.0 ? modulusf(p.x(),param(1)) : trianglef(p.x(),param(1))); const real y=(param(2)>0.0 ? modulusf(p.y(),param(3)) : trianglef(p.y(),param(3))); const XYZ p0(x,param(4),param(5)); const XYZ p1(param(6),y,param(7)); const XYZ warp(arg(0)(p0)); const XYZ weft(arg(1)(p1)); return 0.5*(warp+weft); } FUNCTION_END(FunctionTartanMixRepeat) //------------------------------------------------------------------------------------------ #endif evolvotron-0.8.3/libfunction/functions_tartan.cpp0000644000175000017500000000307315230700302020777 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of specific Function classes. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "functions_tartan.h" evolvotron-0.8.3/libfunction/functions_spiral.h0000644000175000017500000000555015230700302020447 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for specific Function classes. As much as possible of the implementation should be pushed into the FunctionBoilerplate template. */ #ifndef _functions_spiral_h_ #define _functions_spiral_h_ #include "useful.h" #include "function_boilerplate.h" //------------------------------------------------------ FUNCTION_BEGIN(FunctionSpiralLinear,0,1,false,FnStructure) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const real r=p.magnitude(); real theta=atan2(p.y(),p.x()); if (theta<0.0) theta+=2.0*M_PI; const real winding=floorf(r-theta/(2.0*M_PI)); const real x=2.0*winding+theta/M_PI; const real y=2.0*r-x; return arg(0)(XYZ(x,y,p.z())); } FUNCTION_END(FunctionSpiralLinear) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionSpiralLogarithmic,0,1,false,FnStructure) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const real r=p.magnitude(); real theta=atan2(p.y(),p.x()); if (theta<0.0) theta+=2.0*M_PI; const real lnr=log(r); const real winding=floorf(lnr-theta/(2.0*M_PI)); const real x=2.0*winding+theta/M_PI; const real y=2.0*lnr-x; return arg(0)(XYZ(x,y,p.z())); } FUNCTION_END(FunctionSpiralLogarithmic) //------------------------------------------------------------------------------------------ #endif evolvotron-0.8.3/libfunction/functions_spiral.cpp0000644000175000017500000000307315230700302021000 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of specific Function classes. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "functions_spiral.h" evolvotron-0.8.3/libfunction/functions_spherical.h0000644000175000017500000000743115230700302021127 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for specific Function classes. As much as possible of the implementation should be pushed into the FunctionBoilerplate template. */ #ifndef _functions_spherical_h_ #define _functions_spherical_h_ #include "useful.h" #include "function_boilerplate.h" //------------------------------------------------------ //! Transforms cartesian coordinates to spherical FUNCTION_BEGIN(FunctionCartesianToSpherical,0,0,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const real r=p.magnitude(); // Angles are normalised (-1 to +1) over their usual possible range. const real theta=atan2(p.y(),p.x())*(1.0/M_PI); const real phi=(r== 0.0 ? 0.0 : asin(p.z()/r)*(1.0/(0.5*M_PI))); return XYZ(r,theta,phi); } FUNCTION_END(FunctionCartesianToSpherical) //------------------------------------------------------------------------------------------ //! Transforms spherical coordinates to cartesian FUNCTION_BEGIN(FunctionSphericalToCartesian,0,0,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const real r=p.x(); const real theta=M_PI*p.y(); const real phi=0.5*M_PI*p.z(); const real x=r*cos(theta)*sin(phi); const real y=r*sin(theta)*sin(phi); const real z=r*cos(phi); return XYZ(x,y,z); } FUNCTION_END(FunctionSphericalToCartesian) //------------------------------------------------------------------------------------------ // Converts the position argument to spherical coords, pass these through the leaf node, and convert the result back to cartesian. FUNCTION_BEGIN(FunctionEvaluateInSpherical,0,1,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const real in_r=p.magnitude(); const real in_theta=atan2(p.y(),p.x())*(1.0/M_PI); const real in_phi=(in_r== 0.0 ? 0.0 : asin(p.z()/in_r)*(1.0/(0.5*M_PI))); const XYZ v(arg(0)(XYZ(in_r,in_theta,in_phi))); const real out_r=v.x(); const real out_theta=M_PI*v.y(); const real out_phi=0.5*M_PI*v.z(); const real x=out_r*cos(out_theta)*sin(out_phi); const real y=out_r*sin(out_theta)*sin(out_phi); const real z=out_r*cos(out_phi); return XYZ(x,y,z); } FUNCTION_END(FunctionEvaluateInSpherical) //------------------------------------------------------------------------------------------ #endif evolvotron-0.8.3/libfunction/functions_spherical.cpp0000644000175000017500000000307615230700302021463 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of specific Function classes. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "functions_spherical.h" evolvotron-0.8.3/libfunction/functions_shadow.h0000644000175000017500000000471615230700302020445 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for specific Function classes. */ #ifndef _functions_shadow_h_ #define _functions_shadow_h_ #include "useful.h" #include "function_boilerplate.h" //------------------------------------------------------------------------------------------ //! Sum of two evaluations of a function, one sampled at a constant offset and weighted. FUNCTION_BEGIN(FunctionShadow,4,1,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { return arg(0)(p)+param(3)*arg(0)(p+XYZ(param(0),param(1),param(2))); } FUNCTION_END(FunctionShadow) //------------------------------------------------------------------------------------------ //! Like FunctionShadow but the offset is obtained from a function. FUNCTION_BEGIN(FunctionShadowGeneralised,1,2,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { return arg(0)(p)+param(0)*arg(0)(p+arg(1)(p)); } FUNCTION_END(FunctionShadowGeneralised) //------------------------------------------------------------------------------------------ #endif evolvotron-0.8.3/libfunction/functions_shadow.cpp0000644000175000017500000000307315230700302020773 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of specific Function classes. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "functions_shadow.h" evolvotron-0.8.3/libfunction/functions_render.h0000644000175000017500000001457215230700302020440 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for specific Function classes. As much as possible of the implementation should be pushed into the FunctionBoilerplate template. */ #ifndef _functions_render_h_ #define _functions_render_h_ #include "useful.h" #include "function_boilerplate.h" //------------------------------------------------------------------------------------------ //! Rays intersecting a textured unit sphere /*! arg(0) is background arg(1) is 3D texture for sphere param(0,1,2) is light source direction p.x, p.y is the 2D position of a ray from infinity travelling in direction (0 0 1) */ FUNCTION_BEGIN(FunctionOrthoSphereShaded,3,2,false,FnRender) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const real pr2=p.x()*p.x()+p.y()*p.y(); if (pr2<1.0) { const real z=-sqrt(1.0-pr2); const XYZ n(p.x(),p.y(),z); const XYZ lu(param(0),param(1),param(2)); const XYZ l(lu.normalised()); const real i=0.5*(1.0+l%n); // In range 0-1 return i*arg(1)(n); } else { return arg(0)(p); } } FUNCTION_END(FunctionOrthoSphereShaded) //------------------------------------------------------------------------------------------ //! Rays intersecting a textured unit sphere, with bump mapping /*! arg(0) is background arg(1) is 3D texture for sphere arg(2) is bump-map for sphere (take magnitude2) param(0,1,2) is light source direction p.x, p.y is the 2D position of a ray from infinity travelling in direction (0 0 1) */ FUNCTION_BEGIN(FunctionOrthoSphereShadedBumpMapped,3,3,false,FnRender) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const real pr2=p.x()*p.x()+p.y()*p.y(); if (pr2<1.0) { const real z=-sqrt(1.0-pr2); const XYZ n(p.x(),p.y(),z); // Tangent vectors const XYZ east((XYZ(0.0,1.0,0.0)*n).normalised()); const XYZ north(n*east); const real e0=(arg(2)(n-epsilon()*east)).magnitude2(); const real e1=(arg(2)(n+epsilon()*east)).magnitude2(); const real n0=(arg(2)(n-epsilon()*north)).magnitude2(); const real n1=(arg(2)(n+epsilon()*north)).magnitude2(); const real de=(e1-e0)*inv_epsilon2(); const real dn=(n1-n0)*inv_epsilon2(); const XYZ perturbed_n((n-east*de-north*dn).normalised()); const XYZ lu(param(0),param(1),param(2)); const XYZ l(lu.normalised()); const real i=0.5*(1.0+l%perturbed_n); // In range 0-1 return i*arg(1)(n); } else { return arg(0)(p); } } FUNCTION_END(FunctionOrthoSphereShadedBumpMapped) //------------------------------------------------------------------------------------------ //! Rays reflecting off a unit sphere /*! arg(0) is background arg(1) sampled using a normalised vector defines an environment for reflected rays p.x, p.y is the 2D position of a ray from infinity travelling in direction (0 0 1) */ FUNCTION_BEGIN(FunctionOrthoSphereReflect,0,2,false,FnRender) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const real pr2=p.x()*p.x()+p.y()*p.y(); if (pr2<1.0) { const real z=-sqrt(1.0-pr2); // This is on surface of unit radius sphere - no need to normalise XYZ n(p.x(),p.y(),z); // The ray _towards_ the viewer v is (0 0 -1) const XYZ v(0.0,0.0,-1.0); // The reflected ray is (2n.v)n-v const XYZ reflected((2.0*(n%v))*n-v); return arg(1)(reflected); } else { return arg(0)(p); } } FUNCTION_END(FunctionOrthoSphereReflect) //------------------------------------------------------------------------------------------ //! Rays reflecting off a bump mapped unit sphere /*! arg(0) is background arg(1) sampled using a normalised vector defines an environment for reflected rays arg(2) is bump map p.x, p.y is the 2D position of a ray from infinity travelling in direction (0 0 1) */ FUNCTION_BEGIN(FunctionOrthoSphereReflectBumpMapped,0,3,false,FnRender) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const real pr2=p.x()*p.x()+p.y()*p.y(); if (pr2<1.0) { const real z=-sqrt(1.0-pr2); // This is on surface of unit radius sphere - no need to normalise XYZ n(p.x(),p.y(),z); // Tangent vectors const XYZ east((XYZ(0.0,1.0,0.0)*n).normalised()); const XYZ north(n*east); const real e0=(arg(2)(n-epsilon()*east)).magnitude2(); const real e1=(arg(2)(n+epsilon()*east)).magnitude2(); const real n0=(arg(2)(n-epsilon()*north)).magnitude2(); const real n1=(arg(2)(n+epsilon()*north)).magnitude2(); const real de=(e1-e0)*inv_epsilon2(); const real dn=(n1-n0)*inv_epsilon2(); const XYZ perturbed_n((n-east*de-north*dn).normalised()); // The ray _towards_ the viewer is (0 0 -1) const XYZ v(0.0,0.0,-1.0); // The reflected ray is (2n.v)n-v const XYZ reflected((2.0*(perturbed_n%v))*perturbed_n-v); return arg(1)(reflected); } else { return arg(0)(p); } } FUNCTION_END(FunctionOrthoSphereReflectBumpMapped) //------------------------------------------------------------------------------------------ #endif evolvotron-0.8.3/libfunction/functions_render.cpp0000644000175000017500000000307315230700302020765 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of specific Function classes. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "functions_render.h" evolvotron-0.8.3/libfunction/functions_quantize.h0000644000175000017500000000577715230700302021030 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Functions inspired by tartan patterns. */ #ifndef _functions_quantize_h_ #define _functions_quantize_h_ #include "useful.h" #include "function_boilerplate.h" #include "hex.h" //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionPixelize,2,0,false,FnStructure) //! Evaluate function. /*! Quantize coordinates to 2D grid */ virtual const XYZ evaluate(const XYZ& p) const { return XYZ ( param(0)*round(p.x()/param(0)), param(1)*round(p.y()/param(1)), p.z() ); } FUNCTION_END(FunctionPixelize) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionVoxelize,3,0,false,FnStructure) //! Evaluate function. /*! Quantize coordinates to 3D grid. */ virtual const XYZ evaluate(const XYZ& p) const { return XYZ ( param(0)*round(p.x()/param(0)), param(1)*round(p.y()/param(1)), param(2)*round(p.z()/param(2)) ); } FUNCTION_END(FunctionVoxelize) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionPixelizeHex,1,0,false,FnStructure) //! Evaluate function. /*! Quantize coordinates to 2D hexgrid. */ virtual const XYZ evaluate(const XYZ& p) const { const std::pair h=nearest_hex(p.x()/param(0),p.y()/param(0)); //std::cerr << h.first << " " << h.second << "\n"; return XYZ ( param(0)*hex_coord(h.first,h.second), p.z() ); } FUNCTION_END(FunctionPixelizeHex) //------------------------------------------------------------------------------------------ #endif evolvotron-0.8.3/libfunction/functions_quantize.cpp0000644000175000017500000000307515230700302021350 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of specific Function classes. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "functions_quantize.h" evolvotron-0.8.3/libfunction/functions_noise.h0000644000175000017500000000756515230700302020302 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for FunctionNoise */ #ifndef _functions_noise_h_ #define _functions_noise_h_ #include "useful.h" #include "function_boilerplate.h" #include "noise.h" //------------------------------------------------------------------------------------------ //! Perlin noise function. /*! Returns a single value replicated into all three channels */ FUNCTION_BEGIN(FunctionNoiseOneChannel,0,0,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { // Crank up the frequency a bit otherwise don't see much variation in base case const real v=_noise(2.0*p); return XYZ(v,v,v); } protected: static Noise _noise; FUNCTION_END(FunctionNoiseOneChannel) //------------------------------------------------------------------------------------------ //! Multiscale noise function. /*! Returns a single value replicated into all three channels */ FUNCTION_BEGIN(FunctionMultiscaleNoiseOneChannel,0,0,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { real t=0.0; real tm=0.0; for (uint i=0;i<8;i++) { const real k=(1<. */ /**************************************************************************/ /*! \file \brief Implementation of noise related function classes. */ #include "function_boilerplate_instantiate.h" #include "functions_noise.h" Noise FunctionNoiseOneChannel::_noise(100); Noise FunctionMultiscaleNoiseOneChannel::_noise(101); Noise FunctionNoiseThreeChannel::_noise0(200); Noise FunctionNoiseThreeChannel::_noise1(300); Noise FunctionNoiseThreeChannel::_noise2(400); Noise FunctionMultiscaleNoiseThreeChannel::_noise0(201); Noise FunctionMultiscaleNoiseThreeChannel::_noise1(202); Noise FunctionMultiscaleNoiseThreeChannel::_noise2(203); evolvotron-0.8.3/libfunction/functions_misc.h0000644000175000017500000001024615230700302020106 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for specific Function classes. Use this for functions under development, but they should really be split out into separate files eventually. */ #ifndef _functions_misc_h_ #define _functions_misc_h_ #include "useful.h" #include "function_boilerplate.h" //------------------------------------------------------------------------------------------ //! Multiply x and y by z. FUNCTION_BEGIN(FunctionCone,0,0,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { return XYZ(p.x()*p.z(),p.y()*p.z(),p.z()); } FUNCTION_END(FunctionCone) //------------------------------------------------------------------------------------------ //! Multiply x and y by exp(z). FUNCTION_BEGIN(FunctionExpCone,0,0,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const real k=exp(p.z()); return XYZ(p.x()*k,p.y()*k,p.z()); } FUNCTION_END(FunctionExpCone) //------------------------------------------------------------------------------------------ //! Separate influence of z co-ordinate. /*! Interesting as a top level node for animations as structure will tend to be fixed, with only colour map changing */ FUNCTION_BEGIN(FunctionSeparateZ,3,2,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const XYZ v=arg(0)(XYZ(p.x(),p.y(),0.0)); return arg(1)(v+p.z()*XYZ(param(0),param(1),param(2))); } FUNCTION_END(FunctionSeparateZ) //------------------------------------------------------------------------------------------ //! Function repeatedly applying it's leaf function to the argument FUNCTION_BEGIN(FunctionIterate,0,1,true,FnIterative) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { XYZ ret(p); for (uint i=0;i. */ /**************************************************************************/ /*! \file \brief Implementation of specific Function classes. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "functions_misc.h" evolvotron-0.8.3/libfunction/functions_magnitude.h0000644000175000017500000000513215230700302021126 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for specific Function classes. As much as possible of the implementation should be pushed into the FunctionBoilerplate template. */ #ifndef _functions_magnitude_h_ #define _functions_magnitude_h_ #include "useful.h" #include "function_boilerplate.h" //------------------------------------------------------------------------------------------ //! Function returns a value comprising the magnitude of three leaf functions. FUNCTION_BEGIN(FunctionMagnitudes,0,3,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { return XYZ( arg(0)(p).magnitude(), arg(1)(p).magnitude(), arg(2)(p).magnitude() ); } FUNCTION_END(FunctionMagnitudes) //------------------------------------------------------------------------------------------ //! Function returns leaf function value magnitude scaled by position magnitude. FUNCTION_BEGIN(FunctionMagnitude,3,1,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { return arg(0)(p).magnitude()*XYZ(param(0),param(1),param(2)); } FUNCTION_END(FunctionMagnitude) //------------------------------------------------------------------------------------------ #endif evolvotron-0.8.3/libfunction/functions_magnitude.cpp0000644000175000017500000000307615230700302021466 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of specific Function classes. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "functions_magnitude.h" evolvotron-0.8.3/libfunction/functions_kaleidoscope.h0000644000175000017500000001275215230700302021621 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for specific Function classes. As much as possible of the implementation should be pushed into the FunctionBoilerplate template. */ #ifndef _functions_kaleidoscope_h_ #define _functions_kaleidoscope_h_ #include "useful.h" #include "function_boilerplate.h" //------------------------------------------------------------------------------------------ //! Implements reflection of sampling point about multiple planes FUNCTION_BEGIN(FunctionKaleidoscope,1,1,false,FnStructure) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const uint n=2+static_cast(floor(8.0*fabs(param(0)))); const real a=atan2(p.x(),p.y()); const real r=sqrt(p.x()*p.x()+p.y()*p.y()); const real sa=trianglef(a,M_PI/n); const XYZ s(r*sin(sa),r*cos(sa),p.z()); return arg(0)(s); } FUNCTION_END(FunctionKaleidoscope) //------------------------------------------------------------------------------------------ //! Like FunctionKaleidoscope but Z drives rotation of underlying function /*! Good for animation */ FUNCTION_BEGIN(FunctionKaleidoscopeZRotate,2,1,false,FnStructure) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const uint n=2+static_cast(floor(8.0*fabs(param(0)))); const real a=atan2(p.x(),p.y()); const real r=sqrt(p.x()*p.x()+p.y()*p.y()); const real sa=trianglef(a,M_PI/n)+param(1)*p.z(); const XYZ s(r*sin(sa),r*cos(sa),0.0); return arg(0)(s); } FUNCTION_END(FunctionKaleidoscopeZRotate) //------------------------------------------------------------------------------------------ //! Like FunctionKaleidoscope with a twist FUNCTION_BEGIN(FunctionKaleidoscopeTwist,2,1,false,FnStructure) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const uint n=2+static_cast(floor(8.0*fabs(param(0)))); const real a=atan2(p.x(),p.y()); const real r=sqrt(p.x()*p.x()+p.y()*p.y()); const real sa=trianglef(a-r*param(1),M_PI/n); const XYZ s(r*sin(sa),r*cos(sa),p.z()); return arg(0)(s); } FUNCTION_END(FunctionKaleidoscopeTwist) //------------------------------------------------------------------------------------------ //! Implements reflection of sampling point about multiple planes FUNCTION_BEGIN(FunctionWindmill,1,1,false,FnStructure) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const uint n=1+static_cast(floor(8.0*fabs(param(0)))); const real a=atan2(p.x(),p.y()); const real r=sqrt(p.x()*p.x()+p.y()*p.y()); const real sa=modulusf(a,M_PI/n); const XYZ s(r*sin(sa),r*cos(sa),p.z()); return arg(0)(s); } FUNCTION_END(FunctionWindmill) //------------------------------------------------------------------------------------------ //! Like FunctionWindmill but Z drives rotation of underlying function /*! Good for animation */ FUNCTION_BEGIN(FunctionWindmillZRotate,2,1,false,FnStructure) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const uint n=1+static_cast(floor(8.0*fabs(param(0)))); const real a=atan2(p.x(),p.y()); const real r=sqrt(p.x()*p.x()+p.y()*p.y()); const real sa=modulusf(a,M_PI/n)+param(1)*p.z(); const XYZ s(r*sin(sa),r*cos(sa),0.0); return arg(0)(s); } FUNCTION_END(FunctionWindmillZRotate) //------------------------------------------------------------------------------------------ //! Like FunctionWindmill with twist FUNCTION_BEGIN(FunctionWindmillTwist,2,1,false,FnStructure) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const uint n=1+static_cast(floor(8.0*fabs(param(0)))); const real a=atan2(p.x(),p.y()); const real r=sqrt(p.x()*p.x()+p.y()*p.y()); const real sa=modulusf(a-r*param(1),M_PI/n); const XYZ s(r*sin(sa),r*cos(sa),p.z()); return arg(0)(s); } FUNCTION_END(FunctionWindmillTwist) //------------------------------------------------------------------------------------------ #endif evolvotron-0.8.3/libfunction/functions_kaleidoscope.cpp0000644000175000017500000000310115230700302022140 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of specific Function classes. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "functions_kaleidoscope.h" evolvotron-0.8.3/libfunction/functions_juliabrot.h0000644000175000017500000001411615230700302021146 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for specific Function classes. As much as possible of the implementation should be pushed into the FunctionBoilerplate template. */ #ifndef _functions_juliabrot_h_ #define _functions_juliabrot_h_ #include "useful.h" #include "function_boilerplate.h" //------------------------------------------------------------------------------------------ //! Mandelbrot/Julia iterator for fractal functions. /*! Returns i in 0 to iterations inclusive. i==iterations implies "in" set. */ inline uint brot(const real z0r,const real z0i,const real cr,const real ci,const uint iterations) { real zr=z0r; real zi=z0i; uint i; for (i=0;i4.0) break; const real nzr=zr2-zi2+cr; const real nzi=2.0*zr*zi+ci; zr=nzr; zi=nzi; } return i; } //------------------------------------------------------------------------------------------ //! Function selects arg to evaluate based on test for point in Mandelbrot set. FUNCTION_BEGIN(FunctionMandelbrotChoose,0,2,true,FnIterative|FnFractal) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { return (brot(0.0,0.0,p.x(),p.y(),iterations())==iterations() ? arg(0)(p) : arg(1)(p)); } FUNCTION_END(FunctionMandelbrotChoose) //----------------------------------------------------------------------------------------- //! Function returns -1 for points in set, 0-1 for escaped points FUNCTION_BEGIN(FunctionMandelbrotContour,0,0,true,FnIterative|FnFractal) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const uint i=brot(0.0,0.0,p.x(),p.y(),iterations()); return (i==iterations() ? XYZ::fill(-1.0) : XYZ::fill(static_cast(i)/iterations())); } FUNCTION_END(FunctionMandelbrotContour) //------------------------------------------------------------------------------------------ //! Function selects arg to evaluate based on test for point in Julia set. FUNCTION_BEGIN(FunctionJuliaChoose,2,2,true,FnIterative|FnFractal) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { return (brot(p.x(),p.y(),param(0),param(1),iterations())==iterations() ? arg(0)(p) : arg(1)(p)); } FUNCTION_END(FunctionJuliaChoose) //------------------------------------------------------------------------------------------ //! Function returns -1 for points in set, 0-1 for escaped points FUNCTION_BEGIN(FunctionJuliaContour,2,0,true,FnIterative|FnFractal) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const uint i=brot(p.x(),p.y(),param(0),param(1),iterations()); return (i==iterations() ? XYZ::fill(-1.0) : XYZ::fill(static_cast(i)/iterations())); } FUNCTION_END(FunctionJuliaContour) //------------------------------------------------------------------------------------------ //! Function selects arg to evaluate based on test for point in Juliabrot set. /*! Juliabrot is 4 dimensional, but we only have 3 incoming parameters, so have 4 4d-basis vector parameters. */ FUNCTION_BEGIN(FunctionJuliabrotChoose,16,2,true,FnIterative|FnFractal) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const real zr=p.x()*param( 0)+p.y()*param( 1)+p.z()*param( 2)+param( 3); const real zi=p.x()*param( 4)+p.y()*param( 5)+p.z()*param( 6)+param( 7); const real cr=p.x()*param( 8)+p.y()*param( 9)+p.z()*param(10)+param(11); const real ci=p.x()*param(12)+p.y()*param(13)+p.z()*param(14)+param(15); return (brot(zr,zi,cr,ci,iterations())==iterations() ? arg(0)(p) : arg(1)(p)); } FUNCTION_END(FunctionJuliabrotChoose) //------------------------------------------------------------------------------------------ //! Function returns -1 for points in set, 0-1 for escaped points /*! Juliabrot is 4 dimensional, but we only have 3 incoming parameters, so have 4 4d-basis vector parameters. */ FUNCTION_BEGIN(FunctionJuliabrotContour,16,0,true,FnIterative|FnFractal) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const real zr=p.x()*param( 0)+p.y()*param( 1)+p.z()*param( 2)+param( 3); const real zi=p.x()*param( 4)+p.y()*param( 5)+p.z()*param( 6)+param( 7); const real cr=p.x()*param( 8)+p.y()*param( 9)+p.z()*param(10)+param(11); const real ci=p.x()*param(12)+p.y()*param(13)+p.z()*param(14)+param(15); const uint i=brot(zr,zi,cr,ci,iterations()); return (i==iterations() ? XYZ::fill(-1.0) : XYZ::fill(static_cast(i)/iterations())); } FUNCTION_END(FunctionJuliabrotContour) //------------------------------------------------------------------------------------------ #endif evolvotron-0.8.3/libfunction/functions_juliabrot.cpp0000644000175000017500000000307615230700302021504 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of specific Function classes. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "functions_juliabrot.h" evolvotron-0.8.3/libfunction/functions_gradient.h0000644000175000017500000001563515230700302020757 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for specific Function classes. As much as possible of the implementation should be pushed into the FunctionBoilerplate template. */ #ifndef _functions_gradient_h_ #define _functions_gradient_h_ #include "useful.h" #include "function_boilerplate.h" //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionDerivative,3,1,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const XYZ d(epsilon()*XYZ(param(0),param(1),param(2)).normalised()); const XYZ v0(arg(0)(p-d)); const XYZ v1(arg(0)(p+d)); return (v1-v0)*inv_epsilon2(); } FUNCTION_END(FunctionDerivative) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionDerivativeGeneralised,0,2,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const XYZ d(epsilon()*(arg(1)(p)).normalised()); const XYZ v0(arg(0)(p-d)); const XYZ v1(arg(0)(p+d)); return (v1-v0)*inv_epsilon2(); } FUNCTION_END(FunctionDerivativeGeneralised) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionGradient,3,1,false,0) //! Evaluate function. /*! Gradient converts scalar to vector, so need a scalar to work on. */ virtual const XYZ evaluate(const XYZ& p) const { const XYZ k(param(0),param(1),param(2)); const real vx0=k%arg(0)(p-XYZ(epsilon(),0.0,0.0)); const real vy0=k%arg(0)(p-XYZ(0.0,epsilon(),0.0)); const real vz0=k%arg(0)(p-XYZ(0.0,0.0,epsilon())); const real vx1=k%arg(0)(p+XYZ(epsilon(),0.0,0.0)); const real vy1=k%arg(0)(p+XYZ(0.0,epsilon(),0.0)); const real vz1=k%arg(0)(p+XYZ(0.0,0.0,epsilon())); return XYZ(vx1-vx0,vy1-vy0,vz1-vz0)*inv_epsilon2(); } FUNCTION_END(FunctionGradient) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionGradientGeneralised,0,2,false,0) //! Evaluate function. /*! Gradient converts scalar to vector, so need a scalar to work on. */ virtual const XYZ evaluate(const XYZ& p) const { const XYZ k(arg(1)(p)); const real vx0=k%arg(0)(p-XYZ(epsilon(),0.0,0.0)); const real vy0=k%arg(0)(p-XYZ(0.0,epsilon(),0.0)); const real vz0=k%arg(0)(p-XYZ(0.0,0.0,epsilon())); const real vx1=k%arg(0)(p+XYZ(epsilon(),0.0,0.0)); const real vy1=k%arg(0)(p+XYZ(0.0,epsilon(),0.0)); const real vz1=k%arg(0)(p+XYZ(0.0,0.0,epsilon())); return XYZ(vx1-vx0,vy1-vy0,vz1-vz0)*inv_epsilon2(); } FUNCTION_END(FunctionGradientGeneralised) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionDivergence,0,1,false,0) //! Evaluate function. /*! Divergence maps scalar to a scalar, so no problem doing vector->vector. */ virtual const XYZ evaluate(const XYZ& p) const { const XYZ vx0(arg(0)(p-XYZ(epsilon(),0.0,0.0))); const XYZ vy0(arg(0)(p-XYZ(0.0,epsilon(),0.0))); const XYZ vz0(arg(0)(p-XYZ(0.0,0.0,epsilon()))); const XYZ vx1(arg(0)(p+XYZ(epsilon(),0.0,0.0))); const XYZ vy1(arg(0)(p+XYZ(0.0,epsilon(),0.0))); const XYZ vz1(arg(0)(p+XYZ(0.0,0.0,epsilon()))); return (vx1-vx0+vy1-vy0+vz1-vz0)*inv_epsilon2(); } FUNCTION_END(FunctionDivergence) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionCurl,0,1,false,0) //! Evaluate function. /*! Curl maps vector to vector, which is what we want. */ virtual const XYZ evaluate(const XYZ& p) const { const XYZ vx0(arg(0)(p-XYZ(epsilon(),0.0,0.0))); const XYZ vy0(arg(0)(p-XYZ(0.0,epsilon(),0.0))); const XYZ vz0(arg(0)(p-XYZ(0.0,0.0,epsilon()))); const XYZ vx1(arg(0)(p+XYZ(epsilon(),0.0,0.0))); const XYZ vy1(arg(0)(p+XYZ(0.0,epsilon(),0.0))); const XYZ vz1(arg(0)(p+XYZ(0.0,0.0,epsilon()))); const XYZ d_dx((vx1-vx0)*inv_epsilon2()); const XYZ d_dy((vy1-vy0)*inv_epsilon2()); const XYZ d_dz((vz1-vz0)*inv_epsilon2()); const real dzdy=d_dy.z(); const real dydz=d_dz.y(); const real dxdz=d_dz.x(); const real dzdx=d_dx.z(); const real dydx=d_dx.y(); const real dxdy=d_dy.x(); return XYZ ( dzdy-dydz, dxdz-dzdx, dydx-dxdy ); } FUNCTION_END(FunctionCurl) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionScalarLaplacian,0,1,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { // Need to use a bigger baseline to avoid noise being amplified const XYZ vx0(arg(0)(p-XYZ(big_epsilon(),0.0,0.0))); const XYZ vy0(arg(0)(p-XYZ(0.0,big_epsilon(),0.0))); const XYZ vz0(arg(0)(p-XYZ(0.0,0.0,big_epsilon()))); const XYZ v(arg(0)(p)); const XYZ vx1(arg(0)(p+XYZ(big_epsilon(),0.0,0.0))); const XYZ vy1(arg(0)(p+XYZ(0.0,big_epsilon(),0.0))); const XYZ vz1(arg(0)(p+XYZ(0.0,0.0,big_epsilon()))); const XYZ dx0(v-vx0); const XYZ dy0(v-vy0); const XYZ dz0(v-vz0); const XYZ dx1(vx1-v); const XYZ dy1(vy1-v); const XYZ dz1(vz1-v); return XYZ(dx1-dx0+dy1-dy0+dz1-dz0)/(big_epsilon()*big_epsilon()); } FUNCTION_END(FunctionScalarLaplacian) //------------------------------------------------------------------------------------------ #endif evolvotron-0.8.3/libfunction/functions_gradient.cpp0000644000175000017500000000307515230700302021305 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of specific Function classes. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "functions_gradient.h" evolvotron-0.8.3/libfunction/functions_geometry.h0000644000175000017500000000644615230700302021015 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for specific Function classes. As much as possible of the implementation should be pushed into the FunctionBoilerplate template. */ #ifndef _functions_geometry_h_ #define _functions_geometry_h_ #include "useful.h" #include "function_boilerplate.h" //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionCross,0,2,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const XYZ v0(arg(0)(p)); const XYZ v1(arg(1)(p)); return v0*v1; } FUNCTION_END(FunctionCross) //------------------------------------------------------------------------------------------ //! Invert the leaf function using a radius-one origin centred sphere. FUNCTION_BEGIN(FunctionGeometricInversion,0,1,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const real radius2=p.magnitude2(); const XYZ ip(p/radius2); return arg(0)(ip); } FUNCTION_END(FunctionGeometricInversion) //------------------------------------------------------------------------------------------ //! Implements reflection of sampling point about a plane FUNCTION_BEGIN(FunctionReflect,0,3,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const XYZ pt_in_plane(arg(0)(p)); const XYZ normal(arg(1)(p).normalised()); XYZ pos(arg(2)(p)); const real distance_from_plane=(pos-pt_in_plane)%normal; // If pos is on the wrong side of the plane, reflect it over // Check: normal (0,0,1), pos (0,0,-1) => distance -1, pos-=(2*-1)*(0,0,1) => pos-=(0,0,-2) if (distance_from_plane<0.0) { pos-=(2.0*distance_from_plane)*normal; } return pos; } FUNCTION_END(FunctionReflect) //------------------------------------------------------------------------------------------ #endif evolvotron-0.8.3/libfunction/functions_geometry.cpp0000644000175000017500000000307515230700302021343 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of specific Function classes. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "functions_geometry.h" evolvotron-0.8.3/libfunction/functions_friezegroup_step.h0000644000175000017500000000537715230700302022560 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for specific Function classes. */ #ifndef _functions_friezegroup_step_h_ #define _functions_friezegroup_step_h_ #include "useful.h" #include "function_boilerplate.h" #include "friezegroup.h" //! Step (Conway p1a1): glide reflection only. /*! Sawtooth x, out of step by half range across y-axis. \verbatim o o --- --- --- --- o o \endverbatim */ struct Step { const XY operator()(const XY& p) const { return XY ( (p.y()>0.0 ? modulusf(p.x(),1.0) : modulusf(p.x()+0.5,1.0)), fabs(p.y()) ); } }; struct StepInvariant; struct StepBlend; //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionFriezeGroupStepFreeZ,0,1,false,FnStructure) virtual const XYZ evaluate(const XYZ& p) const { return FriezegroupEvaluate(arg(0),p,Step(),FreeZ()); } FUNCTION_END(FunctionFriezeGroupStepFreeZ) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionFriezeGroupStepClampZ,1,1,false,FnStructure) virtual const XYZ evaluate(const XYZ& p) const { return FriezegroupEvaluate(arg(0),p,Step(),ClampZ(param(0))); } FUNCTION_END(FunctionFriezeGroupStepClampZ) //------------------------------------------------------------------------------------------ #endif evolvotron-0.8.3/libfunction/functions_friezegroup_step.cpp0000644000175000017500000000310615230700302023077 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of specific Function classes. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "functions_friezegroup_step.h" evolvotron-0.8.3/libfunction/functions_friezegroup_spinsidle.h0000644000175000017500000000552415230700302023571 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for specific Function classes. */ #ifndef _functions_friezegroup_spinsidle_h_ #define _functions_friezegroup_spinsidle_h_ #include "useful.h" #include "function_boilerplate.h" #include "friezegroup.h" //! Spinsidle (Conway pma2): Glide reflection with half rotation. /*! Oscillate x, reflect y in alternate x cycles. \verbatim |oo| |oo| | | | | | | | | | | | | |oo| \endverbatim */ struct Spinsidle { const XY operator()(const XY& p) const { return XY ( trianglef(p.x(),0.5), modulusf(p.x()+0.5,2.0)<1.0 ? p.y() : -p.y() ); } }; struct SpinsidleInvariant; struct SpinsidleBlend; //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionFriezeGroupSpinsidleFreeZ,0,1,false,FnStructure) virtual const XYZ evaluate(const XYZ& p) const { return FriezegroupEvaluate(arg(0),p,Spinsidle(),FreeZ()); } FUNCTION_END(FunctionFriezeGroupSpinsidleFreeZ) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionFriezeGroupSpinsidleClampZ,1,1,false,FnStructure) virtual const XYZ evaluate(const XYZ& p) const { return FriezegroupEvaluate(arg(0),p,Spinsidle(),ClampZ(param(0))); } FUNCTION_END(FunctionFriezeGroupSpinsidleClampZ) //------------------------------------------------------------------------------------------ #endif evolvotron-0.8.3/libfunction/functions_friezegroup_spinsidle.cpp0000644000175000017500000000311315230700302024114 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of specific Function classes. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "functions_friezegroup_spinsidle.h" evolvotron-0.8.3/libfunction/functions_friezegroup_spinjump.h0000644000175000017500000000471315230700302023443 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for specific Function classes. */ #ifndef _functions_friezegroup_spinjump_h_ #define _functions_friezegroup_spinjump_h_ #include "useful.h" #include "function_boilerplate.h" #include "friezegroup.h" //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionFriezeGroupSpinjumpFreeZ,0,1,false,FnStructure) virtual const XYZ evaluate(const XYZ& p) const { return FriezegroupEvaluate(arg(0),p,Spinjump(1.0),FreeZ()); } FUNCTION_END(FunctionFriezeGroupSpinjumpFreeZ) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionFriezeGroupSpinjumpClampZ,1,1,false,FnStructure) // Don't think this form can be warped without breaking symmetry virtual const XYZ evaluate(const XYZ& p) const { return FriezegroupEvaluate(arg(0),p,Spinjump(1.0),ClampZ(param(0))); } FUNCTION_END(FunctionFriezeGroupSpinjumpClampZ) //------------------------------------------------------------------------------------------ #endif evolvotron-0.8.3/libfunction/functions_friezegroup_spinjump.cpp0000644000175000017500000000311215230700302023766 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of specific Function classes. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "functions_friezegroup_spinjump.h" evolvotron-0.8.3/libfunction/functions_friezegroup_spinhop.h0000644000175000017500000000763415230700302023263 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for specific Function classes. */ #ifndef _functions_friezegroup_spinhop_h_ #define _functions_friezegroup_spinhop_h_ #include "useful.h" #include "function_boilerplate.h" #include "friezegroup.h" //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionFriezeGroupSpinhopFreeZ,0,1,false,FnStructure) virtual const XYZ evaluate(const XYZ& p) const { return FriezegroupEvaluate(arg(0),p,Spinhop(1.0),FreeZ()); } FUNCTION_END(FunctionFriezeGroupSpinhopFreeZ) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionFriezeGroupSpinhopClampZ,1,1,false,FnStructure) virtual const XYZ evaluate(const XYZ& p) const { return FriezegroupEvaluate(arg(0),p,Spinhop(1.0),ClampZ(param(0))); } FUNCTION_END(FunctionFriezeGroupSpinhopClampZ) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionFriezeGroupSpinhopBlendClampZ,1,1,false,FnStructure) virtual const XYZ evaluate(const XYZ& p) const { return FriezegroupBlend(arg(0),p,SpinhopBlend(1.0),ClampZ(param(0))); } FUNCTION_END(FunctionFriezeGroupSpinhopBlendClampZ) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionFriezeGroupSpinhopBlendFreeZ,0,1,false,FnStructure) virtual const XYZ evaluate(const XYZ& p) const { return FriezegroupBlend(arg(0),p,SpinhopBlend(1.0),FreeZ()); } FUNCTION_END(FunctionFriezeGroupSpinhopBlendFreeZ) //------------------------------------------------------------------------------------------ /* FUNCTION_BEGIN(FunctionFriezeGroupSpinhopCutClampZ,2,2,false,FnStructure) virtual const XYZ evaluate(const XYZ& p) const { const int d=SpinhopCut(1.0)(arg(1),p,ClampZ(param(1))); return FriezegroupEvaluate(arg(0),p,Spinhop(1.0,d),ClampZ(param(0))); } FUNCTION_END(FunctionFriezeGroupSpinhopCutClampZ) */ //------------------------------------------------------------------------------------------ /* FUNCTION_BEGIN(FunctionFriezeGroupSpinhopCutFreeZ,0,2,false,FnStructure) virtual const XYZ evaluate(const XYZ& p) const { const int d=SpinhopCut(1.0)(arg(1),p,FreeZ()); return FriezegroupEvaluate(arg(0),p,Spinhop(1.0,d),FreeZ()); } FUNCTION_END(FunctionFriezeGroupSpinhopCutFreeZ) */ //------------------------------------------------------------------------------------------ #endif evolvotron-0.8.3/libfunction/functions_friezegroup_spinhop.cpp0000644000175000017500000000302615230700302023605 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation for FunctionFriezeGroupSpinhop functions. */ #include "function_boilerplate_instantiate.h" #include "functions_friezegroup_spinhop.h" evolvotron-0.8.3/libfunction/functions_friezegroup_sidle.h0000644000175000017500000000457615230700302022705 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for specific Function classes. */ #ifndef _functions_friezegroup_sidle_h_ #define _functions_friezegroup_sidle_h_ #include "useful.h" #include "function_boilerplate.h" #include "friezegroup.h" //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionFriezeGroupSidleFreeZ,0,1,false,FnStructure) virtual const XYZ evaluate(const XYZ& p) const { return FriezegroupEvaluate(arg(0),p,Sidle(1.0),FreeZ()); } FUNCTION_END(FunctionFriezeGroupSidleFreeZ) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionFriezeGroupSidleClampZ,1,1,false,FnStructure) virtual const XYZ evaluate(const XYZ& p) const { return FriezegroupEvaluate(arg(0),p,Sidle(1.0),ClampZ(param(0))); } FUNCTION_END(FunctionFriezeGroupSidleClampZ) //------------------------------------------------------------------------------------------ #endif evolvotron-0.8.3/libfunction/functions_friezegroup_sidle.cpp0000644000175000017500000000310715230700302023225 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of specific Function classes. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "functions_friezegroup_sidle.h" evolvotron-0.8.3/libfunction/functions_friezegroup_jump.h0000644000175000017500000000757315230700302022560 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for specific Function classes. */ #ifndef _functions_friezegroup_jump_h_ #define _functions_friezegroup_jump_h_ #include "useful.h" #include "function_boilerplate.h" #include "friezegroup.h" //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionFriezeGroupJumpFreeZ,0,1,false,FnStructure) virtual const XYZ evaluate(const XYZ& p) const { return FriezegroupEvaluate(arg(0),p,Jump(1.0),FreeZ()); } FUNCTION_END(FunctionFriezeGroupJumpFreeZ) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionFriezeGroupJumpClampZ,1,1,false,FnStructure) virtual const XYZ evaluate(const XYZ& p) const { return FriezegroupEvaluate(arg(0),p,Jump(1.0),ClampZ(param(0))); } FUNCTION_END(FunctionFriezeGroupJumpClampZ) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionFriezeGroupJumpBlendClampZ,1,2,false,FnStructure) virtual const XYZ evaluate(const XYZ& p) const { return FriezegroupBlend(arg(0),arg(1),p,JumpBlend(1.0),ClampZ(param(0))); } FUNCTION_END(FunctionFriezeGroupJumpBlendClampZ) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionFriezeGroupJumpBlendFreeZ,0,2,false,FnStructure) virtual const XYZ evaluate(const XYZ& p) const { return FriezegroupBlend(arg(0),arg(1),p,JumpBlend(1.0),FreeZ()); } FUNCTION_END(FunctionFriezeGroupJumpBlendFreeZ) //------------------------------------------------------------------------------------------ /* FUNCTION_BEGIN(FunctionFriezeGroupJumpCutClampZ,2,2,false,FnStructure) virtual const XYZ evaluate(const XYZ& p) const { const int d=FriezegroupCut(arg(1),p,JumpCut(1.0),ClampZ(param(1))); return FriezegroupEvaluate(arg(0),p,Jump(1.0,d),ClampZ(param(0))); } FUNCTION_END(FunctionFriezeGroupJumpCutClampZ) */ //------------------------------------------------------------------------------------------ /* FUNCTION_BEGIN(FunctionFriezeGroupJumpCutFreeZ,0,2,false,FnStructure) virtual const XYZ evaluate(const XYZ& p) const { const int d=FriezegroupCut(arg(1),p,JumpCut(1.0),FreeZ()); return FriezegroupEvaluate(arg(0),p,Jump(1.0,d),FreeZ()); } FUNCTION_END(FunctionFriezeGroupJumpCutFreeZ) */ //------------------------------------------------------------------------------------------ #endif evolvotron-0.8.3/libfunction/functions_friezegroup_jump.cpp0000644000175000017500000000310615230700302023077 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of specific Function classes. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "functions_friezegroup_jump.h" evolvotron-0.8.3/libfunction/functions_friezegroup_hop.h0000644000175000017500000000754515230700302022372 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for specific Function classes. */ #ifndef _functions_friezegroup_hop_h_ #define _functions_friezegroup_hop_h_ #include "useful.h" #include "function_boilerplate.h" #include "friezegroup.h" //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionFriezeGroupHopFreeZ,0,1,false,FnStructure) virtual const XYZ evaluate(const XYZ& p) const { return FriezegroupEvaluate(arg(0),p,Hop(1.0),FreeZ()); } FUNCTION_END(FunctionFriezeGroupHopFreeZ) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionFriezeGroupHopClampZ,1,1,false,FnStructure) virtual const XYZ evaluate(const XYZ& p) const { return FriezegroupEvaluate(arg(0),p,Hop(1.0),ClampZ(param(0))); } FUNCTION_END(FunctionFriezeGroupHopClampZ) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionFriezeGroupHopBlendClampZ,1,2,false,FnStructure) virtual const XYZ evaluate(const XYZ& p) const { return FriezegroupBlend(arg(0),arg(1),p,HopBlend(1.0),ClampZ(param(0))); } FUNCTION_END(FunctionFriezeGroupHopBlendClampZ) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionFriezeGroupHopBlendFreeZ,0,2,false,FnStructure) virtual const XYZ evaluate(const XYZ& p) const { return FriezegroupBlend(arg(0),arg(1),p,HopBlend(1.0),FreeZ()); } FUNCTION_END(FunctionFriezeGroupHopBlendFreeZ) //------------------------------------------------------------------------------------------ /* FUNCTION_BEGIN(FunctionFriezeGroupHopCutClampZ,2,2,false,FnStructure) virtual const XYZ evaluate(const XYZ& p) const { const int d=FriezegroupCut(arg(1),p,HopCut(1.0),ClampZ(param(1))); return FriezegroupEvaluate(arg(0),p,Hop(1.0,d),ClampZ(param(0))); } FUNCTION_END(FunctionFriezeGroupHopCutClampZ) */ //------------------------------------------------------------------------------------------ /* FUNCTION_BEGIN(FunctionFriezeGroupHopCutFreeZ,0,2,false,FnStructure) virtual const XYZ evaluate(const XYZ& p) const { const int d=FriezegroupCut(arg(1),p,HopCut(1.0),FreeZ()); return FriezegroupEvaluate(arg(0),p,Hop(1.0,d),FreeZ()); } FUNCTION_END(FunctionFriezeGroupHopCutFreeZ) */ //------------------------------------------------------------------------------------------ #endif evolvotron-0.8.3/libfunction/functions_friezegroup_hop.cpp0000644000175000017500000000300415230700302022707 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation for FunctionFriezeGroupHop */ #include "function_boilerplate_instantiate.h" #include "functions_friezegroup_hop.h" evolvotron-0.8.3/libfunction/functions_filter.h0000644000175000017500000001607015230700302020441 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for specific Function classes. As much as possible of the implementation should be pushed into the FunctionBoilerplate template. */ #ifndef _functions_filter_h_ #define _functions_filter_h_ #include "useful.h" #include "function_boilerplate.h" //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionFilter2D,2,1,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { return arg(0)(p) -( arg(0)(p+XYZ(param(0),0.0,0.0)) +arg(0)(p+XYZ(-param(0),0.0,0.0)) +arg(0)(p+XYZ(0.0,param(1),0.0)) +arg(0)(p+XYZ(0.0,-param(1),0.0)) )/4.0; } FUNCTION_END(FunctionFilter2D) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionFilter3D,3,1,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { return arg(0)(p) -( arg(0)(p+XYZ(param(0),0.0,0.0)) +arg(0)(p+XYZ(-param(0),0.0,0.0)) +arg(0)(p+XYZ(0.0,param(1),0.0)) +arg(0)(p+XYZ(0.0,-param(1),0.0)) +arg(0)(p+XYZ(0.0,0.0,param(2))) +arg(0)(p+XYZ(0.0,0.0,-param(2))) )/6.0; } FUNCTION_END(FunctionFilter3D) //------------------------------------------------------------------------------------------ //! Function returning average value of evenly spaced samples between two points FUNCTION_BEGIN(FunctionAverageSamples,3,1,true,FnIterative) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const XYZ baseline(param(0),param(1),param(2)); XYZ p0; XYZ p1; XYZ delta; if (iterations()==1) { p0=p; p1=p; delta=XYZ(0.0,0.0,0.0); } else { // In the case of two iterations the samples will be at p0 and p1 p0=p-baseline; p1=p+baseline; delta=(p1-p0)/(iterations()-1); } XYZ ret(0.0,0.0,0.0); XYZ ps=p0; for (uint i=0;i(i)/iterations(); ret+=k*arg(0)(ps); w+=k; ps+=delta; } ret/=w; return ret; } FUNCTION_END(FunctionStreak) //------------------------------------------------------------------------------------------ //! Average of samples around a ring FUNCTION_BEGIN(FunctionAverageRing,1,1,true,FnIterative) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { if (iterations()==1) return arg(0)(p); const real da=2.0*M_PI/iterations(); XYZ ret(0.0,0.0,0.0); for (uint i=0;i. */ /**************************************************************************/ /*! \file \brief Implementation of specific Function classes. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "functions_filter.h" evolvotron-0.8.3/libfunction/functions_choose.h0000644000175000017500000002502615230700302020435 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for specific Function classes. As much as possible of the implementation should be pushed into the FunctionBoilerplate template. */ #ifndef _functions_choose_h_ #define _functions_choose_h_ #include "useful.h" #include "function_boilerplate.h" #include "hex.h" //------------------------------------------------------------------------------------------ // Strip of one function across another FUNCTION_BEGIN(FunctionChooseStrip,3,3,false,FnStructure) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { if (fabs(p.y()) > fabs(arg(2)(p)%XYZ(param(0),param(1),param(2)))) return arg(1)(p); else return arg(0)(p); } FUNCTION_END(FunctionChooseStrip) //------------------------------------------------------------------------------------------ // Strip of one function across another FUNCTION_BEGIN(FunctionChooseStripBlend,6,4,false,FnStructure) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const real r0=fabs(arg(2)(p)%XYZ(param(0),param(1),param(2))); const real r1=fabs(arg(3)(p)%XYZ(param(3),param(4),param(5))); const real inner=std::min(r0,r1); const real outer=std::max(r0,r1); const real ay=fabs(p.y()); if (ay<=inner) return arg(0)(p); if (ay>=outer) return arg(1)(p); const XYZ v0(arg(0)(p)); const XYZ v1(arg(1)(p)); return v0+(v1-v0)*(ay-inner)/(outer-inner); } FUNCTION_END(FunctionChooseStripBlend) //------------------------------------------------------------------------------------------ //! Function implements selection between 2 functions based on the relative magnitudes of 2 other functions FUNCTION_BEGIN(FunctionChooseSphere,0,4,false,FnStructure) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { if ((arg(0)(p)).magnitude2()<(arg(1)(p)).magnitude2()) return arg(2)(p); else return arg(3)(p); } FUNCTION_END(FunctionChooseSphere) //------------------------------------------------------------------------------------------ //! Function implements selection between 2 functions based on whether a rectangle contains a point FUNCTION_BEGIN(FunctionChooseRect,0,4,false,FnStructure) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const XYZ p0(arg(0)(p)); const XYZ p1(arg(1)(p)); if (p1.origin_centred_rect_contains(p0)) return arg(2)(p); else return arg(3)(p); } FUNCTION_END(FunctionChooseRect) //------------------------------------------------------------------------------------------ //! Function implements selection between 2 functions based on position in 3d mesh FUNCTION_BEGIN(FunctionChooseFrom2InCubeMesh,0,2,false,FnStructure) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const int x=static_cast(floorf(p.x())); const int y=static_cast(floorf(p.y())); const int z=static_cast(floorf(p.z())); if ((x+y+z)&1) return arg(0)(p); else return arg(1)(p); } FUNCTION_END(FunctionChooseFrom2InCubeMesh); //------------------------------------------------------------------------------------------ //! Function implements selection between 2 functions based on position in 3d mesh FUNCTION_BEGIN(FunctionChooseFrom3InCubeMesh,0,3,false,FnStructure) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const int x=static_cast(floorf(p.x())); const int y=static_cast(floorf(p.y())); const int z=static_cast(floorf(p.z())); return arg(modulusi(x+y+z,3))(p); } FUNCTION_END(FunctionChooseFrom3InCubeMesh) //------------------------------------------------------------------------------------------ //! Function implements selection between 2 functions based on position in 2d grid FUNCTION_BEGIN(FunctionChooseFrom2InSquareGrid,0,2,false,FnStructure) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const int x=static_cast(floorf(p.x())); const int y=static_cast(floorf(p.y())); if ((x+y)&1) return arg(0)(p); else return arg(1)(p); } FUNCTION_END(FunctionChooseFrom2InSquareGrid) //------------------------------------------------------------------------------------------ //! Function implements selection between 3 functions based on position in 2d grid FUNCTION_BEGIN(FunctionChooseFrom3InSquareGrid,0,3,false,FnStructure) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const int x=static_cast(floorf(p.x())); const int y=static_cast(floorf(p.y())); return arg(modulusi(x+y,3))(p); } FUNCTION_END(FunctionChooseFrom3InSquareGrid) //------------------------------------------------------------------------------------------ //! Function implements selection between 2 functions based on position in grid of triangles FUNCTION_BEGIN(FunctionChooseFrom2InTriangleGrid,0,2,false,FnStructure) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { static const XYZ d0(1.0 ,0.0 ,0.0); static const XYZ d1(cos( M_PI/3),sin( M_PI/3),0.0); static const XYZ d2(cos(2*M_PI/3),sin(2*M_PI/3),0.0); const int a=static_cast(floorf(p%d0)); const int b=static_cast(floorf(p%d1)); const int c=static_cast(floorf(p%d2)); if ((a+b+c)&1) return arg(0)(p); else return arg(1)(p); } FUNCTION_END(FunctionChooseFrom2InTriangleGrid) //------------------------------------------------------------------------------------------ //! Function implements selection between 2 functions based on position in grid of triangles /*! Not entirely sure this one produces a sensible pattern. Needs explicitly testing. */ FUNCTION_BEGIN(FunctionChooseFrom3InTriangleGrid,0,3,false,FnStructure) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { static const XYZ d0(1.0 ,0.0 ,0.0); static const XYZ d1(cos( M_PI/3),sin( M_PI/3),0.0); static const XYZ d2(cos(2*M_PI/3),sin(2*M_PI/3),0.0); const int a=static_cast(floorf(p%d0)); const int b=static_cast(floorf(p%d1)); const int c=static_cast(floorf(p%d2)); return arg(modulusi(a+b+c,3))(p); } FUNCTION_END(FunctionChooseFrom3InTriangleGrid) //------------------------------------------------------------------------------------------ //! Function implements selection between 3 functions based on position in grid of hexagons /*! Don't entirely understand how this works, but it looks nice. */ FUNCTION_BEGIN(FunctionChooseFrom3InDiamondGrid,0,3,false,FnStructure) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { // Basis vectors for hex grid static const XYZ d0(1.0 ,0.0 ,0.0); static const XYZ d1(cos( M_PI/3),sin( M_PI/3),0.0); static const XYZ d2(cos(2*M_PI/3),sin(2*M_PI/3),0.0); // Dot with basis const real p0=p%d0; const real p1=p%d1; const real p2=p%d2; // Find nearest on-grid point const int i0=(int)floorf(p0+0.5); const int i1=(int)floorf(p1+0.5); const int i2=(int)floorf(p2+0.5); // Measure distance const real m0=fabsf(p0-i0); const real m1=fabsf(p1-i1); const real m2=fabsf(p2-i2); // Closest one decides which function if (m0<=m1 && m0<=m2) return arg(0)(p); else if (m1<=m0 && m1<=m2) return arg(1)(p); else return arg(2)(p); } FUNCTION_END(FunctionChooseFrom3InDiamondGrid) //------------------------------------------------------------------------------------------ //! Function implements selection between 3 functions based on position in grid of hexagons FUNCTION_BEGIN(FunctionChooseFrom3InHexagonGrid,0,3,false,FnStructure) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const std::pair h=nearest_hex(p.x(),p.y()); const uint which=h.second+((h.first&1)? 2 : 0); return arg(modulusi(which,3))(p); } FUNCTION_END(FunctionChooseFrom3InHexagonGrid) //------------------------------------------------------------------------------------------ //! Function implements selection between 2 functions based on position in grid of hexagons FUNCTION_BEGIN(FunctionChooseFrom2InBorderedHexagonGrid,1,2,false,FnStructure) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const std::pair h=nearest_hex(p.x(),p.y()); bool in_border=false; // Hex centres are separated by 1.0 so limit border size const real b=modulusf(param(0),0.5); // Step along grid co-ordinates in various directions. If there's a nearer point, we're in the border. for (uint i=0;i<6;i++) { const real dx=b*sin(i*M_PI/3.0); const real dy=b*cos(i*M_PI/3.0); const std::pair a=nearest_hex(p.x()+dx,p.y()+dy); if (h!=a) { in_border=true; break; } } return arg(in_border)(p); } FUNCTION_END(FunctionChooseFrom2InBorderedHexagonGrid) //------------------------------------------------------------------------------------------ #endif evolvotron-0.8.3/libfunction/functions_choose.cpp0000644000175000017500000000307315230700302020766 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of specific Function classes. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "functions_choose.h" evolvotron-0.8.3/libfunction/functions_arithmetic.h0000644000175000017500000001232315230700302021302 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for specific Function classes. As much as possible of the implementation should be pushed into the FunctionBoilerplate template. */ #ifndef _functions_arithmetic_h_ #define _functions_arithmetic_h_ #include "useful.h" #include "function_boilerplate.h" //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionAdd,0,2,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { return arg(0)(p)+arg(1)(p); } FUNCTION_END(FunctionAdd) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionMultiply,0,2,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const XYZ v0(arg(0)(p)); const XYZ v1(arg(1)(p)); // NB Don't use v0*v1 as it would be cross-product. return XYZ(v0.x()*v1.x(),v0.y()*v1.y(),v0.z()*v1.z()); } FUNCTION_END(FunctionMultiply) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionDivide,0,2,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const XYZ v0(arg(0)(p)); const XYZ v1(arg(1)(p)); return XYZ( (v1.x()==0.0 ? 0.0 : v0.x()/v1.x()), (v1.y()==0.0 ? 0.0 : v0.y()/v1.y()), (v1.z()==0.0 ? 0.0 : v0.z()/v1.z()) ); } FUNCTION_END(FunctionDivide) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionMax,0,2,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const XYZ v0(arg(0)(p)); const XYZ v1(arg(1)(p)); return XYZ( std::max(v0.x(),v1.x()), std::max(v0.y(),v1.y()), std::max(v0.z(),v1.z()) ); } FUNCTION_END(FunctionMax) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionMin,0,2,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const XYZ v0(arg(0)(p)); const XYZ v1(arg(1)(p)); return XYZ( std::min(v0.x(),v1.x()), std::min(v0.y(),v1.y()), std::min(v0.z(),v1.z()) ); } FUNCTION_END(FunctionMin) //------------------------------------------------------------------------------------------ //! Function returning components of one function modulus thos of another. /*! Sane always-positive modulus used to avoid funny business at zero. */ FUNCTION_BEGIN(FunctionModulus,0,2,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { const XYZ v0(arg(0)(p)); const XYZ v1(arg(1)(p)); return XYZ( modulusf(v0.x(),fabs(v1.x())), modulusf(v0.y(),fabs(v1.y())), modulusf(v0.z(),fabs(v1.z())) ); } FUNCTION_END(FunctionModulus) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionExp,0,0,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { return XYZ(exp(p.x()),exp(p.y()),exp(p.z())); } FUNCTION_END(FunctionExp) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionSin,0,0,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { return XYZ(sin(p.x()),sin(p.y()),sin(p.z())); } FUNCTION_END(FunctionSin) //------------------------------------------------------------------------------------------ FUNCTION_BEGIN(FunctionCos,0,0,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { return XYZ(cos(p.x()),cos(p.y()),cos(p.z())); } FUNCTION_END(FunctionCos) //------------------------------------------------------------------------------------------ #endif evolvotron-0.8.3/libfunction/functions_arithmetic.cpp0000644000175000017500000000307715230700302021643 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of specific Function classes. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "functions_arithmetic.h" evolvotron-0.8.3/libfunction/function_transform_generalised.h0000644000175000017500000000365515230700302023353 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for FunctionTransformGeneralised */ #ifndef _function_transform_generalised_h_ #define _function_transform_generalised_h_ #include "useful.h" #include "function_boilerplate.h" #include "transform.h" FUNCTION_BEGIN(FunctionTransformGeneralised,0,4,false,0) //! Return the transformed position argument. virtual const XYZ evaluate(const XYZ& p) const { const Transform transform(arg(0)(p),arg(1)(p),arg(2)(p),arg(3)(p)); return transform.transformed(p); } FUNCTION_END(FunctionTransformGeneralised) #endif evolvotron-0.8.3/libfunction/function_transform_generalised.cpp0000644000175000017500000000312315230700302023674 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of FunctionTransformGeneralised class. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "function_transform_generalised.h" evolvotron-0.8.3/libfunction/function_transform.h0000644000175000017500000000416215230700302021003 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for specific Function class. */ #ifndef _function_transform_h_ #define _function_transform_h_ #include "useful.h" #include "function_boilerplate.h" #include "transform.h" //------------------------------------------------------------------------------------------ //! Function class returning position transfomed by a 12-component linear transform. FUNCTION_BEGIN(FunctionTransform,12,0,false,FnCore) //! Return the transformed position argument. virtual const XYZ evaluate(const XYZ& p) const { const Transform transform(params()); return transform.transformed(p); } FUNCTION_END(FunctionTransform) //------------------------------------------------------------------------------------------ #endif evolvotron-0.8.3/libfunction/function_transform.cpp0000644000175000017500000000307515230700302021340 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of specific Function classes. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "function_transform.h" evolvotron-0.8.3/libfunction/function_top.h0000644000175000017500000000630415230700302017572 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces for class FunctionTop This class would normally live in functions.h (and is included and registered there), but is split out so it can be efficiently used by MutatableImageDisplay and EvolvotronMain. NB There is no class heirarchy here as all virtualisation and boilerplate services are supplied when the functions are plugged into the FunctionNode template */ #ifndef _function_top_h_ #define _function_top_h_ #include "useful.h" #include "function_boilerplate.h" class Transform; //! Function intended primarily to be the top level function node. /*! First 12 parameters are a space transform, second 12 paramters are a colour space transform. */ FUNCTION_BEGIN(FunctionTop,24,1,false,0) public: //! This returns a random tree suitable for use as a starting image. static std::unique_ptr initial(const MutationParameters& parameters,const FunctionRegistration* specific_fn=0,bool unwrapped=false); virtual const XYZ evaluate(const XYZ& p) const; virtual FunctionTop* is_a_FunctionTop() { return this; } virtual const FunctionTop* is_a_FunctionTop() const { return this; } //! Overridden so transform and colours don't keep changing virtual void mutate(const MutationParameters& parameters,bool mutate_own_parameters=true); virtual void concatenate_pretransform_on_right(const Transform& transform); virtual void mutate_pretransform_parameters(const MutationParameters& parameters); virtual void reset_pretransform_parameters(const MutationParameters& parameters); virtual void mutate_posttransform_parameters(const MutationParameters& parameters); virtual void reset_posttransform_parameters(const MutationParameters& parameters); private: const Transform interesting_pretransform(const MutationParameters& parameters,const real k); FUNCTION_END(FunctionTop) #endif evolvotron-0.8.3/libfunction/function_top.cpp0000644000175000017500000001647115230700302020133 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation for FunctionTop */ #include "function_boilerplate_instantiate.h" #include "function_top.h" #include "mutation_parameters.h" #include "transform.h" const XYZ FunctionTop::evaluate(const XYZ& p) const { const Transform space_transform(params(),0); const XYZ sp(space_transform.transformed(p)); const XYZ v(arg(0)(sp)); const XYZ tv(tanh(0.5*v.x()),tanh(0.5*v.y()),tanh(0.5*v.z())); // ...each component of tv is in [-1,1] so the transform parameters define a rhomboid in colour space. const Transform colour_transform(params(),12); return colour_transform.transformed(tv); } std::unique_ptr FunctionTop::initial(const MutationParameters& parameters,const FunctionRegistration* specific_fn,bool unwrapped) { std::unique_ptr fn; do { if (specific_fn) { fn=(*(specific_fn->stubnew_fn))(parameters,true); } else { // This one is crucial: we REALLY want something interesting to happen within here. fn=FunctionNode::stub(parameters,true); } assert(fn->ok()); if (fn->is_constant() && !(specific_fn && specific_fn->name == "FunctionConstant")) { fn.reset(); } } while (!fn.get()); assert(fn->ok()); boost::ptr_vector a; a.push_back(fn.release()); const TransformIdentity ti; std::vector tiv=ti.get_columns(); std::vector p; p.insert(p.end(),tiv.begin(),tiv.end()); p.insert(p.end(),tiv.begin(),tiv.end()); std::unique_ptr fn_top(new FunctionTop(p,a,0)); if (unwrapped) { // For unwrapped just allow a scale factor and scramble colours fn_top->concatenate_pretransform_on_right(TransformScale(parameters.rnegexp())); fn_top->reset_posttransform_parameters(parameters); } else { fn_top->reset_pretransform_parameters(parameters); fn_top->reset_posttransform_parameters(parameters); } return fn_top; } void FunctionTop::mutate(const MutationParameters& parameters,bool mutate_own_parameters) { FunctionNode::mutate(parameters,false); if (mutate_own_parameters) { if (parameters.r01() p(t.get_columns()); for (uint i=0;i<11;i++) params()[i]=p[i]; } void FunctionTop::mutate_posttransform_parameters(const MutationParameters& parameters) { for (uint i=12;i<23;i++) params()[i]+=parameters.effective_magnitude_parameter_variation()*(parameters.r01()<0.5 ? -parameters.rnegexp() : parameters.rnegexp()); } void FunctionTop::reset_posttransform_parameters(const MutationParameters& parameters) { std::vector p; stubparams(p,parameters,12); for (uint i=0;i<11;i++) params()[12+i]=p[i]; } evolvotron-0.8.3/libfunction/function_registry.h0000644000175000017500000000443215230700302020640 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces for class FunctionRegistry. */ #ifndef _function_registry_h_ #define _function_registry_h_ #include "useful.h" #include "function_registration.h" //! Class acting as a dictionary from function name to registration info. /*! Intended to be used as singleton; get() obtains instance. This holds the "definitive" collection of registrations. FunctionRegistrations can be compared using pointer identiy. */ class FunctionRegistry : public std::map { public: FunctionRegistry(); ~FunctionRegistry(); //! Return the registration for the function named (returns 0 if unknown) const FunctionRegistration* lookup(const std::string& f) const; //! Dump list of registered functions std::ostream& status(std::ostream& out) const; //! Register a function. Handles duplicates gracefully. bool register_function(FunctionRegistration* r); }; #endif evolvotron-0.8.3/libfunction/function_registry.cpp0000644000175000017500000000472015230700302021173 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation for class FunctionRegistry and associated classes. */ #include "function_registry.h" #include "register_all_functions.h" FunctionRegistry::FunctionRegistry() { register_all_functions(*this); std::clog << "FunctionRegistry created\n"; } FunctionRegistry::~FunctionRegistry() { for (iterator it = begin(); it != end(); it++) delete it->second; std::clog << "FunctionRegistry destroyed\n"; } //! Return the registration for the function named (returns 0 if unknown) const FunctionRegistration* FunctionRegistry::lookup(const std::string& f) const { const_iterator it = find(f); if (it == end()) return 0; else return it->second; } std::ostream& FunctionRegistry::status(std::ostream& out) const { out << "Registered functions:\n"; for (const_iterator it = begin(); it != end(); it++) out << " " << it->first << "\n"; return out; } bool FunctionRegistry::register_function(FunctionRegistration* r) { if (find(r->name) == end()) { (*this)[r->name] = r; return true; } return false; } evolvotron-0.8.3/libfunction/function_registration.h0000644000175000017500000000624415230700302021505 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces for class FunctionRegistration */ #ifndef _function_registration_h_ #define _function_registration_h_ #include "useful.h" class FunctionNode; class FunctionRegistry; class MutationParameters; class FunctionNodeInfo; //! Enum for classification bits enum { FnCore=1, // Constant, Identity or Transform: the 3 zero-child diluting functions FnStructure=2, // Functions which give rise to a lot of structure e.g spirals and grids FnRender=4, // Functions which use rendering algorithms FnIterative=8, // Iterative functions FnFractal=16, // Fractal functions FnClassifications=5 // The number of function classifications defined. }; extern const char*const function_classification_name[FnClassifications]; //! Define FunctionNodeStubNewFnPtr for convenience. typedef std::unique_ptr (*FunctionNodeStubNewFnPtr)(const MutationParameters&,bool); typedef std::unique_ptr (*FunctionNodeCreateFnPtr)(const FunctionRegistry&,const FunctionNodeInfo&,std::string&); //! Holds meta information about functions. struct FunctionRegistration { //! Constructor. FunctionRegistration(const std::string& n,FunctionNodeStubNewFnPtr fs,FunctionNodeCreateFnPtr fc,uint np,uint na,bool i,uint fnc) : name(n) ,stubnew_fn(fs) ,create_fn(fc) ,params(np) ,args(na) ,iterative(i) ,classification(fnc) {} //! Name of the function. std::string name; //! The FunctionNodeUsing's stubnew function. FunctionNodeStubNewFnPtr stubnew_fn; //! The FunctionNodeUsing's create function. FunctionNodeCreateFnPtr create_fn; //! Number of parameters uint params; //! Number of arguments uint args; //! Whether iterative bool iterative; //! Classification bits uint classification; }; #endif evolvotron-0.8.3/libfunction/function_registration.cpp0000644000175000017500000000313715230700302022036 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation for class FunctionRegistration */ #include "function_registration.h" const char*const function_classification_name[FnClassifications]= { "Core", "Structure", "Render", "Iterative", "Fractal" }; evolvotron-0.8.3/libfunction/function_pre_transform.h0000644000175000017500000000450315230700302021650 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces for class FunctionPreTransform This class would normally live in functions.h (and is included and registered there), but is split out so it can be efficiently used by MutatableImageDisplay and EvolvotronMain. NB There is no class heirarchy here as all virtualisation and boilerplate services are supplied when the functions are plugged into the FunctionNode template. */ #ifndef _function_pre_transform_h_ #define _function_pre_transform_h_ #include "useful.h" #include "function_boilerplate.h" #include "transform.h" //! Function class returning leaf node evaluated at position transfomed by a 12-component linear transform. FUNCTION_BEGIN(FunctionPreTransform,12,1,false,0) //! Return the evaluation of arg(0) at the transformed position argument. virtual const XYZ evaluate(const XYZ& p) const { const Transform transform(params()); return arg(0)(transform.transformed(p)); } FUNCTION_END(FunctionPreTransform) #endif evolvotron-0.8.3/libfunction/function_pre_transform.cpp0000644000175000017500000000307415230700302022205 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation for FunctionPreTransform Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "function_pre_transform.h" evolvotron-0.8.3/libfunction/function_post_transform.h0000644000175000017500000000453615230700302022055 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces for class FunctionPostTransform This class would normally live in functions.h (and is included and registered there), but is split out so it can be efficiently used by MutatableImageDisplay and EvolvotronMain. NB There is no class heirarchy here as all virtualisation and boilerplate services are supplied when the functions are plugged into the FunctionNode template. */ #ifndef _function_post_transform_h_ #define _function_post_transform_h_ #include "useful.h" #include "function_boilerplate.h" #include "transform.h" //! Function class returning leaf node evaluated at given position; result is then transfomed by a 12-component linear transform. FUNCTION_BEGIN(FunctionPostTransform,12,1,false,0) //! Return the evaluation of arg(0) at the transformed position argument. virtual const XYZ evaluate(const XYZ& p) const { const Transform transform(params()); return transform.transformed(arg(0)(p)); } FUNCTION_END(FunctionPostTransform) #endif evolvotron-0.8.3/libfunction/function_post_transform.cpp0000644000175000017500000000307615230700302022406 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation for FunctionPostTransform Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "function_post_transform.h" evolvotron-0.8.3/libfunction/function_node_info.h0000644000175000017500000000501215230700302020723 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class FunctioNodeInfo. */ #ifndef _function_node_info_h_ #define _function_node_info_h_ #include "useful.h" //! Trivial class used during XML parsing. /*! Encapsulates enough info to build a function tree from */ class FunctionNodeInfo { public: FunctionNodeInfo() :_type("UNKNOWN") ,_iterations(0) {} ~FunctionNodeInfo() {} //! Accessor. const std::string& type() const { return _type; } //! Accessor. void type(const std::string& t) { _type=t; } //! Accessor. const std::vector& params() const { return _params; } //! Accessor. std::vector& params() { return _params; } //! Accessor. const boost::ptr_vector& args() const { return _args; } //! Accessor. boost::ptr_vector& args() { return _args; } //! Accessor. uint iterations() const { return _iterations; } //! Accessor. void iterations(uint i) { _iterations=i; } protected: std::string _type; std::vector _params; boost::ptr_vector _args; uint _iterations; }; #endif evolvotron-0.8.3/libfunction/function_node_info.cpp0000644000175000017500000000271615230700302021266 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation for class FunctioNodeInfo. */ #include "function_node_info.h" evolvotron-0.8.3/libfunction/function_node.h0000644000175000017500000002030515230700302017712 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces for class FunctionNode and derived classes. */ #ifndef _function_node_h_ #define _function_node_h_ #include "useful.h" #include "xy.h" #include "xyz.h" class FunctionNodeInfo; class FunctionTop; class FunctionPreTransform; class FunctionPostTransform; class FunctionRegistry; class MutatableImage; class MutationParameters; class Function : boost::noncopyable { public: virtual ~Function() {} //! Convenience wrapper for evaluate (actually, evaluate is protected so can't be called externally anyway) const XYZ operator()(const XYZ& p) const { return evaluate(p); } //! Weighted evaluate; fastpath for zero weight. const XYZ operator()(const real weight,const XYZ& p) const { return (weight==0.0 ? XYZ(0.0,0.0,0.0) : weight*evaluate(p)); } //! This what distinguishes different types of function. virtual const XYZ evaluate(const XYZ&) const =0; }; //! Abstract base class for all kinds of mutatable image node. /*! MutatableImage declared a friend to help constification of the public accessors. */ class FunctionNode : public Function { public: friend class MutatableImage; private: //! The arguments (ie child nodes) for this node. boost::ptr_vector _args; //! The parameters (ie constant values) for this node. std::vector _params; //! Number of iterations for iterative function types. If zero, indicates non-iterative function. /*! \todo Perhaps someday push this out into a derived class. */ uint _iterations; protected: //! This returns a deep-cloned copy of the node's children. std::unique_ptr > cloneargs() const; //! This returns a copy of the node's parameters const std::vector cloneparams() const; //! Obtain some statistics about the image function void get_stats(uint& total_nodes,uint& total_parameters,uint& depth,uint& width,real& proportion_constant) const; //! Check function info against given number of parameters/arguments/iterative-flag. /*! Return true on success, false on fail with reasons in report string. Mainly for use by derived FunctionBoilerplate template to avoid duplicate code proliferation. */ static bool verify_info(const FunctionNodeInfo& info,unsigned int np,unsigned int na,bool it,std::string& report); //! Build argument list. /*! Return true on success, false on fail with reasons in report string. Mainly for use by derived FunctionBoilerplate template to avoid duplicate code proliferation. */ static bool create_args(const FunctionRegistry&,const FunctionNodeInfo& info,boost::ptr_vector& args,std::string& report); public: //! Returns true if the function is independent of it's position argument. /*! This isn't used for optimisation (which would require FunctionNode to have computation-specific state, which would wreck plans for reference counted deepclone()), but to cull boring constant images on creation. Default implementation (and probably the only sensible one) is constant if all args are constant; no args returns false. */ virtual bool is_constant() const; //! Internal self consistency check. virtual bool ok() const; //! Bits give some classification of the function type virtual uint self_classification() const =0; //@{ //! Query the node as to whether it is a FunctionTop (return null if not). virtual const FunctionTop* is_a_FunctionTop() const; virtual FunctionTop* is_a_FunctionTop(); //@} //! This returns a new random bit of tree. Setting the "exciting" flag avoids basic node types, but only at the top level of the stub tree. static std::unique_ptr stub(const MutationParameters& parameters,bool exciting); //! This returns a vector of random parameter values. static void stubparams(std::vector&,const MutationParameters& parameters,uint n); //! This returns a vector of new random bits of tree. static void stubargs(boost::ptr_vector&,const MutationParameters& parameters,uint n,bool exciting=false); //! Return a suitable starting value for a node's iteration count (assuming it's iterative). static uint stubiterations(const MutationParameters& parameters); //! Constructor given an array of params and args and an iteration count. /*! These MUST be provided; there are no alterative constructors. */ FunctionNode(const std::vector& p,boost::ptr_vector& a,uint iter); //! Build a FunctionNode given a description static std::unique_ptr create(const FunctionRegistry& function_registry,const FunctionNodeInfo& info,std::string& report); //! Destructor. virtual ~FunctionNode(); //! Accessor void params(const std::vector& p) { _params=p; } //! Accessor. const std::vector& params() const { return _params; } //! Accessor. real param(uint n) const { assert(n& args() const { return _args; } //! Accessor. void args(boost::ptr_vector& a) { _args=a.release(); } //! Accessor. const FunctionNode& arg(uint n) const { assert(n deepclone() const =0; //! Prune any is_constant() nodes and replace them with an actual constant node virtual void simplify_constants(); //! Return a deepcloned copy of the node's arguments virtual std::unique_ptr > deepclone_args() const; //! Save the function tree. virtual std::ostream& save_function(std::ostream& out,uint indent) const =0; protected: //! Save the function tree. Common code needing a function name. std::ostream& save_function(std::ostream& out,uint indent,const std::string& function_name) const; //! Accessor (non-const). boost::ptr_vector& args() { return _args; } //! Accessor (non-const). std::vector& params() { return _params; } //! Accessor. FunctionNode& arg(uint n) { assert(n. */ /**************************************************************************/ /*! \file \brief Implementation of class FunctionNode and derived classes. */ #include "function_node.h" #include "function_compose_pair.h" #include "function_constant.h" #include "function_node_info.h" #include "function_registry.h" #include "margin.h" #include "mutation_parameters.h" std::unique_ptr > FunctionNode::cloneargs() const { std::unique_ptr > ret(new boost::ptr_vector()); for (boost::ptr_vector::const_iterator it=args().begin();it!=args().end();it++) { ret->push_back(it->deepclone().release()); } return ret; } const std::vector FunctionNode::cloneparams() const { return params(); } //! Obtain some statistics about the image function void FunctionNode::get_stats(uint& total_nodes,uint& total_parameters,uint& depth,uint& width,real& proportion_constant) const { uint total_sub_nodes=0; uint total_sub_parameters=0; uint max_sub_depth=0; uint total_sub_width=0; real sub_constants=0.0; // Traverse child nodes. Need to reconstruct the actual numbers from the proportions for (boost::ptr_vector::const_iterator it=args().begin();it!=args().end();it++) { uint sub_nodes; uint sub_parameters; uint sub_depth; uint sub_width; real sub_proportion_constant; it->get_stats(sub_nodes,sub_parameters,sub_depth,sub_width,sub_proportion_constant); total_sub_nodes+=sub_nodes; total_sub_parameters+=sub_parameters; if (sub_depth>max_sub_depth) max_sub_depth=sub_depth; total_sub_width+=sub_width; sub_constants+=sub_nodes*sub_proportion_constant; } // And add our own details total_nodes=1+total_sub_nodes; total_parameters=params().size()+total_sub_parameters; depth=1+max_sub_depth; if (total_sub_width==0) { width=1; } else { width=total_sub_width; } if (is_constant()) { proportion_constant=1.0; } else { proportion_constant=sub_constants/(1+total_sub_nodes); } } bool FunctionNode::verify_info(const FunctionNodeInfo& info,unsigned int np,unsigned int na,bool it,std::string& report) { if (info.params().size()!=np) { std::stringstream msg; msg << "Error: For function " << info.type() << ": expected " << np << " parameters, but found " << info.params().size() << "\n"; report+=msg.str(); return false; } if (info.args().size()!=na) { std::stringstream msg; msg << "Error: For function " << info.type() << ": expected " << na << " arguments, but found " << info.args().size() << "\n"; report+=msg.str(); return false; } if (info.iterations()!=0 && !it) { std::stringstream msg; msg << "Error: For function " << info.type() << ": unexpected iteration count\n"; report+=msg.str(); return false; } if (info.iterations()==0 && it) { std::stringstream msg; msg << "Error: For function " << info.type() << ": expected iteration count but none found\n"; report+=msg.str(); return false; } return true; } bool FunctionNode::is_constant() const { if (args().empty()) return false; for (unsigned int i=0;i::const_iterator it=args().begin();good && it!=args().end();it++) { good=(*it).ok(); } return good; } bool FunctionNode::create_args(const FunctionRegistry& function_registry,const FunctionNodeInfo& info,boost::ptr_vector& args,std::string& report) { for (boost::ptr_vector::const_iterator it=info.args().begin();it!=info.args().end();it++) { std::unique_ptr fn(FunctionNode::create(function_registry,*it,report)); // Check whether something has gone wrong. If it has, delete everything allocated so far and return false. if (!fn.get()) { args.clear(); return false; } args.push_back(fn.release()); } return true; } std::unique_ptr FunctionNode::stub(const MutationParameters& parameters,bool exciting) { return parameters.random_function_stub(exciting); } /*! This setus up a vector of random bits of stub, used for initialiing nodes with children. */ void FunctionNode::stubargs(boost::ptr_vector& v,const MutationParameters& parameters,uint n,bool exciting) { assert(v.empty()); for (uint i=0;i& v,const MutationParameters& parameters,uint n) { assert(v.empty()); for (uint i=0;i(floor(parameters.r01()*parameters.max_initial_iterations())); } FunctionNode::FunctionNode(const std::vector& p,boost::ptr_vector& a,uint iter) :_args(a.release()) ,_params(p) ,_iterations(iter) {} /*! Returns null ptr if there's a problem, in which case there will be an explanation in report. */ std::unique_ptr FunctionNode::create(const FunctionRegistry& function_registry,const FunctionNodeInfo& info,std::string& report) { const FunctionRegistration*const reg=function_registry.lookup(info.type()); if (reg) { return std::unique_ptr((*(reg->create_fn))(function_registry,info,report)); } else { report+="Error: Unrecognised function name: "+info.type()+"\n"; return std::unique_ptr(); } } /*! Deletes all arguments. No one else should be referencing nodes except the root node of an image. */ FunctionNode::~FunctionNode() {} /*! There are 2 kinds of mutation: - random adjustments to constants - structural mutations (messing with the function tree) For structural mutations the obvious things to do are: - reordering argsuments - dropping argsuments and replacing them with new "stubs". - duplicating arguments - substituting nodes with other types (can't do this for ourself very easily, but we can do it for children) - inserting new nodes between children and ourself And of course all children have to be mutated too. */ void FunctionNode::mutate(const MutationParameters& parameters,bool mutate_own_parameters) { // First mutate all child nodes. for (boost::ptr_vector::iterator it=args().begin();it!=args().end();it++) it->mutate(parameters); // Perturb any parameters we have if (mutate_own_parameters) { if (parameters.r01() p; stubparams(p,parameters,params().size()); params(p); } else { for (std::vector::iterator it=params().begin();it!=params().end();it++) { (*it)+=parameters.effective_magnitude_parameter_variation()*(parameters.r01()<0.5 ? -parameters.rnegexp() : parameters.rnegexp()); } } } // Perturb iteration count if any if (_iterations) { if (parameters.r01()=2) _iterations--; } else { _iterations++; } if (parameters.r01()1) _iterations=(_iterations+1)/2; } else { _iterations*=2; } } // For safety but shouldn't happen if (_iterations==0) _iterations=1; } } // Then go to work on the argument structure... // Think about glitching some nodes. for (uint i=0;i > a(args()[i].deepclone_args()); std::vector p(args()[i].params()); // Replace the node with something interesting (maybe this should depend on how complex the original node was) args().replace(i,stub(parameters,false).release()); FunctionNode& it=args()[i]; // Do we need some extra arguments ? if (a->size() xa; stubargs(xa,parameters,it.args().size()-a->size()); a->transfer(a->end(),xa.begin(),xa.end(),xa); } // Shuffle them random_shuffle(*a,parameters.rng01()); // Have we got too many arguments ? while (a->size()>it.args().size()) { a->pop_back(); } // Do we need some extra parameters ? if (p.size() xp; stubparams(xp,parameters,it.params().size()-p.size()); p.insert(p.end(),xp.begin(),xp.end()); } // Shuffle them random_shuffle(p,parameters.rng01()); // Have we go too many arguments ? while (p.size()>it.params().size()) { p.pop_back(); } // Impose the new parameters and arguments on the new node (iterations not touched) it.args(*a); it.params()=p; } } // Think about randomising child order if (parameters.r01() a; a.transfer(a.begin(),args().begin()+i,args()); a.push_back(stub(parameters,false).release()); std::vector p; args().insert(args().begin()+i,new FunctionComposePair(p,a,0)); } } } void FunctionNode::simplify_constants() { for (uint i=0;i vp; vp.push_back(v.x()); vp.push_back(v.y()); vp.push_back(v.z()); boost::ptr_vector va; std::unique_ptr replacement(new FunctionConstant(vp,va,0)); args().replace(i,replacement.release()); } else { args()[i].simplify_constants(); } } } std::unique_ptr > FunctionNode::deepclone_args() const { std::unique_ptr > ret(new boost::ptr_vector()); for (boost::ptr_vector::const_iterator it=args().begin();it!=args().end();it++) ret->push_back(it->deepclone().release()); return ret; } const FunctionTop* FunctionNode::is_a_FunctionTop() const { return 0; } FunctionTop* FunctionNode::is_a_FunctionTop() { return 0; } /*! This function only saves the parameters, iteration count if any and child nodes. It is intended to be called from save_function of subclasses which will write a function node wrapper. The indent number is just the level of recursion, incrementing by 1 each time. Outputting multiple spaces per level is handled by the Margin class. */ std::ostream& FunctionNode::save_function(std::ostream& out,uint indent,const std::string& function_name) const { out << Margin(indent) << "\n"; out << Margin(indent+1) << "" << function_name << "\n"; if (iterations()!=0) out << Margin(indent+1) << "" << iterations() << "\n"; for (std::vector::const_iterator it=params().begin();it!=params().end();it++) { out << Margin(indent+1) << "

" << (*it) << "

\n"; } for (boost::ptr_vector::const_iterator it=args().begin();it!=args().end();it++) { (*it).save_function(out,indent+1); } out << Margin(indent) << "\n"; return out; } evolvotron-0.8.3/libfunction/function_identity.h0000644000175000017500000000410615230700302020617 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for certain core Function classes. Split out from functions.h as included in mutation_parameters.cpp */ #ifndef _function_identity_h_ #define _function_identity_h_ #include "useful.h" #include "function_boilerplate.h" //------------------------------------------------------------------------------------------ //! Function class simply returning the position argument. FUNCTION_BEGIN(FunctionIdentity,0,0,false,FnCore) //! Simply return the position argument. virtual const XYZ evaluate(const XYZ& p) const { return p; } FUNCTION_END(FunctionIdentity) //------------------------------------------------------------------------------------------ #endif evolvotron-0.8.3/libfunction/function_identity.cpp0000644000175000017500000000307415230700302021155 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of specific Function classes. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "function_identity.h" evolvotron-0.8.3/libfunction/function_constant.h0000644000175000017500000000434015230700302020617 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for specific Function class. */ #ifndef _function_constant_h_ #define _function_constant_h_ #include "useful.h" #include "function_boilerplate.h" //------------------------------------------------------------------------------------------ //! Function class representing a constant value. FUNCTION_BEGIN(FunctionConstant,3,0,false,FnCore) //! Returns the constant value virtual const XYZ evaluate(const XYZ&) const { return XYZ(param(0),param(1),param(2)); } //! Returns true, obviously. /*! One of the few cases this method is overriden; most (all?) other no-argument functions should return false */ virtual bool is_constant() const { return true; } FUNCTION_END(FunctionConstant) //------------------------------------------------------------------------------------------ #endif evolvotron-0.8.3/libfunction/function_constant.cpp0000644000175000017500000000307415230700302021155 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of specific Function classes. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "function_constant.h" evolvotron-0.8.3/libfunction/function_compose_triple.h0000644000175000017500000000405615230700302022016 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for FunctionComposeTriple */ #ifndef _function_compose_triple_h_ #define _function_compose_triple_h_ #include "useful.h" #include "function_boilerplate.h" FUNCTION_BEGIN(FunctionComposeTriple,0,3,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { return arg(2)(arg(1)(arg(0)(p))); } //! Is constant if any (rather than default "all") function is constant. /*! One of the few cases it's worth overriding this method */ virtual bool is_constant() const { return (arg(0).is_constant() || arg(1).is_constant() || arg(2).is_constant()); } FUNCTION_END(FunctionComposeTriple) #endif evolvotron-0.8.3/libfunction/function_compose_triple.cpp0000644000175000017500000000310515230700302022343 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of FunctionComposeTriple class. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "function_compose_triple.h" evolvotron-0.8.3/libfunction/function_compose_pair.h0000644000175000017500000000400415230700302021443 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for FunctionComposeTriple */ #ifndef _function_compose_pair_h_ #define _function_compose_pair_h_ #include "useful.h" #include "function_boilerplate.h" FUNCTION_BEGIN(FunctionComposePair,0,2,false,0) //! Evaluate function. virtual const XYZ evaluate(const XYZ& p) const { return arg(1)(arg(0)(p)); } //! Is constant if any (rather than default "all") function is constant. /*! One of the few cases it's worth overriding this method */ virtual bool is_constant() const { return (arg(0).is_constant() || arg(1).is_constant()); } FUNCTION_END(FunctionComposePair) #endif evolvotron-0.8.3/libfunction/function_compose_pair.cpp0000644000175000017500000000307615230700302022006 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of FunctionComposePair class. Except there's nothing here because it's all in the header. */ #include "function_boilerplate_instantiate.h" #include "function_compose_pair.h" evolvotron-0.8.3/libfunction/function_boilerplate_instantiate.h0000644000175000017500000000320215230700302023667 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Modifications to function_boilerplate macros. Include this in function .cpp files before the header is included. */ #ifndef _function_boilerplate_instantiate_h_ #define _function_boilerplate_instantiate_h_ #define FUNCTION_BOILERPLATE_INSTANTIATE #endif evolvotron-0.8.3/libfunction/function_boilerplate.h0000644000175000017500000002165515230700302021300 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for abstract base class FunctionBoilerplate. And implementation given that it's a template. */ #ifndef _function_boilerplate_h_ #define _function_boilerplate_h_ #include "useful.h" #include "function_node.h" #include "function_node_info.h" #include "function_registry.h" #include "margin.h" //! Template class to generate boilerplate for virtual methods. template class FunctionBoilerplate : public FunctionNode { public: typedef FunctionNode Superclass; //! Constructor /*! \warning Careful to pass an appropriate initial iteration count for iterative functions. */ FunctionBoilerplate(const std::vector& p,boost::ptr_vector& a,uint iter); //! Destructor. virtual ~FunctionBoilerplate(); //! Accessor providing function name virtual const char* thisname() const =0; //! Make function meta-information. static FunctionRegistration* make_registration(const char* fn_name); //! Bits give some classification of the function type static uint type_classification() {return CLASSIFICATION;} //! Bits give some classification of the function type virtual uint self_classification() const; //! Factory method to create a stub node for this type static std::unique_ptr stubnew(const MutationParameters& mutation_parameters,bool exciting); //! Factory method to create a node given contents. /*! Returns null if there's a problem, in which case explanation is in report */ static std::unique_ptr create(const FunctionRegistry& function_registry,const FunctionNodeInfo& info,std::string& report); //! Return a deeploned copy. virtual std::unique_ptr deepclone() const; //! Return a deeploned copy with more specific type (but of course this can't be virtual). std::unique_ptr typed_deepclone() const; //! Internal self-consistency check. We can add some extra checks. virtual bool ok() const; //! Save this node. virtual std::ostream& save_function(std::ostream& out,uint indent) const; }; template FunctionBoilerplate::FunctionBoilerplate(const std::vector& p,boost::ptr_vector& a,uint iter) :FunctionNode(p,a,iter) { assert(params().size()==PARAMETERS); assert(args().size()==ARGUMENTS); assert((iter==0 && !ITERATIVE) || (iter!=0 && ITERATIVE)); } template FunctionBoilerplate::~FunctionBoilerplate() {} //! Provide a complete registration for the function template FunctionRegistration* FunctionBoilerplate::make_registration(const char* fn_name) { return new FunctionRegistration ( std::string(fn_name), &FunctionBoilerplate::stubnew, &FunctionBoilerplate::create, PARAMETERS, ARGUMENTS, ITERATIVE, FUNCTION::type_classification() ); } template uint FunctionBoilerplate::self_classification() const { return CLASSIFICATION; } template std::unique_ptr FunctionBoilerplate::stubnew(const MutationParameters& mutation_parameters,bool exciting) { static constexpr uint _PARAMETERS=PARAMETERS; static constexpr uint _ARGUMENTS=ARGUMENTS; std::vector params; stubparams(params,mutation_parameters,_PARAMETERS); boost::ptr_vector args; stubargs(args,mutation_parameters,_ARGUMENTS,exciting); return std::unique_ptr ( new FUNCTION ( params, args, (ITERATIVE ? stubiterations(mutation_parameters) : 0) ) ); } template std::unique_ptr FunctionBoilerplate::create(const FunctionRegistry& function_registry,const FunctionNodeInfo& info,std::string& report) { if (!verify_info(info,PARAMETERS,ARGUMENTS,ITERATIVE,report)) return std::unique_ptr(); boost::ptr_vector args; if (!create_args(function_registry,info,args,report)) return std::unique_ptr(); return std::unique_ptr(new FUNCTION(info.params(),args,info.iterations())); } template std::unique_ptr FunctionBoilerplate::deepclone() const { return std::unique_ptr(typed_deepclone()); } template std::unique_ptr FunctionBoilerplate::typed_deepclone() const { return std::unique_ptr(new FUNCTION(cloneparams(),*cloneargs(),iterations())); } template bool FunctionBoilerplate::ok() const { return ( params().size()==PARAMETERS && args().size()==ARGUMENTS && ((iterations()==0 && !ITERATIVE) || (iterations()!=0 && ITERATIVE)) && FunctionNode::ok() ); } template std::ostream& FunctionBoilerplate::save_function(std::ostream& out,uint indent) const { return Superclass::save_function(out,indent,thisname()); } #define FN_CTOR_DCL(FN) FN(const std::vector& p,boost::ptr_vector& a,uint iter); #define FN_CTOR_IMP(FN) FN::FN(const std::vector& p,boost::ptr_vector& a,uint iter) :Superclass(p,a,iter) {} #define FN_DTOR_DCL(FN) virtual ~FN(); #define FN_DTOR_IMP(FN) FN::~FN() {} #define FN_VNAME_DCL(FN) virtual const char* thisname() const; #define FN_VNAME_IMP(FN) const char* FN::thisname() const {return FN::classname();} #define FN_SNAME_DCL(FN) static const char* classname(); #define FN_SNAME_IMP(FN) const char* FN::classname() {return #FN;} #define FUNCTION_BEGIN(FN,NP,NA,IT,CL) \ class FN : public FunctionBoilerplate \ {public: \ typedef FunctionBoilerplate Superclass; \ FN_CTOR_DCL(FN) \ FN_DTOR_DCL(FN) \ FN_VNAME_DCL(FN) \ FN_SNAME_DCL(FN) //! Macro to push registrations through to registry. /*! Used by register_all_functions.h/register_all_functions.cpp */ #define REGISTER(R,FN) R.register_function(FN::make_registration(#FN)); #define REGISTER_DCL(FN) extern void register_ ## FN(FunctionRegistry&); #define REGISTER_IMP(FN) void register_ ## FN(FunctionRegistry& r){REGISTER(r,FN);} #ifdef FUNCTION_BOILERPLATE_INSTANTIATE #define FUNCTION_END(FN) };FN_CTOR_IMP(FN);FN_DTOR_IMP(FN);FN_VNAME_IMP(FN);FN_SNAME_IMP(FN);REGISTER_IMP(FN); #else #define FUNCTION_END(FN) };REGISTER_DCL(FN); #endif #endif evolvotron-0.8.3/libfunction/function_boilerplate.cpp0000644000175000017500000000305115230700302021621 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of specific Function classes. Except there's virtually nothing here because it's all in the header (templates). */ #include "function_boilerplate.h" evolvotron-0.8.3/libfunction/friezegroup.h0000644000175000017500000002465215230700302017432 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces and implementation for friezegroup related code. */ #ifndef _friezegroup_h_ #define _friezegroup_h_ #include "useful.h" #include "function_node.h" //! Functor implementing a pass-through Z coordinate policy struct FreeZ { float operator()(float z) const { return z; } }; //! Functor implementing a clamping Z coordinate policy struct ClampZ { ClampZ(float z) :_z(z) {} float operator()(float) const { return _z; } private: const float _z; }; //! Function evaluation via symmetry. template inline const XYZ FriezegroupEvaluate ( const Function& f,const XYZ& p,const SYMMETRY& sym,const ZPOLICY& zpol ) { return f(XYZ(sym(p.xy()),zpol(p.z()))); } //! Function evaluation with blending. /*! NB Is symmetry unaware; blend must have already reduced points to base domain. */ template inline const XYZ FriezegroupBlend ( const Function& f0,const Function& f1,const XYZ& p,const BLEND& blend,const ZPOLICY& zpol ) { const boost::tuple b(blend(p.xy())); return b.get<0>() *f0(XYZ(b.get<1>(),zpol(p.z()))) +(1.0-b.get<0>())*f1(XYZ(b.get<2>(),zpol(p.z()))); } template inline const XYZ FriezegroupBlend ( const Function& f,const XYZ& p,const BLEND& blend,const ZPOLICY& zpol ) { return FriezegroupBlend(f,f,p,blend,zpol); } //! Generate domain shift for when cutting. /*! This function actually far too specific to Hop and Jump, so move into their Cut functions as done for SpinhopCut */ /* template inline const int FriezegroupCut ( const Function& f,const XYZ& p,const CUT& cut,const ZPOLICY& zpol ) { const XY pc(cut(p.xy())); const real k=tanh(f(XYZ(pc,zpol(p.z()))).sum_of_components()); const real t=pc.x()/(0.5*cut.width()); // -1 to +1 over domain used for cut function (should be in -width/2 to +width/2) if (pc.x()<0.0 && k=0.0 && k>t) return 1; else return 0; } */ //------------------------------------------------------------------------------------------ struct Friezegroup { Friezegroup(real width) :_width(width) { assert(_width>0.0f); } real width() const { return _width; } private: const real _width; }; //------------------------------------------------------------------------------------------ //! Hop (Conway p111): no reflections or rotation. /*! Just have to cycle x range. \verbatim o o o --- --- --- \endverbatim Domain is over (-width/2,width/2), centred on zero. Default domain we use -0.5 to +0.5 to see symmetry at default sort of zoom. */ struct Hop : public Friezegroup { Hop(real width,int domain=0) :Friezegroup(width) ,_domain(domain) {} const XY operator()(const XY& p) const { return XY ( (_domain-0.5)*width()+modulusf(p.x()-0.5*width(),width()), p.y() ); } private: const int _domain; }; //! Constructs two points and a blending weight which will behave sensibly for Hop. /*! The additional point is half a domain width away. The blend weight is the weight of the primary point, should be maximum in the centre of the domain (0) and zero at the edges +/-0.5*width */ struct HopBlend : public Friezegroup // subclassing doesn't make much sense really { HopBlend(real width) :Friezegroup(width) {} const boost::tuple operator()(const XY& p) const { const Hop hop(width()); return boost::tuple ( (2.0/width())*trianglef(p.x()-0.5*width(),0.5*width()), // 0 at -width/2 and +width/2, 1 at 0 hop(p), hop(p-XY(0.5*width(),0.0)) ); } }; //! Generates points suitable for evaluating cutting function /* struct HopCut : public Friezegroup { HopCut(real width) :Friezegroup(width) {} const XY operator()(const XY& p) const { return Hop(width())(p+XY(0.5*width(),0.0)); } }; */ //------------------------------------------------------------------------------------------ //! Jump (Conway p1m1): horizontal reflection only /*! Just cycle x range and reflect in y. Is simply Hop with a relection about y=0 \verbatim o o o --- --- --- --- --- --- o o o \endverbatim */ struct Jump : public Hop { Jump(real width,int domain=0) :Hop(width,domain) {} const XY operator()(const XY& p) const { return Hop::operator()(XY(p.x(),fabs(p.y()))); } }; //! Constructs two points and a blending weight which will behave sensibly for Jump struct JumpBlend : public HopBlend { JumpBlend(real width) :HopBlend(width) {} const boost::tuple operator()(const XY& p) const { return HopBlend::operator()(XY(p.x(),fabs(p.y()))); } }; /* struct JumpCut : public HopCut { JumpCut(real width) :HopCut(width) {} const XY operator()(const XY& p) const { return HopCut::operator()(XY(p.x(),fabs(p.y()))); } }; */ //------------------------------------------------------------------------------------------ //! Sidle (Conway pm11): vertical reflection /*! Bounce x backwards and forwards. Can't be blended or cut because there are only reflection lines. (Well we could blend it by increasing the domain width and blending between overlapping domains, but the reflection lines aren't really worth going to any trouble to hide. \verbatim o| |o o| |o | | | | | | | | \endverbatim */ struct Sidle : public Friezegroup { Sidle(real width) :Friezegroup(width) {} const XY operator()(const XY& p) const { return XY ( trianglef(p.x()+0.5*width(),width())-0.5*width(), // So -width/2 maps to -width/2 p.y() ); } }; //------------------------------------------------------------------------------------------ //! Spinjump (Conway pmm2): vertical & horizontal reflection and half-rotation. /*! Oscillate x and reflect y. Is just sidle with a reflection about y=0. Can't be blended or cut because there are only reflection lines. \verbatim o o o o --- --- --- --- --- --- --- --- o o o o \endverbatim */ struct Spinjump : public Sidle { Spinjump(real width) :Sidle(width) {} const XY operator()(const XY& p) const { return Sidle::operator()(XY(p.x(),fabs(p.y()))); } }; //------------------------------------------------------------------------------------------ //! Spinhop (Conway p112): Half turn rotation only. /*! Sawtooth x increasing or decreasing depending on which side, with y inverting. Don't think this can be blended because it would change symmetry. \verbatim o o --- --- --- --- o o \endverbatim */ struct Spinhop : public Friezegroup { Spinhop(real width,int domain=0) :Friezegroup(width) ,_domain(domain) {} const XY operator()(const XY& p) const { bool flipped=(modulusf(p.x()+0.5*width(),2.0*width())>width()); if (_domain!=0) flipped=!flipped; real x=modulusf(p.x()+0.5*width(),width())-0.5*width()+_domain*width(); real y=p.y(); if (flipped) { x=-x; y=-y; } return XY(x,y); } private: const int _domain; }; //! Blended Spinhop /*! Can build this from blending two rotated hop sequences. Make the domains wider. \verbatim o o o o ----- ----- ----- ----- v blend these two together ----- ----- ----- ----- ^ using triangular alpha fn o o o o \endverbatim */ struct SpinhopBlend : public Friezegroup // subclassing doesn't make much sense really { SpinhopBlend(real width) :Friezegroup(width) {} const boost::tuple operator()(const XY& p) const { const Hop hop(2*width()); return boost::tuple ( trianglef(p.x()-width(),width())/width(), // zero at x=-width and +width, 1 at x=0 hop(p), hop(XY(width()-p.x(),-p.y())) ); } }; //! Only suitable cut I can see looks like Sidle with rotate across y=0 /*! \todo There's something different could be done here. The cutting is too constrained (needs pictures :^) \todo Some "softening" of the cut around y=0 would be good to stop odd looking hard lines. */ /* template struct SpinhopCut : public Friezegroup { SpinhopCut(real width) :Friezegroup(width) {} const int operator()(const Function& f,const XYZ& p,const ZPOLICY& zpol) const { const XY pm(p.x()-0.5*width(),fabs(p.y())); // Shift out of alignment with spinhop being cut, and add reflection about y=0 const XY r(Sidle(width())(pm)); // in combo with sidle, gets us something suitable for cutting without breaking spinhop const XY pc(p.y()<0.0 ? XY(-r.x(),r.y()) : r); // if we also flip it below y=0 const real k=tanh(f(XYZ(pc,zpol(p.z()))).sum_of_components()); const real t=(modulusf(pm.x()-0.5*width(),width())-0.5*width())/(0.5*width()); // Scans -1 to 1 across each (shifted, cutting) domain int d=0; if (t<0.0 && k=0.0 && k>t) d=1; return d; } }; */ //------------------------------------------------------------------------------------------ #endif evolvotron-0.8.3/libfunction/friezegroup.cpp0000644000175000017500000000271215230700302017756 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation for friezegroup related code. */ #include "friezegroup.h" evolvotron-0.8.3/libevolvotron/0000755000175000017500000000000015230700302015277 5ustar karlkarlevolvotron-0.8.3/libevolvotron/usage_text.h0000644000175000017500000010064415230700302017625 0ustar karlkarl"\n" "

Evolvotron User Manual

\n" "\n" "

\n" " Evolvotron is interactive "generative art" software to evolve\n" " images/textures/patterns through an iterative process of random\n" " mutation and user-selection driven evolution.\n" "

\n" "

\n" " On starting the application, a grid of images is displayed.\n" " Resize or maximise the application if you like, but the more\n" " pixels have to be calculated, the slower it will be.\n" " (For the default 2D image mode, you will need a fast machine or patience.\n" " For the optional animation mode, you will need both.)\n" "

\n" "

\n" " Simply repeat the following until bored:\n" "

  • Click (singleclick) on an image you like to\n" " spawn the next generation of its mutant offspring.\n" "
  • Wait until variations on it are regenerated in sufficient\n" " detail that you can decide which one you like best again.\n" "
  • \n" "
\n" "

\n" "

\n" " IMPORTANT: Initially you should select images with some sort of variation.\n" " If you select a uniform image, you may get stuck in a degenerate zone with\n" " little to mutate and therefore little chance of escape to more interesting\n" " images. You can always reset/restart from the "File" menu (the difference is\n" " that "reset" also resets the mutation parameters to their default values).\n" " Selecting one of the "warp" options from a context menu (right-click on\n" " an image) can also help by introducing an additional opportunity for\n" " mutation on subsequent spawns.\n" "

\n" "

\n" " Note that various spirals, grids and tiles, although complex looking,\n" " are actually implemented by a single function node and may leave you stuck too.\n" "

\n" "

Command Line Options

\n" "

\n" " The following are equivalent:\n" "

  • evolvotron --grid 12x8\n" "
  • evolvotron --grid=12x8\n" "
  • evolvotron -g 12x8\n" "
  • \n" "
\n" "

\n" "

General Options

\n" "\n" "

\n" "

  • -a, --autocool
    \n" " Enable autocooling by default, and cause resets of mutation\n" " parameters to re-enable autocooling if it was disabled.\n" "
  • \n" "
\n" "

\n" "

\n" "

  • -F, --fullscreen
    \n" " Start in "fullscreen" mode (NB for Qt on X11 this means\n" " a screen-filling borderless/undecorated window is used;\n" " it's not simply maximising the window, and it's not the\n" " sort of framebuffer hijacking used by SDL games). The Qt\n" " documentation claims some window managers may not be entirely\n" " cooperative with this (in which case sorry, you're on your own).\n" " evolvotron actions which bring up dialog boxes (e.g save) seem\n" " to generally behave fairly sensibly but child windows\n" " (e.g enlargements or dialogs) can show some "interesting" behaviour.\n" " Fullscreen mode can be toggled within the application using CTRL-F key.\n" " The Esc key will also exit it.\n" "
  • \n" "
\n" "

\n" "

\n" "

  • -g, --grid colsxrows
    \n" " Sets size of the grid of image display cells in the main application area (defaults to 5x6)\n" "
  • \n" "
\n" "

\n" "

\n" "

  • -h, --help
    \n" " Print summary of command line options and exit.\n" "
  • \n" "
\n" "

\n" "

\n" "

  • -j, --jitter
    \n" " Enable sample jittering. Samples will be made at a random position\n" " within a pixel instead of on a regular grid, providing some antialiasing.\n" "
  • \n" "
\n" "

\n" "

\n" "

  • -m, --multisample multisample grid
    \n" " Enables additional antialiasing passes.\n" " Specifying 2 or 3 will provide an additional pass with 2x2 or 3x3 samples per pixel.\n" " Specifying 4 (or higher) will provide a 2x2 and a final 4x4 pass.\n" " Specifying 1 provides the default behaviour of one sample per pixel.\n" " For best rendering quality also specify -j.\n" "
  • \n" "
\n" "

\n" "

\n" "

  • -M, --menuhide
    \n" " Start with menu and status bar hidden. Nice with --fullscreen.\n" " Hiding can be toggled within the application using CTRL-M.\n" " The Esc key will also bring them back.\n" "
  • \n" "
\n" "

\n" "

\n" "

  • -p, --spheremap
    \n" " Images are produced by sampling the underlying 3D function on the\n" " latitude-longitude grid of a sphere. The resulting images should be\n" " usable as spheremaps/spherical environment maps. Animations vary\n" " the radius of the sphere. NB when in spheremap mode,\n" " middle mouse button adjustments do not yet behave like you'd expect.\n" "
  • \n" "
\n" "

\n" "

\n" "

  • -S, --startup function_filename
    \n" " Specify a function filename (evolvotron's XML format) to load on startup\n" " (or reset). The option can be provided multiple times, and this is\n" " also the interpretation of any positional arguments. Startup functions\n" " are placed in the grid from left to right, top to bottom.\n" "
  • \n" "
\n" "

\n" "

\n" "

  • -U, --shuffle
    \n" " Use in conjunction with -S / --startup options, to display the specified\n" " functions in random order, both on application startup and on each\n" " reset of the application.\n" "
  • \n" "
\n" "

\n" "

Animation Options

\n" "\n" "

\n" "

  • -f, --frames frames
    \n" " Number of frames in animations (defaults to 1 i.e no animation)\n" "
  • \n" "
\n" "

\n" "

\n" "

  • -l, --linear
    \n" " Vary z linearly with time rather than sinusoidally.\n" " Sinusoidal variation generally looks better when animations are "bounced"\n" " forwards and backwards, but this option is useful when generating slices to\n" " use as volumetric textures.\n" "
  • \n" "
\n" "

\n" "

\n" "

  • -s, --fps framerate
    \n" " Rate at which frames are displayed per second (integer). (Defaults to 8).\n" "
  • \n" "
\n" "

\n" "

Power-user & Debug Options

\n" "\n" "

\n" " Note that the usual Qt/X11 options\n" " (for example, -geometry widthxheight option to set on-screen size in pixels)\n" " are processed and removed before evolvotron options are checked.\n" "

\n" "

\n" "

  • -D, --debug
    \n" " Puts the certain aspects of the app into a more debug oriented mode.\n" " Currently (ie this may change) it simply changes function weightings\n" " so virtually all function nodes are FunctionNoiseOneChannel. By itself\n" " this is a pretty pointless thing to do, but in conjunction with the -X\n" " options it's useful for examining the behaviour of specific functions.\n" "
  • \n" "
\n" "

\n" "

\n" "

  • -E, --enlargement-threadpool
    \n" " Use a separate thread pool for computing enlargements.\n" " Using this option ensures computation of enlargements\n" " continue to make some progress even while the main grid\n" " is being actively worked on. However, this will be at\n" " the expense of main grid rendering performance.\n" " Without this option, enlargements' final high-resolution\n" " renderings are invariably lower priority than computation\n" " for images in the main grid.\n" " See also the -N option to control the priority of threads\n" " in this pool.\n" "
  • \n" "
\n" "

\n" "

\n" "

  • -n, --nice niceness
    \n" " Sets additional niceness (relative to the main application thread)\n" " of the compute (rendering) thread(s).\n" " It's useful to run compute threads at a slightly lower priority\n" " ("nice 4" is the default without this option) than the main (GUI)\n" " part of the program (but note that this means other normal/lowish\n" " priority tasks running on your machine may slow evolvotron down\n" " a bit more than expected).\n" "
  • \n" "
\n" "

\n" "

\n" "

  • -N, --Nice enlargement niceness
    \n" " Sets additional niceness (relative to the main application thread)\n" " of the compute thread(s) computing enlargements (default value is 8).\n" " Only effective in conjunction with -E option.\n" "
  • \n" "
\n" "

\n" "

\n" "

  • -t, --threads threads
    \n" " Sets number of compute threads.\n" " If this is not specified, then as many compute threads are created\n" " as there are processors on the system (unless this cannot be\n" " discovered in which case only a single compute thread is created).\n" " Non-linux builds will likely not include code to determine processor count\n" " (suitable patches gratefully received).\n" "
  • \n" "
\n" "

\n" "

\n" "

  • -u, --unwrapped
    \n" " Modifies -F behaviour so that the specified "favourite" function\n" " is NOT wrapped by space/colour transforms. NB For functions without leaf nodes\n" " or parameters (e.g FunctionSphericalToCartesian) this doesn't\n" " leave any scope for variation or future mutation.\n" " Function name recognition is case sensitive.\n" " Example:\n" " evolvotron -F FunctionKaleidoscope -u\n" "
  • \n" "
\n" "

\n" "

\n" "

  • -v, --verbose
    \n" " Verbose mode, writes various things to application stderr.\n" " This is primarily intended to assist debugging.\n" " This option used to be useful for getting a list of supported function\n" " names for use with the -F option, but those can also be inspected\n" " via the Settings dialogs.\n" "
  • \n" "
\n" "

\n" "

\n" "

  • -x, --favourite functionname
    \n" " Force a specific "favourite" function type to be used at the top level\n" " of all function trees. The specified function is still wrapped\n" " by spatial and colour warping functions which may disguise\n" " it considerably. A list of all the function names understood\n" " by evolvotron is output during app startup when the -v option\n" " is specified. Function name recognition is case sensitive.\n" " Example:\n" " evolvotron -F FunctionSpiralLinear\n" "
  • \n" "
\n" "

\n" "

Mouse Control

\n" "\n" "

Left-click

\n" "

\n" " A left-click on an image in the main window can either mutate it or toggle\n" " its lock. The lock is toggled when clicking in the upper right corner.\n" " Clicking elsewhere spawns the mutant offspring of that image to all the other\n" " (non-locked) displays in the grid.\n" "

\n" "

Right-click Context Menu

\n" "

\n" " Right clicking on an image gets you a few more options:\n" "

\n" "

\n" "

  • "Respawn" regenerates just the current image from whatever it was\n" " spawned from (and using recolour or warp, if that's what was used\n" " to produce it).\n" " The main use of this is to make your grid of images look nice\n" " for screendumps, by regenerating any which aren't up to scratch.\n" " NB May not work as expected after an "undo".\n" "
  • \n" "
\n" "

\n" "

\n" "

  • "Spawn" is the same as clicking an image. It generates mutated\n" " images to all unlocked images in the grid.\n" "
  • \n" "
\n" "

\n" "

\n" "

  • "Recolour" to produce different coloured variants of the selected image\n" "
  • \n" "
\n" "

\n" "

\n" "

  • "Warp"'s sub-options produce variants of the image which have been\n" " zoomed/rotated/panned.\n" "
  • \n" "
\n" "

\n" "

\n" "

  • "Lock" to prevent an image from being overwritten by spawns from other\n" " images (select again to toggle).\n" "
  • \n" "
\n" "

\n" "

\n" "

  • "Enlarge" to produce a blow-up of the image in a single window.\n" " Submenu items select either a freely resizable window or\n" " a scrollable view of a fixed size image.\n" " If the application is running in fullscreen mode (NB this is\n" " NOT the same as a simply "maximised" window) then the enlarged\n" " image will also be fullscreen (the "Resizeable" mode is probably\n" " what you want in this case as the image will automatically be\n" " rendered at the correct resolution).\n" "
  • \n" "
\n" "

\n" "

\n" "

  • "Save image" to save the image in a file (.ppm or .png).\n" " You generally want to save an enlarged image: if you\n" " save a small image from the grid, the size you see on the screen\n" " is the size you get in the file. Save isn't allowed until the\n" " full resolution image has been generated; if you try to save too\n" " early a dialog box will be displayed telling you to try again later.\n" "
  • \n" "
\n" "

\n" "

\n" "

  • "Save function" to store the function to an XML file.\n" "
  • \n" "
\n" "

\n" "

\n" "

  • "Load function" to load a stored function from an XML file.\n" " NB if the file was saved from a different version numbered\n" " evolvotron, a warning message will be generated.\n" " Save/load of functions is an experimental feature and you should\n" " not count on future versions of evolvotron being able to load\n" " files saved from old versions, or producing the same image\n" " from a loaded function. Attempting to load functions from later\n" " versions into earlier versions is even less likely to succeed.\n" "
  • \n" "
\n" "

\n" "

\n" "

  • "Simplify" prunes the function tree of redundant branches where\n" " possible (the same action can be applied to all images from\n" " the main "Edit" menu). This doesn't change the appearance of\n" " the image, but may make it recompute faster.\n" "
  • \n" "
\n" "

\n" "

\n" "

  • "Properties" brings up a dialog box containing some information\n" " about the image (e.g the number of function nodes it contains).\n" "
  • \n" "
\n" "

\n" "

Middle Mouse Button

\n" "

\n" " [NB This feature will probably only be of practical use to those with high-end machines].\n" "

\n" "

\n" " You can use the middle mouse button to drag-adjust individual images.\n" " This is useful for "final composition" type tweaks, e.g centering an\n" " image's most interesting feature, or just for satisfying your curiosity\n" " about what's off the edge of the image.\n" "

\n" "

\n" " It also works on enlarged images, although it's virtually unusable without\n" " a bit of practice on smaller, faster ones (just boldly make the adjustment\n" " you want, release the button... and wait).\n" "

\n" "

\n" " Changes made can be rolled-back on the main Edit/Undo menu item,\n" " one drag-action at a time.\n" "

\n" "

\n" " An unmodified middle-mouse drag pans the image around following\n" " the mouse motion.\n" "

\n" "

\n" " A SHIFT-middle drag zooms the image in and out with scaling\n" " proportional to the distance from the centre of the image. Beware of\n" " generating huge zooms by clicking too near the centre of the image.\n" "

\n" "

\n" " An ALT-SHIFT-middle drag is similar but anisotropic: the scaling\n" " may be different in X and Y. Warning: this technique is very\n" " sensitive and can be quite tricky to use! In particular,\n" " if you initially click near the centre axes of the image the zoom factor\n" " can be HUGE, so the best way to start using this is to click about halfway\n" " on a diagonal between the image centre and a corner and gently move in and\n" " out radially. Dragging from one side of the image to the other flips it over\n" " (the degenerate case of infinite zoom at the centre is handled cleanly I think).\n" " If it all goes horribly wrong, undo and try again.\n" "

\n" "

\n" " A CTRL-middle drag rotates the image about its centre.\n" "

\n" "

\n" " A CTRL-ALT-middle drag shears the image (the best way to see what\n" " this does is to click in the corner of an image and move the mouse\n" " horizontally or vertically).\n" "

\n" "

Mouse Wheel

\n" "

\n" " Scrolling the mouse wheel zooms the image in and out.\n" "

\n" "

Keyboard Control

\n" "\n" "

\n" " There are some keyboard shortcuts.\n" "

\n" "

Main Window

\n" "\n" "

\n" "

  • "r"/"t"/"x" perform various starts of reset/restart.\n" "
  • \n" "
\n" "

\n" "

\n" "

  • "CTRL-Q" quits the application.\n" "
  • \n" "
\n" "

\n" "

\n" "

  • "u" (and also CTRL-Z) does an undo.\n" "
  • \n" "
\n" "

\n" "

\n" "

  • "CTRL-F": full-screen mode. See also "-F" command line option.\n" " Fullscreen mode propagates to enlarged image display windows.\n" " NB The application may completely disappear from the screen for\n" " a brief interval while switching mode.\n" "
  • \n" "
\n" "

\n" "

\n" "

  • "CTRL-M": hides status and menu-bar hiding, which can be nice when\n" " in full-screen or window-maximised mode. See also "-M"\n" " command line option. Also note that while the menu bar\n" " is hidden, most of these keyboard shortcuts won't function\n" " as they're tied to the menu system.\n" "
  • \n" "
\n" "

\n" "

\n" "

  • Esc: exits full-screen and/or menu-hiding mode, putting the\n" " application into its normal default state.\n" "
  • \n" "
\n" "

\n" "

Enlargement Windows

\n" "

\n" " The image display windows created by selecting "Enlarge" from a\n" " context menu also have a couple of keyboard operations:\n" "

\n" "

\n" "

  • "f" : [NB only available with fullscreen build option] toggles\n" " full-screen mode. When returning to normal mode, if the main app\n" " window was fullscreen then it will also drop back to normal mode.\n" "
  • \n" "
\n" "

\n" "

\n" "

  • Esc : [NB only available with fullscreen build option]\n" " completely closes a fullscreen-mode enlargement window.\n" "
  • \n" "
\n" "

\n" "

Gui Elements

\n" "\n" "

Main Menu Bar

\n" "

\n" "

  • File menu:\n" " Items to restart, reset and quit the application.\n" " The difference between restart and reset is that reset\n" " sets the mutation parameters back the their default values.\n" " The "randomize function weights" version of restart scrambles\n" " the relative probability of the various function types (if you\n" " think evolvotron just keeps generating the same kinds of\n" " images give it a try). The "restart with specific function"\n" " item duplicates the functionality of the "-x" and "-X" command-line\n" " options.\n" "
  • Edit menu:\n" " "Undo" lets you undo certain actions: e.g spawn,\n" " middle-button adjustment, simplification and lock/unlock.\n" " There is a large but limited number of levels of undo.\n" " "Simplify" is of curiosity value only: it prunes redundant\n" " branches from images ("junk DNA"); this may help them recompute\n" " faster but at the cost of there being less mutatable material.\n" "
  • Settings menu:\n" " "Mutations" brings up a dialog to modify the amount\n" " of change spawned images are subject to.\n" " (See "advanced usage" below.)\n" " "Functions" brings up a dialog to modify the relative probability\n" " of functions being used. By default all functions are equally\n" " likely except for iterative functions and fractals, which are\n" " almost but not completely suppressed. But if you think there\n" " are too many spirals or grids (or not enough fractals) then this\n" " is the place to adjust the frequency with which they appear.\n" " If the software was built with the fullscreen option,\n" " that can also be controlled from this menu.\n" " "Favourite" brings up a dialog which allows you to select a specific\n" " function type to always be used as the root node of any new functions.\n" " The function can be wrapped by some other random stuff, or unwrapped.\n" " See also the -X and -x command line options.\n" "
  • Help menu:\n" " Items to bring up documentation, and the usual "About" box\n" " (which includes the license).\n" "
  • \n" "
\n" "

\n" "

Status Bar

\n" "

\n" " An area on the status bar shows how many compute "tasks" are\n" " outstanding (or "Ready" when there are none). When two task\n" " totals are reported, the first is for the main grid and the\n" " second for any enlargements being computed.\n" " Each "task" is the recomputation of an image at some resolution.\n" " Tasks are prioritised by their number of pixels (small image\n" " implies higher priority). This is why, if the main grid is still\n" " recomputing, recalculations of enlargements will appear to freeze\n" " after they have reached a certain resolution, at least until other\n" " lower resolution tasks have completed.\n" "

\n" "

\n" " The status bar also provides some control over the "autocool"\n" " mechanism which reduces mutation strength with time.\n" " See the advanced usage section below.\n" "

\n" "

Tips

\n" "

\n" "

  • Don't start a session with any preconceived ideas about the kind\n" " of image you want to get out of it. You will be disappointed.\n" "
  • I get the best results when I click the image which most\n" " immediately catches my eye as they start appearing. If you stop\n" " to think about it too much then things seem to go downhill.\n" "
  • If you seem to be just getting the same old spirals and grids\n" " all the time, stop clicking on spirals and grids!\n" " (The same goes for random mush).\n" "
  • Don't get too hung up on using the warp and middle-mouse drag\n" " adjustments every iteration... use those tools for final\n" " polishing of your masterpiece.\n" "
  • You can quickly cycle through a lot of initial images (until\n" " you find one with real potential) by bashing on CTRL-R to\n" " repeatedly restart.\n" "
  • To add variety to an image's mutations, nudge it with a small\n" " middle-mouse drag. This introduces a top level transform, and\n" " therefore more parameters to be varied.\n" "
  • Enlargements take a long time to complete their final\n" " high-resolution rendering pass (especially with multisampling\n" " enabled). Most convenient practice seems to be to go away and\n" " leave them to complete, then come back and save them later.\n" " Continuing to click away on the main grid effectively starves\n" " them of CPU, unless the -E command-line option is used.\n" "
  • \n" "
\n" "

\n" "

Animation

\n" "

\n" " As of version 0.2.0 evolvotron contains some experimental support\n" " for generation of animations (although so far the results have been\n" " pretty disappointing IMHO, but it's still early days).\n" "

\n" "

\n" " NB THIS IS EVEN MORE COMPUTATIONALLY AND MEMORY INTENSIVE THAN\n" " THE STATIC IMAGE MODE.\n" "

\n" "

\n" " Simply supply a -f frames command line option and evolvotron will\n" " generate animated sequences with the specified number of frames.\n" " These will be displayed at the frame rate specified by the\n" " optional -s framerate option (default 8). So "evolvotron -s 24"\n" " will generate 3 second long animations. Animations reverse direction\n" " at each end to avoid a sudden jump.\n" "

\n" "

\n" " If you save an animation as PPM or PNG, multiple files will\n" " be saved with .fnnnnnn (where nnnnnn is the zero-filled frame\n" " number) inserted in each filename before the filetype qualifier.\n" "

\n" "

\n" " For example, if you enter foo.ppm as the filename to save,\n" " files foo.f000000.ppm, foo.f000001.ppm... will be saved.\n" " If you have the ImageMagick tools you can convert these to\n" " an animated GIF playing at approx. 8 frames per second with:\n" "

\n" "

\n" " convert -delay 12 foo.f??????.ppm foo.gif\n" "

\n" "

Advanced Usage

\n" "

\n" " Evolvotron's idea of an image is a function which converts\n" " XYZ co-ordinates to an RGB colour (however we can only display\n" " a 2D plane for now so the input Z is fixed to zero, or varied\n" " with time when animating).\n" "

\n" "

\n" " The image functions are constructed from trees of function nodes.\n" " (In the mathematical expression 1+(2*x) the "+" and the "*" would\n" " be function nodes.) Evolvotron's functions tend to correspond to\n" " geometric or colour-space operations or anything else which can be\n" " applied to a 3D vector.\n" "

\n" "

\n" " By mutating the structure of the function tree (adding random\n" " branches, for example) and the values of the constant embedded\n" " within it, the image can be changed.\n" "

\n" "

\n" " The mutation parameters are under control from the dialogs accessible\n" " via the Settings menu, and the "autocool" mechanism exposed in the\n" " status bar also has some influence.\n" "

\n" "

\n" " There are two kinds of mutation: perturbations to the magnitude of constants,\n" " and structural mutations which re-arrange the function tree of an image.\n" " Four types of structural mutations are currently implemented:\n" "

  • replacement of a function branch by a new random stub (a "Glitch" mutation).\n" "
  • a random shuffle of a node's sub-nodes\n" "
  • insertion of random nodes between a node and it's sub-nodes\n" "
  • the substitution of a node with one of a different type,\n" " with sub-nodes unaffected where possible).\n" "
  • \n" "
\n" "

\n" "

\n" " The probability (per function node) of these mutations is controlled\n" " from spinboxes on the "Mutation Parameters" dialog (expressed as\n" " chances-in-a-hundred), as is the size of perturbations to constants.\n" "

\n" "

\n" " It is useful to think of the perturbations to constant parameters as\n" " being a thermal effect (hence the "heat" and "cool" buttons), while\n" " structural alterations are more drastic and are caused by high energy\n" " gamma rays or something (hence "irradiate" and "shield" buttons to\n" " adjust the probability of structural mutations).\n" "

\n" "

\n" " So why would you want to change the mutation parameters from the initial\n" " defaults ? Basically, if you're getting too much variation in spawned images\n" " (this tends to happen after many generations of images, by which time the\n" " function trees have grown quite large and therefore are experiencing a lot\n" " of mutations) then cool and/or shield.\n" " If all the images look too similar, heat and/or irradiate.\n" "

\n" "

\n" " The "autocool" mechanism (enabled from the statusbar or mutation parameters\n" " dialog) automatically reduces the strength of mutations from the base\n" " values with successive generations. The cooling can be cancelled by\n" " disabling autocooling or pressing the "Reheat" button to zero the number\n" " of generations counted for cooling. The effect of the cooling is a compound\n" " halving of the mutation strength after some number of generations (this number\n" " is the "half-life" controllable from the mutation parameters dialog).\n" " Note that if autocooling is enabled then eventually, after a number of\n" " iterations more than many multiples of the half-life has passes, spawned\n" " images will differ very little from their parents (hence the need for "reheat").\n" "

\n" "

\n" " There is also a dialog accessible from "Functions..." on the "Settings" menu.\n" " This allows control over the relative proportions in which functions occur.\n" " There is a tab showing the relative weighting of all functions (log-2 scale: each\n" " tick halves the probability of the function occurring), and additional tabs\n" " for various classifications of function for quicker access.\n" " The "Randomize" button on each tab assigns random weightings and helps\n" " increase the uniqueness of your session.\n" "

\n" "

\n" " The "Functions" dialog also has a "Dilution" tab which allows the average\n" " function-tree branching ratio to be controlled (by changing the proportion\n" " of trivial zero-branch functions added): note that using a high branching\n" " ratio results in very complex images which will take a long time to compute,\n" " while reducing the ratio results in simple, boring images.\n" "

\n" "

\n" " 3 types of function node are considered fundamental: constant nodes\n" " (which return a constant), identity nodes (which return their\n" " position argument) and transform nodes (which transform their position\n" " argument by random parameters). On the "Dilution" tab of the "Functions"\n" " dialog there are two slider controls to affect things related to these:\n" "

  • "proportion constant" controls the proportion of diluting fundamental nodes\n" " which are constants. Changing this from its default value of 0.5 doesn't\n" " actually seem to have much effect.\n" "
  • "proportion transforms" sets the proportion of non-constant nodes diluting\n" " which are transforms (as opposed to identity nodes).\n" " The main effect of this is that images are less commonly obviously centred\n" " on the origin or aligned with the axes. I think this is a good thing, so\n" " the value is at 1.0 by default.\n" "
  • \n" "
\n" "

\n" "

Other Executables

\n" "

\n" " This release also builds some other command-line driven (non-GUI, non-interactive) utilities.\n" " Consult the man pages for full details.\n" "

\n" "

\n" " evolvotron_render reads a XML function description from its standard input and renders it to the\n" " file specified.\n" "

\n" "

\n" " evolvotron_mutate reads an XML function description from its standard input and outputs a mutated version.\n" " A command line option allows the "genesis" situation of creating a random function description with no input.\n" "

\n" "

Examples

\n" "\n" "

\n" " Evolving and mutating on the command line:\n" "

\n" "

\n" " evolvotron_mutate -g | tee fn.xml | evolvotron_render /tmp/xxx.ppm ; display /tmp/xxx.ppm\n" "

\n" "

\n" " cat fn.xml | evolvotron_mutate | evolvotron_render -j -m 4 /tmp/xxx.ppm ; display /tmp/xxx.ppm\n" "

\n" "

\n" " Animating a function ani.xml saved from evolvotron in animation mode:\n" "

\n" "

\n" " cat ani.xml | evolvotron_render -f 100 -v -s 256 256 ani.ppm ; animate ani.f??????.ppm\n" "

\n" "

Future Developments

\n" "

\n" " Please check the TODO file first before you send me suggestions!\n" "

\n" "

\n" " Please don't ask me to port evolvotron to proprietary platforms.\n" " You are of course Free under the terms of the GPL to do so yourself,\n" " but please read\n" " http://www.fefe.de/nowindows/\n" " first.\n" "

\n" "

Thanks

\n" "

\n" " To those who have contributed feedback, suggestions and patches:\n" "

  • Dmitry Kirsanov\n" "
  • Jonathan Melhuish\n" "
  • Karl Robillard\n" "
  • Linc Davis\n" "
  • Paolo Greppi\n" "
  • Marcin Wojtczuk\n" "
  • Michael Sterrett\n" "
  • Massimiliano Guastafierro\n" "
  • Goetz Waschk\n" "
  • Forrest Walter\n" "
  • "chr_bl" at web.de\n" "
  • \n" "
\n" "

\n" "

\n" " And to the anonymous Linspire reviewer who perhaps came up with the best\n" " summary of evolvotron yet: "Fascinating. Utterly pointless, but fascinating."\n" "

\n" "

\n" " The friezegroups wouldn't have been possible without\n" " http://michaelshepperd.tripod.com/resources/groups.html\n" "

\n" "

\n" " Thanks to www.di.fm, www.somafm.com and Trance4Ever for music to code to.\n" "

\n" "

\n" " Thanks especially to a SIGGRAPH conference panel many years ago (likely\n" " including Karl Sims, the pioneer in this area) who first got me interested\n" " in this stuff.\n" "

\n" "

Why ?

\n" "

\n" " I have always admired those who have the skill to wield a pen or paintbrush\n" " and fill a sheet of paper or a canvas with some striking image from their\n" " imagination. Unfortunately I lack the patience to learn such skills,\n" " and probably the necessary manual dexterity and imagination too.\n" "

\n" "

\n" " Evolvotron, and several predecessors developed on and off over a decade\n" " since I first came across the idea, are an attempt to compensate for\n" " this using the skills I do have i.e some mathematical sensibility\n" " and the ability to write working code (well, sometimes). If you like\n" " an image it produces, then as far as I'm concerned that's as satisfying\n" " a result as if you liked something I'd drawn myself.\n" "

\n" "

\n" " Tim Day\n" evolvotron-0.8.3/libevolvotron/transform_factory.h0000644000175000017500000001120015230700302021204 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class TransformFactory. */ #ifndef _transform_factory_h_ #define _transform_factory_h_ #include "common.h" class Random01; #include "transform.h" //! Abstract base class for classes creating Transforms class TransformFactory { public: TransformFactory() {} virtual ~TransformFactory() {} //! Clone functionality needed to retain typed copies of factories. virtual std::unique_ptr clone() const =0; //! Method to build a Transform. virtual const Transform operator()(Random01&) const =0; protected: }; //! Factory for creating random warps /*! These are the mixed scale/rotate/translate ones used by the combo warp. */ class TransformFactoryRandomWarpXY : public TransformFactory { public: //! Constructor accepts power-of-2 specifiers, so -1 & 1 would generate scalings between 0.5 and 2, half zooming in and half zooming out. // Constructor. /*! \todo Should be parameterised with parameters specified at point of usage in MutatableImageDisplay */ TransformFactoryRandomWarpXY() {} //! Clone. virtual std::unique_ptr clone() const { return std::unique_ptr(new TransformFactoryRandomWarpXY()); } //! Return a random transform. virtual const Transform operator()(Random01& rng) const; protected: }; //! Factory for creating random scaling transforms class TransformFactoryRandomScaleXY : public TransformFactory { public: //! Constructor accepts power-of-2 specifiers, so -1 & 1 would generate scalings between 0.5 and 2, half zooming in and half zooming out. TransformFactoryRandomScaleXY(real lopow2,real hipow2) :_lopow2(lopow2),_hipow2(hipow2) {} //! Clone method. virtual std::unique_ptr clone() const { return std::unique_ptr(new TransformFactoryRandomScaleXY(_lopow2,_hipow2)); } //! Return a random scaling transform. virtual const Transform operator()(Random01& rng) const; protected: //! The low end of the scaling as a power of 2 real _lopow2; //! The high end of the scaling as a power of 2 real _hipow2; }; //! Factory for creating random z-axis rotation transforms class TransformFactoryRandomRotateZ : public TransformFactory { public: //! Constructor TransformFactoryRandomRotateZ() {} //! Clone method. virtual std::unique_ptr clone() const { return std::unique_ptr(new TransformFactoryRandomRotateZ()); } //! Create a transform. virtual const Transform operator()(Random01& rng) const; protected: }; //! Factory for creating random translation transforms class TransformFactoryRandomTranslateXYZ : public TransformFactory { public: //! Constructor accepts XYZ origin (centre) and range (+/-) TransformFactoryRandomTranslateXYZ(const XYZ& o,const XYZ& r) :_origin(o) ,_range(r) {} //! Clone method. virtual std::unique_ptr clone() const { return std::unique_ptr(new TransformFactoryRandomTranslateXYZ(_origin,_range)); } //! Return a random Transform virtual const Transform operator()(Random01& rng) const; protected: //! Base value for translations XYZ _origin; //! Range for translations XYZ _range; }; #endif evolvotron-0.8.3/libevolvotron/transform_factory.cpp0000644000175000017500000000605115230700302021547 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation for class TransformFactory. */ #include "transform_factory.h" #include "random.h" #include "transform.h" const Transform TransformFactoryRandomWarpXY::operator()(Random01& r01) const { // Gives a scale between 0.5 and 2, average 1. const real r=pow(2.0,2.0*r01()-1.0); // Random rotation const real a=(2.0*M_PI)*r01(); const XYZ basis_x( r*cos(a), r*sin(a),0.0); const XYZ basis_y(-r*sin(a), r*cos(a),0.0); const XYZ basis_z(0.0,0.0,1.0); // Random translation const real tx=2.0*r01()-1.0; const real ty=2.0*r01()-1.0; const XYZ translate(tx,ty,0.0); return Transform(translate,basis_x,basis_y,basis_z); } const Transform TransformFactoryRandomScaleXY::operator()(Random01& rng) const { const XYZ translate(0.0,0.0,0.0); const real p=rng(); const real s=pow(2.0,_lopow2+p*(_hipow2-_lopow2)); const XYZ basis_x( s,0.0,0.0); const XYZ basis_y(0.0, s,0.0); const XYZ basis_z(0.0,0.0,1.0); return Transform(translate,basis_x,basis_y,basis_z); } const Transform TransformFactoryRandomRotateZ::operator()(Random01& r01) const { // Random rotation const real a=(2.0*M_PI)*r01(); const real ca=cos(a); const real sa=sin(a); const XYZ basis_x( ca, sa,0.0); const XYZ basis_y( -sa, ca,0.0); const XYZ basis_z(0.0,0.0,1.0); const XYZ translate(0.0,0.0,0.0); return Transform(translate,basis_x,basis_y,basis_z); } const Transform TransformFactoryRandomTranslateXYZ::operator()(Random01& r01) const { const XYZ translate(_origin+RandomXYZInBox(r01,_range)); const XYZ basis_x(1.0,0.0,0.0); const XYZ basis_y(0.0,1.0,0.0); const XYZ basis_z(1.0,0.0,1.0); return Transform(translate,basis_x,basis_y,basis_z); } evolvotron-0.8.3/libevolvotron/render_parameters.h0000644000175000017500000000507215230700302021156 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class RenderParameters */ #ifndef _render_parameters_h_ #define _render_parameters_h_ #include "common.h" template bool change(T& dst,const T& src) { const T previous=dst; dst=src; return (dst!=previous); } //! Class encapsulating things affecting rendering class RenderParameters : public QObject { Q_OBJECT; public: RenderParameters(bool jitter,uint multisample,QObject* parent); ~RenderParameters(); //! Accessor. bool jittered_samples() const { return _jittered_samples; } //! Accessor. void jittered_samples(bool v) { if (change(_jittered_samples,v)) report_change(); } //! Accessor. uint multisample_grid() const { assert(_multisample_grid>=1); return _multisample_grid; } //! Accessor. void multisample_grid(uint v) { assert(v>=1); if (change(_multisample_grid,v)) report_change(); } signals: void changed(); protected: void report_change(); private: //! Whether sample points should be randomized. bool _jittered_samples; //! Grid for multisampling. /*! Default is 1. 4 would be 16 samples in a 4x4 grid. */ uint _multisample_grid; }; #endif evolvotron-0.8.3/libevolvotron/render_parameters.cpp0000644000175000017500000000335015230700302021506 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of class MutationParametersQObject. */ #include "useful.h" #include "render_parameters.h" RenderParameters::RenderParameters(bool j,uint m,QObject* parent) :QObject(parent) ,_jittered_samples(j) ,_multisample_grid(clamped(m,1u,4u)) {} RenderParameters::~RenderParameters() {} void RenderParameters::report_change() { emit changed(); } evolvotron-0.8.3/libevolvotron/platform_specific.h0000644000175000017500000000345115230700302021144 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Try to isolate platform specific code here (or rather, in the .cpp implementations) */ #ifndef _platform_specific_h_ #define _platform_specific_h_ #include "../libfunction/useful.h" //! Return the number of processors on the system extern uint get_number_of_processors(); //! Lower the priority of the calling thread by increasing its "niceness" (unix 0-19 'nice' scale used) extern void add_thread_niceness(uint); #endif evolvotron-0.8.3/libevolvotron/platform_specific.cpp0000644000175000017500000000447115230700302021502 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of platform specific functions. */ #include #ifdef __unix__ #include // for getpriority/setprioirty #endif uint get_number_of_processors() { return QThread::idealThreadCount(); } void add_thread_niceness(uint n) { #ifdef __unix__ /*! \todo: People porting to non-Linux (BSD, MacOS, Fink etc) please send a suitable #ifdef-able patch if you need something different here. Note that this code relies on Linux NPTL's non-Posix-compliant thread-specific nice value (although without a suitable replacement per-thread priority mechanism it's just as well it's that way). \todo: Should check some error codes, but it's probably pretty harmless if it doesn't work. */ const int current_priority=getpriority(PRIO_PROCESS,0); setpriority(PRIO_PROCESS,0,std::min(19u,current_priority+n)); #else #warning "No platform-specific implementation of add_thread_niceness available" #endif } evolvotron-0.8.3/libevolvotron/mutation_parameters_qobject.h0000644000175000017500000000366015230700302023247 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class MutationParametersQObject. */ #ifndef _mutation_parameters_qobject_h_ #define _mutation_parameters_qobject_h_ #include "common.h" #include "mutation_parameters.h" //! class extending MutationParameters to emit changed signal when appropriate. class MutationParametersQObject : public QObject, public MutationParameters { Q_OBJECT; public: MutationParametersQObject(uint seed,bool autocool,bool debug_mode,QObject* parent); ~MutationParametersQObject(); signals: void changed(); protected: void report_change(); }; #endif evolvotron-0.8.3/libevolvotron/mutation_parameters_qobject.cpp0000644000175000017500000000343015230700302023575 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of class MutationParametersQObject. */ #include "mutation_parameters_qobject.h" MutationParametersQObject::MutationParametersQObject(uint seed,bool autocool,bool debug_mode,QObject* parent) :QObject(parent) ,MutationParameters(seed,autocool,debug_mode) {} MutationParametersQObject::~MutationParametersQObject() {} void MutationParametersQObject::report_change() { emit changed(); } evolvotron-0.8.3/libevolvotron/mutatable_image_display_big.h0000644000175000017500000000453615230700302023146 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class MutatableImageDisplayBig */ #ifndef _mutatable_image_display_big_h_ #define _mutatable_image_display_big_h_ #include "common.h" class EvolvotronMain; //! Intended to be used as a top-level widget holding a single MutatableImageDisplay /*! We just used to use a display or scroll view itself as a top-level widget, but need this to get some specific keyboard effects. \todo class name is a bit misleading. This is really just a slightly modified top-level holder. */ class MutatableImageDisplayBig : public QWidget { Q_OBJECT protected: //! Pointer back to the application object to access fullscreen state EvolvotronMain* _main; public: //! Constructor. MutatableImageDisplayBig(EvolvotronMain* mn); //! Destructor. virtual ~MutatableImageDisplayBig(); //! Accessor. EvolvotronMain* main() const { assert(_main!=0); return _main; } protected: //! Handle key-presses void keyPressEvent(QKeyEvent* e); }; #endif evolvotron-0.8.3/libevolvotron/mutatable_image_display_big.cpp0000644000175000017500000000521215230700302023471 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of class MutatableImageDisplayBig. */ #include "mutatable_image_display_big.h" #include "evolvotron_main.h" MutatableImageDisplayBig::MutatableImageDisplayBig(EvolvotronMain* mn) :QWidget(mn,Qt::Window) // We're a window, but with a parent ,_main(mn) { setAttribute(Qt::WA_DeleteOnClose,true); } /*! Don't think destructor needs to do anything to _display... Qt takes care of it */ MutatableImageDisplayBig::~MutatableImageDisplayBig() { std::clog << "An enlargement was deleted\n"; } /*! There's not much point in dropping back to normal mode (from fullscreen) if the main app is fullscreen because we'll just be hidden, so close instead under such circumstances. (However, on ctrl-f we put both into normal mode). */ void MutatableImageDisplayBig::keyPressEvent(QKeyEvent* e) { if (e->key()==Qt::Key_Escape) { if (main()->isFullScreen()) close(); else showNormal(); } else if (e->key()==Qt::Key_F && (e->modifiers() & Qt::ControlModifier)) { if (isFullScreen()) { if (main()->isFullScreen()) main()->toggle_fullscreen(); // Need to use this to maintain menu checkmarks showNormal(); } else showFullScreen(); } else { // Perhaps it's for someone else e->ignore(); } } evolvotron-0.8.3/libevolvotron/mutatable_image_display.h0000644000175000017500000002260715230700302022324 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class MutatableImageDisplay */ #ifndef _mutatable_image_display_h_ #define _mutatable_image_display_h_ #include "common.h" #include "mutatable_image.h" #include "mutatable_image_computer.h" #include "dialog_mutatable_image_display.h" class EvolvotronMain; class MutatableImageComputerTask; class Transform; //! Widget responsible for displaying a MutatableImage. /*! A MutatableImageDisplay is responsible for displaying the image computed from the MutatableImage it owns. Computations are split off into separate threads to take advantage of multiprocessor machines. */ class MutatableImageDisplay : public QWidget { Q_OBJECT protected: //! Pointer back to the application object to access services. EvolvotronMain* _main; //! Flag for whether context menu should display all options. /*! false also implies a standalone window */ const bool _full_functionality; //! Flag for whether the offscreen buffer has fixed size const bool _fixed_size; //! Size of offscreen buffer QSize _image_size; //! Number of frames in image uint _frames; //! Framerate for animation. uint _framerate; //! Currently displaying frame. uint _current_frame; //! Direction to play bool _animate_reverse; //! Timer for animating frames QTimer* _timer; //! Flag indicating resize is in progress (between resizeEvent and subsequent paintEvent). /*! Used to supress unnecessary task spawning. */ bool _resize_in_progress; //! The resolution level currently displaying (0=1-for-1 pixels, 1=half resolution etc). /*! Needed to handle possible out of order task returns from multiple compute threads. */ uint _current_display_level; //! Similar to _current_display_level, but for tracking multisample grids within a resolution level. uint _current_display_multisample_grid; //! An image suitable for setting as an icon. std::unique_ptr _icon; //! Track which image the icon is actually of. unsigned long long int _icon_serial; //! Offscreen image buffer. std::vector _offscreen_pixmaps; //! Offscreen image buffer in sensible image format (used for save, as pixmap is in display format which might be less bits). std::vector _offscreen_images; //! Type for staging area for incoming fragments. /*! Key is level and multisampling, mapped type is also itself a map from fragment number to tasks. */ typedef std::map,std::map > > OffscreenImageInbox; //! Staging area for incoming fragments. /*! Fragments are accumulated for each (level,multisample) key, and completed levels passed on for display */ OffscreenImageInbox _offscreen_images_inbox; //! The image function being displayed (its root node). /*! The held image is const because references to it could be held by history archive, compute tasks etc, so it should be completely replaced rather than manipulated. */ boost::shared_ptr _image_function; //! Properties dialog. DialogMutatableImageDisplay* _properties; //! Context (right-click) menu. QMenu* _menu; //! Submenu for spawn warped options. QMenu* _menu_warped; //! Submenu for Big image options. QMenu* _menu_big; //! Position of item in menu. /*! This is the only menu item we need to retain this information for becuase we need it to set the lock check-mark. */ QAction* _menu_item_action_lock; //! Coordinate of mouse event which started mid-button adjustment QPoint _mid_button_adjust_start_pos; //! Coordinate of last mouse event when mid-button adjusting QPoint _mid_button_adjust_last_pos; //! Serial number to kill some rare problems with out-of-order tasks being returned unsigned long long int _serial; public: //! Constructor. MutatableImageDisplay(EvolvotronMain* mn,bool full_functionality,bool fixed_size,const QSize& image_size,uint f,uint fr); //! Destructor. virtual ~MutatableImageDisplay(); //! Accessor. const boost::shared_ptr& image_function() { return _image_function; } //! Accessor. bool locked() const { return (_image_function.get()!=0 ? _image_function->locked() : false); } //! Accessor. EvolvotronMain& main() const { assert(_main!=0); return *_main; } //! Accessor. void main(EvolvotronMain* m) { _main=m; } //! Accessor. const QSize& image_size() const { return _image_size; } //! Load a new image (clears up old image, starts new compute tasks). /*! When the one_of_many parameter is true, it implies many other images are also being updated (affects fragmentation strategy for multithreading). */ void image_function(const boost::shared_ptr& image_fn,bool one_of_many); //! Evolvotron main calls this with completed (but possibly aborted) tasks. void deliver(const boost::shared_ptr& task); //! Set the lock state. void lock(bool l,bool record_in_history); protected: //! Which farm this display should use. MutatableImageComputerFarm& farm() const; //! Take a snapshot to undo back to. void snapshot(const char* name); void mouseTransform(const Transform& tf); //! Usual handler for repaint events. virtual void paintEvent(QPaintEvent* event); //! Usual handler for resize events. virtual void resizeEvent(QResizeEvent* event); //! Handler for mouse events. virtual void mousePressEvent(QMouseEvent* event); //! Handler for mouse events. virtual void mouseMoveEvent(QMouseEvent* event); virtual void wheelEvent(QWheelEvent *event); public slots: //! Simplify the held image, return the number of nodes eliminated uint simplify_constants(bool single); //! Load a function from the given filename. void load_function_file(const QString&); protected slots: //! Called by timer void frame_advance(); //! Called from context menu. void menupick_respawn(); //! Called from context menu and also by click event. void menupick_spawn(); //! Called from context menu. void menupick_spawn_recoloured(); //! Called from context menu. void menupick_spawn_warped_random(); //! Called from context menu. void menupick_spawn_warped_zoom_in(); //! Called from context menu. void menupick_spawn_warped_zoom_out(); //! Called from context menu. void menupick_spawn_warped_rotate(); //! Called from context menu. void menupick_spawn_warped_pan_xy(); //! Called from context menu. void menupick_spawn_warped_pan_x(); //! Called from context menu. void menupick_spawn_warped_pan_y(); //! Called from context menu. void menupick_spawn_warped_pan_z(); //! Called from context menu. void menupick_lock(); //! Trivial wrapper for simplify_constants void menupick_simplify(); //! Called from context menu. void menupick_save_image(); //! Called from context menu. void menupick_save_function(); //! Called from context menu. void menupick_load_function(); //! Called from "Big" submenu of context menu. void menupick_big_resizable(); //! Called from "Big" submenu of context menu. void menupick_big_256x256(); //! Called from "Big" submenu of context menu. void menupick_big_512x512(); //! Called from "Big" submenu of context menu. void menupick_big_768x768(); //! Called from "Big" submenu of context menu. void menupick_big_1024x1024(); //! Called from "Big" submenu of context menu. void menupick_big_640x480(); //! Called from "Big" submenu of context menu. void menupick_big_1024x768(); //! Called from "Big" submenu of context menu. void menupick_big_1280x960(); //! Called from "Big" submenu of context menu. void menupick_big_1600x1200(); //! Called from "Big" submenu of context menu. void menupick_big_2048x2048(); //! Called from "Big" submenu of context menu. void menupick_big_4096x4096(); //! Called from "Properties" on context menu void menupick_properties(); protected: //! Common code for big slots. void spawn_big(int w, int h); }; #endif evolvotron-0.8.3/libevolvotron/mutatable_image_display.cpp0000644000175000017500000010040515230700302022650 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of class MutatableImageDisplay. */ #include "mutatable_image_display.h" #include "mutatable_image_display_big.h" #include "evolvotron_main.h" #include "mutatable_image_computer_task.h" #include "transform_factory.h" #include "function_pre_transform.h" #include "function_top.h" /*! The constructor is passed: - the owning widget (probably either a QGrid or null if top-level), - the EvolvotronMain providing spawn and farm services, - a flag to specify whether this is a fully functional display or a restricted one (e.g no spawning for a single top level display), - a flag to specify whether the offscreen buffer has fixed size (in which case scrollbars may be used), - and the size of the offscreen buffer (only used if fixed_size is true). Note that we use Qt's WDestructiveCode flag to ensure the destructor is called on close */ MutatableImageDisplay::MutatableImageDisplay(EvolvotronMain* mn,bool full_functionality,bool fixed_size,const QSize& sz,uint f,uint fr) :_main(mn) ,_full_functionality(full_functionality) ,_fixed_size(fixed_size) ,_image_size(sz) ,_frames(f) ,_framerate(fr) ,_current_frame(0) ,_animate_reverse(false) ,_timer(0) ,_resize_in_progress(false) ,_current_display_level(0) ,_current_display_multisample_grid(0) ,_icon_serial(0LL) ,_properties(0) ,_menu(0) ,_menu_big(0) ,_menu_item_action_lock(0) ,_serial(0LL) { setAttribute(Qt::WA_DeleteOnClose,true); setFocusPolicy(Qt::StrongFocus); _properties=new DialogMutatableImageDisplay(this); _menu=new QMenu(this); // Most items on the context menu aren't appropriate for a window displaying a single big image if (_full_functionality) { _menu->addAction("Respawn",this,SLOT(menupick_respawn())); _menu->addSeparator(); _menu->addAction("Spawn",this,SLOT(menupick_spawn())); _menu->addAction("Spawn recoloured",this,SLOT(menupick_spawn_recoloured())); _menu_warped=_menu->addMenu("Spawn warped"); _menu_warped->addAction("Random Mix",this,SLOT(menupick_spawn_warped_random()) ); _menu_warped->addAction("Zoom In" ,this,SLOT(menupick_spawn_warped_zoom_in()) ); _menu_warped->addAction("Zoom Out" ,this,SLOT(menupick_spawn_warped_zoom_out())); _menu_warped->addAction("Rotate" ,this,SLOT(menupick_spawn_warped_rotate()) ); _menu_warped->addAction("Pan XY" ,this,SLOT(menupick_spawn_warped_pan_xy()) ); _menu_warped->addAction("Pan X" ,this,SLOT(menupick_spawn_warped_pan_x()) ); _menu_warped->addAction("Pan Y" ,this,SLOT(menupick_spawn_warped_pan_y()) ); _menu_warped->addAction("Pan Z" ,this,SLOT(menupick_spawn_warped_pan_z()) ); _menu->addSeparator(); _menu_item_action_lock=_menu->addAction("Lock",this,SLOT(menupick_lock())); _menu_item_action_lock->setCheckable(true); _menu->addSeparator(); } _menu_big=_menu->addMenu("Enlarge"); _menu_big->addAction("Resizable",this,SLOT(menupick_big_resizable())); _menu_big->addSeparator(); _menu_big->addAction("256x256" ,this,SLOT(menupick_big_256x256())); _menu_big->addAction("512x512" ,this,SLOT(menupick_big_512x512()) ); _menu_big->addAction("768x768" ,this,SLOT(menupick_big_768x768()) ); _menu_big->addAction("1024x1024",this,SLOT(menupick_big_1024x1024())); _menu_big->addAction("2048x2048",this,SLOT(menupick_big_2048x2048())); _menu_big->addAction("4096x4096",this,SLOT(menupick_big_4096x4096())); _menu_big->addSeparator(); _menu_big->addAction("640x480" ,this,SLOT(menupick_big_640x480()) ); _menu_big->addAction("1024x768" ,this,SLOT(menupick_big_1024x768()) ); _menu_big->addAction("1280x960" ,this,SLOT(menupick_big_1280x960()) ); _menu_big->addAction("1600x1200",this,SLOT(menupick_big_1600x1200())); _menu->addSeparator(); _menu->addAction("Save image...",this,SLOT(menupick_save_image())); _menu->addAction("Save function...",this,SLOT(menupick_save_function())); if (_full_functionality) { _menu->addAction("Load function...",this,SLOT(menupick_load_function())); } _menu->addSeparator(); _menu->addAction("Simplify function",this,SLOT(menupick_simplify())); _menu->addAction("Properties...",this,SLOT(menupick_properties())); main().hello(this); if (_fixed_size) { setGeometry(0,0,image_size().width(),image_size().height()); } for (uint f=0;f<_frames;f++) { _offscreen_pixmaps.push_back(QPixmap()); } _timer=new QTimer(this); connect ( _timer,SIGNAL(timeout()), this,SLOT(frame_advance()) ); if (_frames>1) _timer->start(1000/_framerate); } /*! Destructor signs off from EvolvotronMain to prevent further attempts at completed task delivery. */ MutatableImageDisplay::~MutatableImageDisplay() { assert(!_image_function.get() || _image_function->ok()); // During app shutdown EvolvotronMain might have already been destroyed so only call it if it's there. // Don't use main() because it asserts non-null. if (_main) { farm().abort_for(this); main().goodbye(this); } _image_function.reset(); _offscreen_pixmaps.clear(); _offscreen_images.clear(); } uint MutatableImageDisplay::simplify_constants(bool single_action) { if (single_action) main().history().begin_action("simplify"); uint old_nodes; uint old_parameters; uint old_depth; uint old_width; real old_const; _image_function->get_stats(old_nodes,old_parameters,old_depth,old_width,old_const); main().history().replacing(this); image_function(_image_function->simplified(),!single_action); uint new_nodes; uint new_parameters; uint new_depth; uint new_width; real new_const; _image_function->get_stats(new_nodes,new_parameters,new_depth,new_width,new_const); const uint nodes_eliminated=old_nodes-new_nodes; if (single_action) main().history().end_action(); if (single_action) { std::stringstream msg; msg << "Eliminated " << nodes_eliminated << " redundant function nodes\n"; QMessageBox::information(this,"Evolvotron",msg.str().c_str(),QMessageBox::Ok); } return nodes_eliminated; } void MutatableImageDisplay::frame_advance() { assert(!(_current_frame==0 && _animate_reverse==true)); assert(!(_current_frame==_frames-1 && _animate_reverse==false)); if (_animate_reverse) { _current_frame--; if (_current_frame==0) { _animate_reverse=false; } } else { _current_frame++; if (_current_frame==_frames-1) { _animate_reverse=true; } } repaint(); // Use repaint rather than update because we really do want this to happen immediately. } void MutatableImageDisplay::image_function(const boost::shared_ptr& i,bool one_of_many) { assert(_image_function.get()==0 || _image_function->ok()); assert(i.get()==0 || i->ok()); // New image, so increment serial number so any old incoming stuff which somehow avoids abort is ignored. _serial++; // This might have already been done (e.g by resizeEvent), but it can't hurt to be sure. farm().abort_for(this); // Careful: we could be passed our own existing (and already owned) image // (a trick used by resize to trigger recompute & redisplay) if (i.get()==0 || _image_function.get()==0 || i->serial()!=_image_function->serial()) { _image_function=i; // If we're part of a fullscale change then better to display back rather than something misleading // but for one-offs (e.g middle mouse drag) is better not to clear. if (one_of_many) { // Clear any existing image data - stops old animations continuing to play for (uint f=0;f<_offscreen_pixmaps.size();f++) _offscreen_pixmaps[f].fill(QColor(0,0,0)); // Queue a redraw update(); } } // If we start recomputing again we need to accept any delivered images. _current_display_level=static_cast(-1); _current_display_multisample_grid=static_cast(-1); // Clear up staging area... its contents are now useless _offscreen_images_inbox.clear(); // Update lock status displayed in menu if (_menu_item_action_lock) _menu_item_action_lock->setChecked(_image_function.get() ? _image_function->locked() : false); if (_image_function.get()) { // Allow for displays up to 4096 pixels high or wide for (int level=12;level>=0;level--) { const int s=(1<=4 && render_size.height()>=4) || level==0) { const int fragments =( one_of_many ? 1 : std::min ( 2*farm().num_threads(), static_cast(render_size.height()) ) ); std::vector multisample_grid; multisample_grid.push_back(1); if (level==0) { // Only the final full resolution level gets an additional multisampling task. // For 4x4 sampling, do an initial 2x2 too. if (main().render_parameters().multisample_grid()==4) multisample_grid.push_back(2); if (main().render_parameters().multisample_grid()>1) multisample_grid.push_back(main().render_parameters().multisample_grid()); } for (std::vector::const_iterator multisample_it=multisample_grid.begin();multisample_it!=multisample_grid.end();multisample_it++) { //! \todo Should computed animation frames be constant or reduced c.f spatial resolution ? (Do full z resolution for now) const boost::shared_ptr task_image(_image_function); assert(task_image->ok()); // Use number of samples in unfragmented image as priority const uint task_priority=render_size.width()*render_size.height()*(*multisample_it)*(*multisample_it); int fragment_start_row=0; for (int f=0;f task ( new MutatableImageComputerTask ( this, task_image, task_priority, QSize(0,fragment_start_row), QSize(render_size.width(),fragment_end_row-fragment_start_row), render_size, _frames, level, f, fragments, main().render_parameters().jittered_samples(), (*multisample_it), _serial ) ); farm().push_todo(task); fragment_start_row=fragment_end_row; } } } } } } void MutatableImageDisplay::deliver(const boost::shared_ptr& task) { // Ignore tasks which were aborted or which have somehow got out of order // (entirely possible with multiple compute threads). if ( task->aborted() || task->serial()!=_serial || task->level()>_current_display_level || (task->level()==_current_display_level && task->multisample_grid()<=_current_display_multisample_grid) ) return; // Record the fragment in the inbox const OffscreenImageInbox::key_type inbox_key(task->level(),task->multisample_grid()); OffscreenImageInbox::mapped_type& inbox_level=_offscreen_images_inbox[inbox_key]; assert(inbox_level.find(task->fragment())==inbox_level.end()); inbox_level[task->fragment()]=task; if (inbox_level.size()!=task->number_of_fragments()) return; // If the level is complete, we can proceed to displaying it // Note that obsolete levels will never complete once a better one is displayed. // So clear up previous levels; they're now irrelevant _offscreen_images_inbox.erase ( _offscreen_images_inbox.upper_bound(inbox_key), // upper_bound is the NEXT key from the one we're about to display _offscreen_images_inbox.end() ); const QSize render_size(task->whole_image_size()); if (task->number_of_fragments()==1) { // If there's only one fragment in the task, just use it _offscreen_images=task->images(); } else { // Otherwise we need to assemble the fragments together _offscreen_images.resize(0); for (uint f=0;f<_frames;f++) { _offscreen_images.push_back(QImage(render_size,QImage::Format_RGB32)); for (OffscreenImageInbox::mapped_type::const_iterator it=inbox_level.begin();it!=inbox_level.end();++it) { QPainter painter(&_offscreen_images.back()); painter.drawImage ( QPoint((*it).second->fragment_origin().width(),(*it).second->fragment_origin().height()), (*it).second->images()[f] ); } } } for (uint f=0;f<_frames;f++) { //! \todo Pick a scaling mode: Qt::SmoothTransformation vs Qt::FastTransformation (default) (and put it under GUI control). //! \todo Expose dither mode control: Qt::DiffuseDither vs Qt::ThresholdDither _offscreen_pixmaps[f]=QPixmap::fromImage(_offscreen_images[f].scaled(image_size()),(Qt::ColorOnly|Qt::ThresholdDither)); } //! Note the resolution we've displayed so out-of-order low resolution images are dropped _current_display_level=task->level(); _current_display_multisample_grid=task->multisample_grid(); // For an icon, take the first image big enough to (hopefully) be filtered down nicely. // The (Qt3) converter seems to auto-create an alpha mask sometimes (images with const-color areas), which is quite cool. const QSize icon_size(32,32); if (task->serial()!=_icon_serial && (task->level()==0 || (render_size.width()>=2*icon_size.width() && render_size.height()>=2*icon_size.height()))) { const QImage icon_image(_offscreen_images[_offscreen_images.size()/2].scaled(icon_size)); if (!_icon.get()) _icon=std::unique_ptr(new QPixmap(icon_size)); (*_icon)=QPixmap::fromImage(icon_image,Qt::ColorOnly); _icon_serial=task->serial(); } // Update what's on the screen. update(); } void MutatableImageDisplay::lock(bool l,bool record_in_history) { // This might be called (with l=false) with null _image during start-up reset. if (_image_function && _image_function->locked()!=l) { if (record_in_history) { main().history().begin_action(l ? "lock" : "unlock"); main().history().replacing(this); } const boost::shared_ptr new_image_function(_image_function->deepclone(l)); image_function(new_image_function,false); if (record_in_history) { main().history().end_action(); } } _menu_item_action_lock->setChecked(l); } /*! Enlargements are implied by a non-full-functionality displays. */ MutatableImageComputerFarm& MutatableImageDisplay::farm() const { return main().farm(!_full_functionality); } void MutatableImageDisplay::paintEvent(QPaintEvent*) { // Repaint the screen from the offscreen pixmaps QPainter painter(this); painter.drawPixmap(0,0,_offscreen_pixmaps[_current_frame]); if (_full_functionality && locked()) { const QPixmap& pix = _main->lockPix; painter.drawPixmap(width() - (pix.width()+2), 2, pix); } // If this is the first paint event after a resize we can start computing images for the new size. if (_resize_in_progress) { image_function(_image_function,false); // A resize should really be considered one-of-many, but because the image doesn't change we seem to be able to get away with it _resize_in_progress=false; } } /*! In the resize event we just focus on shutting down existing compute threads because they'll all have to be restarted. NB Multiple resize events can be received before a repaint occurs. NB There's nothing to be done for fixed size images (not even setting _resize_in_progress). */ void MutatableImageDisplay::resizeEvent(QResizeEvent* event) { // Fixed size images don't need anything doing here. We don't even set _resize_in_progress. if (!_fixed_size) { _image_size=event->size(); // Abort all current tasks because they'll be the wrong size. farm().abort_for(this); // Resize and reset our offscreen pixmap (something to do while we wait) for (uint f=0;f<_offscreen_pixmaps.size();f++) { _offscreen_pixmaps[f]=QPixmap(image_size()); _offscreen_pixmaps[f].fill(QColor(0,0,0)); } // Flag for the next paintEvent to tell it a recompute can be started now. _resize_in_progress=true; } } void MutatableImageDisplay::snapshot(const char* name) { main().history().begin_action(name); main().history().replacing(this); main().history().end_action(); } #if QT_VERSION >= 0x060000 #define POS_X(ev) int(ev->position().x()) #define POS_Y(ev) int(ev->position().y()) #else #define POS_X(ev) ev->x() #define POS_Y(ev) ev->y() #endif void MutatableImageDisplay::mousePressEvent(QMouseEvent* event) { if (event->button()==Qt::RightButton) { _menu->exec(QCursor::pos()); } else if (event->button() == Qt::MiddleButton) { snapshot("middle-button drag"); _mid_button_adjust_start_pos=event->pos(); _mid_button_adjust_last_pos=event->pos(); } else if (_full_functionality && event->button()==Qt::LeftButton) { if (POS_X(event) > (width() - 32) && POS_Y(event) < 32) { menupick_lock(); } else { menupick_spawn(); } } } void MutatableImageDisplay::mouseTransform(const Transform& tf) { std::unique_ptr new_root(image_function()->top().typed_deepclone()); new_root->concatenate_pretransform_on_right(tf); // Install new image (triggers recompute). const boost::shared_ptr new_image_function(new MutatableImage(new_root,image_function()->sinusoidal_z(),image_function()->spheremap(),false)); image_function(new_image_function,false); } void MutatableImageDisplay::mouseMoveEvent(QMouseEvent* event) { if (event->buttons() & Qt::MiddleButton) { if (locked()) { QMessageBox::warning(this,"Evolvotron","Cannot middle-mouse adjust a locked image.\nUnlock and try again."); } else { const QPoint pixel_delta(event->pos()-_mid_button_adjust_last_pos); // Build the transform caused by the adjustment Transform transform=TransformIdentity(); // Shift button (no ctrl) is various zooms if (event->modifiers()&Qt::ShiftModifier && !(event->modifiers()&Qt::ControlModifier)) { // Alt-Shift is anisotropic if (event->modifiers()&Qt::AltModifier) { // Only scale in non-degenerate cases if ( event->pos().x()!=image_size().width()/2 && event->pos().y()!=image_size().height()/2 && _mid_button_adjust_last_pos.x()!=image_size().width()/2 && _mid_button_adjust_last_pos.y()!=image_size().height()/2 ) { XYZ scale( (event->pos().x()-image_size().width() /2) / static_cast(_mid_button_adjust_last_pos.x()-image_size().width() /2), (event->pos().y()-image_size().height()/2) / static_cast(_mid_button_adjust_last_pos.y()-image_size().height()/2), 0.0 ); transform.basis_x(XYZ(1.0/scale.x(), 0.0,0.0)); transform.basis_y(XYZ( 0.0,1.0/scale.y(),0.0)); std::clog << "[Anisotropic scale]"; } } // Shift button alone is isotropic zoom else { const real cx=image_size().width()/2.0; const real cy=image_size().width()/2.0; const real dx=event->pos().x()-cx; const real dy=event->pos().y()-cy; const real last_dx=_mid_button_adjust_last_pos.x()-cx; const real last_dy=_mid_button_adjust_last_pos.y()-cy; const real radius=sqrt(dx*dx+dy*dy); const real last_radius=sqrt(last_dx*last_dx+last_dy*last_dy); // Only scale in non-degenerate cases if (radius!=0.0 && last_radius!=0.0) { const real scale=radius/last_radius; transform.basis_x(XYZ(1.0/scale, 0.0,0.0)); transform.basis_y(XYZ( 0.0,1.0/scale,0.0)); std::clog << "[Isotropic scale]"; } } } else if (event->modifiers()&Qt::ControlModifier) { // Control-alt is shear if (event->modifiers()&Qt::AltModifier) { const real cx=image_size().width()/2.0; const real cy=image_size().width()/2.0; const real dx=(event->pos().x()-_mid_button_adjust_last_pos.x())/cx; const real dy=(event->pos().y()-_mid_button_adjust_last_pos.y())/cy; transform.basis_x(XYZ(1.0, -dy,0.0)); transform.basis_y(XYZ( dx,1.0,0.0)); std::clog << "[Shear]"; } // Control button only is rotate else { const real cx=image_size().width()/2.0; const real cy=image_size().width()/2.0; const real dx=event->pos().x()-cx; const real dy=event->pos().y()-cy; const real last_dx=_mid_button_adjust_last_pos.x()-cx; const real last_dy=_mid_button_adjust_last_pos.y()-cy; const real a=atan2(dy,dx); const real last_a=atan2(last_dy,last_dx); const real rot=a-last_a; const real sr=sin(rot); const real cr=cos(rot); transform.basis_x(XYZ( cr,sr,0.0)); transform.basis_y(XYZ(-sr,cr,0.0)); std::clog << "[Rotate]"; } } // Default (no interesting modifier keys detected) is panning around else { XYZ translate( (-2.0*pixel_delta.x())/image_size().width(), ( 2.0*pixel_delta.y())/image_size().height(), 0.0 ); transform.translate(translate); std::clog << "[Pan]"; } mouseTransform(transform); // Finally, record position of this event as last event _mid_button_adjust_last_pos=event->pos(); } } } void MutatableImageDisplay::wheelEvent(QWheelEvent *event) { int dy = event->angleDelta().y() / 120; if (dy) { if (! main().history().last_action_named(this, "mouse-wheel")) snapshot("mouse-wheel"); real scale = 1.0; for (; dy > 0; --dy) scale *= 0.8; for (; dy < 0; ++dy) scale *= 1.2; Transform tf; tf.translate(XYZ(0.0, 0.0, 0.0)); tf.basis_x(XYZ(scale, 0.0, 0.0)); tf.basis_y(XYZ(0.0, scale, 0.0)); tf.basis_z(XYZ(0.0, 0.0, 1.0)); mouseTransform(tf); } } /*! This slot is called by selecting the "Respawn" context menu item */ void MutatableImageDisplay::menupick_respawn() { main().respawn(this); } /*! This slot is called by selecting the "Spawn" context menu item, or by clicking the image */ void MutatableImageDisplay::menupick_spawn() { main().spawn_normal(this); } /*! This slot is called by selecting the "Spawn Recoloured" context menu item */ void MutatableImageDisplay::menupick_spawn_recoloured() { main().spawn_recoloured(this); } /*! This slot is called by selecting the "Spawn Warped/Random" context menu item */ void MutatableImageDisplay::menupick_spawn_warped_random() { TransformFactoryRandomWarpXY transform_factory; main().spawn_warped(this,transform_factory); } void MutatableImageDisplay::menupick_spawn_warped_zoom_in() { TransformFactoryRandomScaleXY transform_factory(-2.0,0.0); main().spawn_warped(this,transform_factory); } void MutatableImageDisplay::menupick_spawn_warped_zoom_out() { TransformFactoryRandomScaleXY transform_factory(0.0,2.0); main().spawn_warped(this,transform_factory); } void MutatableImageDisplay::menupick_spawn_warped_rotate() { TransformFactoryRandomRotateZ transform_factory; main().spawn_warped(this,transform_factory); } void MutatableImageDisplay::menupick_spawn_warped_pan_xy() { TransformFactoryRandomTranslateXYZ transform_factory(XYZ(0.0,0.0,0.0),XYZ(1.0,1.0,0.0)); main().spawn_warped(this,transform_factory); } void MutatableImageDisplay::menupick_spawn_warped_pan_x() { TransformFactoryRandomTranslateXYZ transform_factory(XYZ(0.0,0.0,0.0),XYZ(1.0,0.0,0.0)); main().spawn_warped(this,transform_factory); } void MutatableImageDisplay::menupick_spawn_warped_pan_y() { TransformFactoryRandomTranslateXYZ transform_factory(XYZ(0.0,0.0,0.0),XYZ(0.0,1.0,0.0)); main().spawn_warped(this,transform_factory); } void MutatableImageDisplay::menupick_spawn_warped_pan_z() { TransformFactoryRandomTranslateXYZ transform_factory(XYZ(0.0,0.0,0.0),XYZ(0.0,0.0,1.0)); main().spawn_warped(this,transform_factory); } /*! This slot is called by selecting the "Lock" context menu item. It stops the image from being overwritten by a new image. */ void MutatableImageDisplay::menupick_lock() { lock(!_image_function->locked(),true); } void MutatableImageDisplay::menupick_simplify() { simplify_constants(true); } /*! Saves image (unless the image is not full resolution yet, in which case an informative dialog is generated. */ void MutatableImageDisplay::menupick_save_image() { std::clog << "Save requested...\n"; if (_current_display_level!=0 || _current_display_multisample_grid!=main().render_parameters().multisample_grid()) { QMessageBox::information(this,"Evolvotron","The selected image has not yet been generated at maximum resolution.\nPlease try again later."); } else { const QString save_filename = QFileDialog::getSaveFileName(this, "Save image to a PNG or PPM file", _main->imagePath, "Images (*.png *.ppm)" ); if (! save_filename.isEmpty()) { QString save_format="PNG"; if (save_filename.endsWith(".ppm", Qt::CaseInsensitive)) { save_format="PPM"; } else if (! save_filename.endsWith(".png", Qt::CaseInsensitive)) { QMessageBox::warning(this, "Evolvotron", QString("Unrecognised file suffix.\nFile will be written in ")+save_format+QString(" format.") ); } bool ok = true; for (uint f=0;f<_offscreen_images.size();f++) { QString actual_save_filename(save_filename); if (_offscreen_images.size()>1) { QString frame_component = QString::asprintf(".f%06d",f); int insert_point = save_filename.lastIndexOf('.'); if (insert_point==-1) actual_save_filename.append(frame_component); else actual_save_filename.insert(insert_point,frame_component); } if (!_offscreen_images[f].save(actual_save_filename,save_format.toLocal8Bit())) { QMessageBox::critical(this,"Evolvotron","Failed to write file "+actual_save_filename); if (f<_offscreen_images.size()-1) { QMessageBox::critical(this,"Evolvotron","Not attempting to save remaining images in animation"); } ok = false; break; } } if (ok) _main->imagePath = save_filename; } } std::clog << "...save done\n"; } void MutatableImageDisplay::menupick_save_function() { const QString fn = QFileDialog::getSaveFileName(this, "Save image function to an XML file", _main->functionPath, "Functions (*.xml)" ); if (! fn.isEmpty()) { std::ofstream file(fn.toLocal8Bit()); _image_function->save_function(file); file.flush(); if (file) _main->functionPath = fn; else QMessageBox::critical(this,"Evolvotron","File write failed"); } } void MutatableImageDisplay::load_function_file(const QString& load_filename) { const std::string filename(load_filename.toLocal8Bit()); std::ifstream file(filename.c_str()); if (!file) { QMessageBox::critical( this, "Evolvotron", ("Filename '"+filename+"' could not be opened\n").c_str() ); } else { std::string report; boost::shared_ptr new_image_function(MutatableImage::load_function(_main->mutation_parameters().function_registry(),file,report)); if (new_image_function.get()==0) { QMessageBox::critical( this, "Evolvotron", ("Function in filename '"+filename+"' not loaded due to errors:\n"+report).c_str() ); } else { if (!report.empty()) { QMessageBox::warning( this, "Evolvotron", ("Function in filename '"+filename+"' +loaded with warnings:\n"+report).c_str(), QMessageBox::Ok, QMessageBox::NoButton ); } snapshot("load"); image_function(new_image_function,false); } } } void MutatableImageDisplay::menupick_load_function() { const QString fn = QFileDialog::getOpenFileName(this, "Load image function from an XML file", _main->functionPath, "Functions (*.xml)" ); if (! fn.isEmpty()) { _main->functionPath = fn; load_function_file(fn); } } void MutatableImageDisplay::menupick_big_resizable() { spawn_big(0,0); } void MutatableImageDisplay::menupick_big_640x480() { spawn_big(640,480); } void MutatableImageDisplay::menupick_big_1024x768() { spawn_big(1024,768); } void MutatableImageDisplay::menupick_big_1280x960() { spawn_big(1280,960); } void MutatableImageDisplay::menupick_big_1600x1200() { spawn_big(1600,1200); } void MutatableImageDisplay::menupick_big_256x256() { spawn_big(256,256); } void MutatableImageDisplay::menupick_big_512x512() { spawn_big(512,512); } void MutatableImageDisplay::menupick_big_768x768() { spawn_big(768,768); } void MutatableImageDisplay::menupick_big_1024x1024() { spawn_big(1024,1024); } void MutatableImageDisplay::menupick_big_2048x2048() { spawn_big(2048,2048); } void MutatableImageDisplay::menupick_big_4096x4096() { spawn_big(4096,4096); } void MutatableImageDisplay::menupick_properties() { uint total_nodes; uint total_parameters; uint depth; uint width; real proportion_constant; image_function()->get_stats(total_nodes,total_parameters,depth,width,proportion_constant); std::stringstream msg; msg << " " << total_nodes << "\t function nodes\n"; msg << " " << total_parameters << "\t parameters\n"; msg << " " << depth << "\t maximum depth\n"; msg << " " << width << "\t width\n"; msg << " " << std::setprecision(3) << 100.0*proportion_constant << "%\t constant\n"; std::stringstream xml; image_function()->save_function(xml); _properties->set_content(msg.str(),xml.str()); _properties->exec(); } /*! Create an image display as a top level window. Disable full menu functionality because there's less we can do with a single image (e.g no spawn_target) \param w Fixed pixel width or zero if resizeable. \param h Fixed pixel height or zero if resizeable. */ void MutatableImageDisplay::spawn_big(int w, int h) { MutatableImageDisplayBig*const window = new MutatableImageDisplayBig(&main()); QBoxLayout* lo = new QVBoxLayout; lo->setContentsMargins(0, 0, 0, 0); window->setLayout(lo); bool fixedSize = (w && h); MutatableImageDisplay* display = new MutatableImageDisplay(&main(),false,fixedSize,QSize(w,h),_frames,_framerate); if (fixedSize) { window->setWindowTitle(QString::asprintf("Image (%dx%d)",w,h)); if (w <= 512 && h <= 512) { window->setFixedSize(w, h); lo->addWidget(display); } else { QScrollArea*const scrollview=new QScrollArea; scrollview->setMinimumSize(256, 256); //scrollview->setMaximumSize(w, h); scrollview->setWidget(display); lo->addWidget(scrollview); } } else { window->setWindowTitle("Image (resizeable)"); window->setMinimumSize(256, 256); window->resize(512, 512); lo->addWidget(display); } window->show(); //Propagate full screen mode if (main().isFullScreen()) window->showFullScreen(); // Fire up image calculation display->image_function(_image_function,false); } evolvotron-0.8.3/libevolvotron/mutatable_image_computer_task.h0000644000175000017500000001560715230700302023541 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class MutatableImageComputerTask. */ #ifndef _mutatable_image_computer_task_h_ #define _mutatable_image_computer_task_h_ #include "common.h" #include "mutatable_image.h" #include "mutatable_image_display.h" //! Class encapsulating all the parameters of, and output from, a single image generation run. class MutatableImageComputerTask { protected: //! Flag indicating (to compute thread) that this task should be aborted. Also indicates to MutatableImageDisplay that it's a dud and shouldn't be displayed.. /*! \todo Think more about whether this needs to be mutex protected for sanity. */ bool _aborted; //! The display originating the task, and to which the output will be returned. MutatableImageDisplay*const _display; //! The root node of the image tree to be generated. /*! Constness of the MutatableImage referenced is important as the instance is shared between all tasks and the original display. */ const boost::shared_ptr _image_function; //! Task priority. /*! Low numbers go to the head of the queue. The total number of samples in the complete (non-fragmented) image is used, so small low resolution images which can be quickly completed are run first. */ const uint _priority; //! The origin (on the display) of the image being generated. const QSize _fragment_origin; //! The size of the image to be generated. const QSize _fragment_size; //! The full size of the image of which this is a fragment. const QSize _whole_image_size; //! Number of animation frames to be rendered const uint _frames; //! The resolution level of this image (0=1-for-1 pixels, 1=half res etc) /*! This is tracked because multiple compute threads could return the completed tasks out of order (Unlikely given the huge difference in the amount of compute between levels, but possible). */ const uint _level; //! The fragment number, used when a rendering job is split into multiple fragments. const uint _fragment; //! The number of fragments in the rendering job const uint _number_of_fragments; //! Whether samples should be jittered. const bool _jittered_samples; //! Multisampling grid resolution e.g 4 implies a 4x4 grid const uint _multisample_grid; //@{ //! Track pixels computed, so tasks can be restarted after defer. Row and column are relative to the fragment origin. uint _current_pixel; int _current_col; int _current_row; uint _current_frame; //@} //! The image data generated for the fragments. /*! This is lazily created to avoid multiple high resolution images (especially with multisampling) being unnecessarily concurrently allocated. */ mutable std::vector _images; //! Lazy allocator for _images (which is mutable) void allocate_images() const; //! Set true by pixel_advance when it advances off the last frame. bool _completed; //! Serial number, to fix some occasional out-of-order display problems unsigned long long int _serial; public: //! Constructor. MutatableImageComputerTask ( MutatableImageDisplay*const disp, const boost::shared_ptr& fn, uint pri, const QSize& fo, const QSize& fs, const QSize& wis, uint f, uint lev, uint frag, uint nfrag, bool j, uint ms, unsigned long long int n ); //! Destructor. ~MutatableImageComputerTask(); //! Accessor. bool aborted() const { return _aborted; } //! Mark task as aborted. void abort() { _aborted=true; } //! Accessor. MutatableImageDisplay* display() const { return _display; } //! Accessor. const boost::shared_ptr& image_function() const { return _image_function; } //! Accessor. const QSize& fragment_origin() const { return _fragment_origin; } //! Accessor. const QSize& fragment_size() const { return _fragment_size; } //! Accessor. const QSize& whole_image_size() const { return _whole_image_size; } //! Accessor. uint frames() const { return _frames; } //! Accessor. uint level() const { return _level; } //! Accessor. uint fragment() const { return _fragment; } //! Accessor. uint number_of_fragments() const { return _number_of_fragments; } //! Accessor. bool jittered_samples() const { return _jittered_samples; } //! Accessor. uint multisample_grid() const { return _multisample_grid; } //! Serial number unsigned long long int serial() const { return _serial; } //! Accessor. uint priority() const { return _priority; } //! Accessor, with lazy creation. std::vector& images() { if (_images.empty()) allocate_images(); return _images; } //! Accessor. const std::vector& images() const { if (_images.empty()) allocate_images(); return _images; } //! Accessor. uint current_col() const { return _current_col; } //! Accessor. uint current_row() const { return _current_row; } //! Accessor. uint current_frame() const { return _current_frame; } //! Accessor. uint current_pixel() const { return _current_pixel; } //!Accessor. bool completed() const { return _completed; } //! Increment pixel count, set completed flag if advanced off end of last frame. void pixel_advance(); }; #endif evolvotron-0.8.3/libevolvotron/mutatable_image_computer_task.cpp0000644000175000017500000000627015230700302024070 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of class MutatableImageComputerTask */ #include "mutatable_image_computer_task.h" MutatableImageComputerTask::MutatableImageComputerTask ( MutatableImageDisplay*const disp, const boost::shared_ptr& fn, uint pri, const QSize& fo, const QSize& fs, const QSize& wis, uint f, uint lev, uint frag, uint nfrag, bool j, uint ms, unsigned long long int n ) :_aborted(false) ,_display(disp) ,_image_function(fn) ,_priority(pri) ,_fragment_origin(fo) ,_fragment_size(fs) ,_whole_image_size(wis) ,_frames(f) ,_level(lev) ,_fragment(frag) ,_number_of_fragments(nfrag) ,_jittered_samples(j) ,_multisample_grid(ms) ,_current_pixel(0) ,_current_col(0) ,_current_row(0) ,_current_frame(0) ,_completed(false) ,_serial(n) { /* std::cerr << "[" << _number_of_fragments << ":" << _fragment_size.width() << "x" << _fragment_size.height() << " in " << _whole_image_size.width() << "x" << _whole_image_size.height() << "]"; */ assert(_image_function->ok()); assert(_fragment<_number_of_fragments); assert(_number_of_fragments>1 || _whole_image_size==_fragment_size); assert(1<=_multisample_grid); } void MutatableImageComputerTask::allocate_images() const { for (uint f=0;fok()); } void MutatableImageComputerTask::pixel_advance() { _current_pixel++; _current_col++; if (_current_col==fragment_size().width()) { _current_col=0; _current_row++; if (_current_row==fragment_size().height()) { _current_row=0; _current_frame++; if (_current_frame==frames()) { _completed=true; } } } } evolvotron-0.8.3/libevolvotron/mutatable_image_computer_farm.h0000644000175000017500000001247015230700302023517 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class MutatableImageComputerFarm. */ #ifndef _mutatable_image_computer_farm_h_ #define _mutatable_image_computer_farm_h_ #include "common.h" #include "useful.h" #include "mutatable_image_computer.h" #include "mutatable_image_computer_task.h" class MutatableImageComputer; class MutatableImageDisplay; //! Class encapsulating some compute threads and queues of tasks to be done and tasks completed. /*! Priority queues are implemented using multiset becase we want to be able to iterate over all members. */ class MutatableImageComputerFarm { protected: //! Comparison class for STL template. class CompareTaskPriorityLoResFirst { public: //! Compare task priorities. bool operator()(const boost::shared_ptr& t0,const boost::shared_ptr& t1) const { return (t0->priority() < t1->priority()); } }; //! Comparison class for STL template. class CompareTaskPriorityHiResFirst { public: //! Compare task priorities. bool operator()(const boost::shared_ptr& t0,const boost::shared_ptr& t1) const { return (t0->priority() > t1->priority()); } }; //! Mutex for locking. This is the ONLY thing the compute threads should ever block on. mutable QMutex _mutex; //! Wait condition for threads waiting for a new task. QWaitCondition _wait_condition; //! The compute threads boost::ptr_vector _computers; //! Convenience typedef. typedef std::multiset,CompareTaskPriorityLoResFirst> TodoQueue; //! Queue of tasks to be performed, lowest resolution first TodoQueue _todo; //! Conveniencetypedef. typedef std::multiset,CompareTaskPriorityHiResFirst> DoneQueue; //! Convenience typedef. /*! const because never needs to do anything other than compare pointers */ typedef std::map DoneQueueByDisplay; //! Queue of tasks completed awaiting display. /*! We reverse the compute priority so that highest resolution images get displayed first. Lower resolution ones arriving later should be discarded by the displays. This mainly makes a difference for animation where enlarging multiple low resolution images to screen res takes a lot of time. May help low-bandwidth X11 connections by minimising redraws too. We now also sort by display and do round-robin delivery (ithout this one display can run way ahead of the others) */ DoneQueueByDisplay _done; //! Points to the next display queue to be returned (could be .end()) DoneQueueByDisplay::iterator _done_position; public: //! Constructor. MutatableImageComputerFarm(uint n_threads,int niceness); //! Destructor cleans up threads. ~MutatableImageComputerFarm(); //! Accessor. uint num_threads() const { return _computers.size(); } //! Move aborted tasks from todo queue to done queue. void fasttrack_aborted(); //! Enqueue a task for computing. void push_todo(const boost::shared_ptr&); //! Remove a task from the head of the todo queue (returns null if none). const boost::shared_ptr pop_todo(MutatableImageComputer& requester); //! Enqueue a task for display. void push_done(const boost::shared_ptr&); //! Remove a task from the head of the display queue (returns null if none). const boost::shared_ptr pop_done(); //! Flags all tasks in all queues as aborted, and signals the compute threads to abort their current task. void abort_all(); //! Flags all tasks for a particular display as aborted (including compute threads) void abort_for(const MutatableImageDisplay* disp); //! Number of tasks in queues uint tasks() const; }; #endif evolvotron-0.8.3/libevolvotron/mutatable_image_computer_farm.cpp0000644000175000017500000001636315230700302024057 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of class MutatableImageComputerFarm. */ #include "mutatable_image_computer_farm.h" #include "mutatable_image_computer.h" /*! Creates the specified number of threads and store pointers to them. */ MutatableImageComputerFarm::MutatableImageComputerFarm(uint n_threads, int niceness) { _done_position = _done.end(); for (uint i = 0; i < n_threads; i++) { // The computer's constructor includes a start() _computers.push_back(new MutatableImageComputer(this, niceness)); } } /*! Destructor kills off all compute threads and frees their resources. NB The MutatableImageComputer destructor signals the thread to stop and waits for it. */ MutatableImageComputerFarm::~MutatableImageComputerFarm() { std::clog << "Compute farm shut down begun...\n"; // Kill all the computers (care needed to wake any waiting ones). for (boost::ptr_vector::iterator it = _computers.begin(); it != _computers.end(); it++) (*it).kill(); _wait_condition.wakeAll(); _computers.clear(); // Clear all the tasks in queues { QMutexLocker lock(&_mutex); _todo.clear(); _done.clear(); } std::clog << "...completed compute farm shut down\n"; } #if 0 //! Predicate function to test whether a task has been aborted static bool predicate_aborted(const boost::shared_ptr t) { return t->aborted(); } #endif void MutatableImageComputerFarm::fasttrack_aborted() { QMutexLocker lock(&_mutex); TodoQueue::iterator it = _todo.begin(); while (it != _todo.end()) { if ((*it)->aborted()) { _done[(*it)->display()].insert(*it); it = _todo.erase(it); } else it++; } } void MutatableImageComputerFarm::push_todo(const boost::shared_ptr &task) { { QMutexLocker lock(&_mutex); // We could be in a situation where there are tasks with lower priority which should be defered in favour of this one. // Currently we simply defer everything with a lower priority and let the queue sort them out. //! \todo: It would be better to just defer the lowest priority task if there's any less than the queued task. /* bool any_deferred=false; for (boost::ptr_vector::iterator it=_computers.begin();it!=_computers.end();it++) { if ((*it).defer_if_less_important_than(task->priority())) { any_deferred=true; } } */ _todo.insert(task); } // If there any threads waiting, we should wake one up. _wait_condition.wakeOne(); } const boost::shared_ptr MutatableImageComputerFarm::pop_todo(MutatableImageComputer &requester) { _mutex.lock(); boost::shared_ptr ret; while (!ret) { TodoQueue::iterator it = _todo.begin(); if (it != _todo.end()) { ret = (*it); _todo.erase(it); } else { std::clog << "Thread waiting\n"; _wait_condition.wait(&_mutex); std::clog << "Thread woken\n"; if (requester.killed()) break; } } _mutex.unlock(); return ret; } void MutatableImageComputerFarm::push_done(const boost::shared_ptr &task) { QMutexLocker lock(&_mutex); _done[task->display()].insert(task); } const boost::shared_ptr MutatableImageComputerFarm::pop_done() { QMutexLocker lock(&_mutex); boost::shared_ptr ret; if (_done_position == _done.end()) { _done_position = _done.begin(); } if (_done_position != _done.end()) { DoneQueue &q = (*_done_position).second; DoneQueue::iterator it = q.begin(); if (it != q.end()) { ret = (*it); q.erase(it); } if (q.empty()) { DoneQueueByDisplay::iterator advanced_done_position = _done_position; advanced_done_position++; _done.erase(_done_position); _done_position = advanced_done_position; } else { _done_position++; } } return ret; } void MutatableImageComputerFarm::abort_all() { QMutexLocker lock(&_mutex); for (TodoQueue::iterator it = _todo.begin(); it != _todo.end(); it++) { (*it)->abort(); } _todo.clear(); for (boost::ptr_vector::iterator it = _computers.begin(); it != _computers.end(); it++) { (*it).abort(); } for (DoneQueueByDisplay::iterator it0 = _done.begin(); it0 != _done.end(); it0++) { DoneQueue &q = (*it0).second; for (DoneQueue::iterator it1 = q.begin(); it1 != q.end(); it1++) { (*it1)->abort(); } } _done.clear(); } void MutatableImageComputerFarm::abort_for(const MutatableImageDisplay *disp) { QMutexLocker lock(&_mutex); for (TodoQueue::iterator it = _todo.begin(); it != _todo.end(); it++) { if ((*it)->display() == disp) { (*it)->abort(); it = _todo.erase(it); if (it == _todo.end()) break; } } for (boost::ptr_vector::iterator it = _computers.begin(); it != _computers.end(); it++) { (*it).abort_for(disp); } DoneQueueByDisplay::iterator it0 = _done.find(disp); if (it0 != _done.end()) { DoneQueue &q = (*it0).second; //! \todo It would be pretty odd if display didn't match the queue bin: change to assert for (DoneQueue::iterator it1 = q.begin(); it1 != q.end(); it1++) { if ((*it1)->display() == disp) { (*it1)->abort(); it1 = q.erase(it1); if (it1 == q.end()) break; } } } } uint MutatableImageComputerFarm::tasks() const { uint ret = 0; for (boost::ptr_vector::const_iterator it = _computers.begin(); it != _computers.end(); it++) { if ((*it).active()) { ret++; } } QMutexLocker lock(&_mutex); ret += _todo.size(); for (DoneQueueByDisplay::const_iterator it = _done.begin(); it != _done.end(); it++) ret += (*it).second.size(); return ret; } evolvotron-0.8.3/libevolvotron/mutatable_image_computer.h0000644000175000017500000001355315230700302022515 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class MutatableImageComputer. */ #ifndef _mutatable_image_computer_h_ #define _mutatable_image_computer_h_ #include "common.h" #include "mutatable_image.h" #include "random.h" class MutatableImageDisplay; class MutatableImageComputerFarm; class MutatableImageComputerTask; //! Class to handle computing of MutatableImages in a separate thread. /*! A compute task starts up and fetches work from it's parent farm. The parent farm thread can communicate when necessary using the public methods of the class. */ class MutatableImageComputer : public QThread { protected: //! Pointer to compute farm of which this thread is part. MutatableImageComputerFarm*const _farm; //! Priority offset applied to compute threads. const int _niceness; //! The current task. Can't be a const MutatableImageComputerTask because the task holds the calculated result. boost::shared_ptr _task; //! Randomness for sampling jitter Random01 _r01; //! Class encapsulating mutex-protected flags used for communicating between farm and worker. /*! The Mutex is of dubious value (could certainly be eliminated for reads). */ class Communications { protected: //! Mutex protecting access to members (mutable to enable const-ness of accessors). mutable QMutex _mutex; //! Flag to indicate we should put our current task back on the todo queue and take another one. /*! volatile because used for inter-thread communication. */ volatile bool _defer; //! Flag to indicate we should abort the current compute. /*! volatile because used for inter-thread communication. */ volatile bool _abort; //! Flag to indicate the thread should shut down and exit. /*! volatile because used for inter-thread communication. */ volatile bool _kill; public: //! Constructor. /*! Mutex is recursive to allow nesting. */ Communications() :_mutex() ,_defer(false) ,_abort(false) ,_kill(false) {} //! Mutex-protected accessor. void defer(bool v) { QMutexLocker lock(&_mutex); _defer=v; } //! Mutex-protected accessor. bool defer() const { QMutexLocker lock(&_mutex); const bool ret=_defer; return ret; } //! Mutex-protected accessor. void abort(bool v) { QMutexLocker lock(&_mutex); _abort=v; } //! Mutex-protected accessor. bool abort() const { QMutexLocker lock(&_mutex); const bool ret=_abort; return ret; } //! Mutex-protected accessor. void kill(bool v) { QMutexLocker lock(&_mutex); _kill=v; } //! Mutex-protected accessor. bool kill() const { QMutexLocker lock(&_mutex); const bool ret=_kill; return ret; } //! Check union of all flags with only one mutex lock. bool kill_or_abort_or_defer() const { QMutexLocker lock(&_mutex); const bool ret=(_kill || _abort || _defer); return ret; } }; //! Instance of communications flags. Communications _communications; //! The actual compute code, launched by invoking start() in the constructor. virtual void run(); //! Accessor. Communications& communications() { return _communications; } //! Accessor. const Communications& communications() const { return _communications; } //! Accessor. const boost::shared_ptr& task() const { return _task; } //! Accessor. MutatableImageComputerFarm* farm() const { return _farm; } public: //! Constructor MutatableImageComputer(MutatableImageComputerFarm* frm,int niceness); //! Destructor ~MutatableImageComputer(); //! Defer the current task if it's priority is less important than specified. Returns true if deferrment occurred. bool defer_if_less_important_than(uint pri); //! This method called by an external threads to shut down the current task void abort(); //! This method called by an external threads to shut down the current task if it's for a particular display void abort_for(const MutatableImageDisplay* disp); //! This method called by external thread to kill the thread. void kill(); //! Return kill state. /*! Needs external visibility for deciding what to do when woken from wait for task. */ bool killed() const; //! Indicate whether computation us taking place (only intended for counting outstanding threads). bool active() const { return (_task!=0); } }; #endif evolvotron-0.8.3/libevolvotron/mutatable_image_computer.cpp0000644000175000017500000001137415230700302023047 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of class MutatableImageComputer. */ #include "mutatable_image_computer.h" #include "mutatable_image.h" #include "mutatable_image_computer_farm.h" #include "mutatable_image_computer_task.h" #include "platform_specific.h" MutatableImageComputer::MutatableImageComputer(MutatableImageComputerFarm* frm,int niceness) :_farm(frm) ,_niceness(niceness) ,_r01(23) // Seed pretty unimportant; only used for sample jitter { start(); } MutatableImageComputer::~MutatableImageComputer() { std::clog << "Deleting a computer...\n"; kill(); wait(); _task.reset(); std::clog << "...deleted a computer\n"; } /*! Compute threads run this method until killed (probably by the destructor being invoked by the original spawning thread. */ void MutatableImageComputer::run() { std::clog << "Thread starting\n"; // Lower compute thread priority slightly; computing yet more stuff // is less important than displaying the results we've got so far. add_thread_niceness(_niceness); // Run until something sets the kill flag while(!communications().kill()) { // If we don't have a task try and get one. This will block or return null. if (task()==0) { _task=farm()->pop_todo(*this); } if (task()) { // Careful, we could be given an already aborted task if (!task()->aborted()) { while (!communications().kill_or_abort_or_defer() && !task()->completed()) { XYZ accumulated_colour=task()->image_function()->get_rgb ( task()->fragment_origin().width()+task()->current_col(), task()->fragment_origin().height()+task()->current_row(), task()->current_frame(), task()->whole_image_size().width(), task()->whole_image_size().height(), task()->frames(), (task()->jittered_samples() ? &_r01 : 0), task()->multisample_grid() ); const uint col0=lrint(accumulated_colour.x()); const uint col1=lrint(accumulated_colour.y()); const uint col2=lrint(accumulated_colour.z()); task()->images()[task()->current_frame()].setPixel(task()->current_col(),task()->current_row(),((col0<<16)|(col1<<8)|(col2))); task()->pixel_advance(); } } // Maybe should capture copies of the flags for use here if (!communications().kill()) { if (communications().defer() && !communications().abort()) { farm()->push_todo(task()); communications().defer(false); _task.reset(); } else { if (communications().abort()) { task()->abort(); } communications().defer(false); communications().abort(false); farm()->push_done(task()); _task.reset(); } } } } std::clog << "Thread shutting down\n"; } bool MutatableImageComputer::defer_if_less_important_than(uint pri) { const boost::shared_ptr task_tmp=_task; if (task_tmp && task_tmp->priority()>pri) { communications().defer(true); return true; } else { return false; } } void MutatableImageComputer::abort() { communications().abort(true); } void MutatableImageComputer::abort_for(const MutatableImageDisplay* disp) { if (task()!=0 && task()->display()==disp) { communications().abort(true); } } void MutatableImageComputer::kill() { communications().kill(true); } bool MutatableImageComputer::killed() const { return communications().kill(); } evolvotron-0.8.3/libevolvotron/mutatable_image.h0000644000175000017500000001240115230700302020566 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interfaces for class MutatableImage. */ #ifndef _mutatable_image_h_ #define _mutatable_image_h_ #include "common.h" #include "xyz.h" class FunctionNull; class FunctionRegistry; class FunctionTop; class MutationParameters; //! Class to hold the base FunctionNode of an image. /*! Once it owns a root FunctionNode* the whole structure should be fixed (mutate isn't available, only mutated). \todo Do reference counting on this object ? Maybe not: have to worry about stateful nodes, \todo Generally tighten up const-ness of interfaces. */ class MutatableImage { protected: //! The top level FunctionNode of the image. /*! This is partly here because FunctionNode::mutate can't change the type of the node it is invoked on (only child nodes can be zapped), partly so we can keep colour and space transforms under control. */ std::unique_ptr _top; //! Whether to sweep z sinusoidally (vs linearly) bool _sinusoidal_z; //! Whether xyz should be interpreted as long/lat/radius bool _spheremap; //! Whether this image is locked \todo Should be a property of display, not image. bool _locked; //! Serial number for identity tracking (used by display to discover whether a recompute is needed) unsigned long long _serial; //! Object count to generate serial numbers static unsigned long long _count; public: //! Take ownership of the image tree with the specified root node. MutatableImage(std::unique_ptr&,bool sinz,bool sm,bool lock); //! Create a new random image tree. MutatableImage(const MutationParameters& parameters,bool exciting,bool sinz,bool sm); //! Destructor. NB Deletes owned image function tree. virtual ~MutatableImage(); //! Returns the sampling co-ordinate given a (sub)pixel position in the given frame of an animation. /*! This depends on things like sinusoidal_z and spheremap */ const XYZ sampling_coordinate(real x,real y,uint z,uint sx,uint sy,uint sz) const; //! Accessor. const FunctionTop& top() const; //! Accessor. bool sinusoidal_z() const { return _sinusoidal_z; } //! Accessor. bool spheremap() const { return _spheremap; } //! Accessor. bool locked() const { return _locked; } //! Accessor. void locked(bool l) { _locked=l; } //! Accessor. unsigned long long serial() const { return _serial; } //! Clone this image. The cloned image will not have locked state. boost::shared_ptr deepclone() const; //! Clone this image, setting locked state to that specified. boost::shared_ptr deepclone(bool lock) const; //! Return a mutated version of this image boost::shared_ptr mutated(const MutationParameters& p) const; //! Return a simplified version of this image boost::shared_ptr simplified() const; //! Return the a 0-255-scaled RGB value at the specified location. const XYZ get_rgb(const XYZ& p) const; //! Return the a 0-255-scaled RGB value at the specified pixel of an image/animation taking jitter (if random number generator provided) and multisampling into account const XYZ get_rgb(uint x,uint y,uint f,uint width,uint height,uint frames,Random01* r01,uint multisample) const; //! Return whether image value is independent of position. bool is_constant() const; //! Save the function-tree to the stream std::ostream& save_function(std::ostream& out) const; //! Obtain some statistics about the image function void get_stats(uint& total_nodes,uint& total_parameters,uint& depth,uint& width,real& proportion_constant) const; //! Check the function tree is ok. bool ok() const; //! Read a new function tree from the given stream. static boost::shared_ptr load_function(const FunctionRegistry& function_registry,std::istream& in,std::string& report); }; #endif evolvotron-0.8.3/libevolvotron/mutatable_image.cpp0000644000175000017500000004012515230700302021125 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of class MutatableImage. */ #include #include "mutatable_image.h" #include "function_node_info.h" #include "function_top.h" #include "mutatable_image_display_big.h" #include "random.h" #include "transform.h" unsigned long long MutatableImage::_count=0; MutatableImage::MutatableImage(std::unique_ptr& r,bool sinz,bool sm,bool lock) :_top(r.release()) ,_sinusoidal_z(sinz) ,_spheremap(sm) ,_locked(lock) ,_serial(_count++) { assert(_top.get()!=0); } MutatableImage::MutatableImage(const MutationParameters& parameters,bool exciting,bool sinz,bool sm) :_sinusoidal_z(sinz) ,_spheremap(sm) ,_locked(false) ,_serial(_count++) { std::vector pv; FunctionNode::stubparams(pv,parameters,12); boost::ptr_vector av; av.push_back(FunctionNode::stub(parameters,exciting).release()); _top=std::unique_ptr(new FunctionTop(pv,av,0)); //! \todo _sinusoidal_z should be obtained from AnimationParameters when it exists } MutatableImage::~MutatableImage() {} //! Accessor. const FunctionTop& MutatableImage::top() const { return *_top; } boost::shared_ptr MutatableImage::deepclone() const { return deepclone(false); } boost::shared_ptr MutatableImage::deepclone(bool lock) const { std::unique_ptr root(top().typed_deepclone()); return boost::shared_ptr(new MutatableImage(root,sinusoidal_z(),spheremap(),lock)); } bool MutatableImage::is_constant() const { return top().is_constant(); } bool MutatableImage::ok() const { return top().ok(); } const XYZ MutatableImage::sampling_coordinate(real x,real y,uint z,uint sx,uint sy,uint sz) const { if (spheremap()) { const real longitude=-M_PI+2.0*M_PI*x/sx; const real latitude=0.5*M_PI-M_PI*y/sy; const real r=( sinusoidal_z() ? 0.5+cos(M_PI*z/sz) : 0.5+(z+0.5)/sz ); return XYZ ( r*sin(longitude)*cos(latitude), r*cos(longitude)*cos(latitude), r*sin(latitude) ); } else { return XYZ ( -1.0+2.0*x/sx, 1.0-2.0*y/sy, ( sinusoidal_z() ? cos(M_PI*(z+0.5)/sz) : -1.0+2.0*(z+0.5)/sz ) ); } } boost::shared_ptr MutatableImage::mutated(const MutationParameters& p) const { std::unique_ptr c(top().typed_deepclone()); c->mutate(p); return boost::shared_ptr(new MutatableImage(c,sinusoidal_z(),spheremap(),false)); } boost::shared_ptr MutatableImage::simplified() const { std::unique_ptr c(top().typed_deepclone()); c->simplify_constants(); return boost::shared_ptr(new MutatableImage(c,sinusoidal_z(),spheremap(),false)); } const XYZ MutatableImage::get_rgb(const XYZ& p) const { // Actually calculate a pixel value from the image. // negexp distribution on colour-space parameters probably means the nominal range is something like -4.0 to 4.0 const XYZ pv(top()(p)); // Scale a nominal -2.0 to 2.0 range to 0-255 return 127.5*(0.5*pv+XYZ(1.0,1.0,1.0)); } const XYZ MutatableImage::get_rgb(uint x,uint y,uint f,uint width,uint height,uint frames,Random01* r01,uint multisample) const { XYZ accumulated_colour(0.0,0.0,0.0); for (uint sy=0;sy\n" << "\n"; top().save_function(out,1); out << "\n"; return out; } #if QT_VERSION >= 0x060000 #define QStringRef QStringView #define QS_EQUAL(SV,C) SV == QLatin1StringView(C) #else #define QS_EQUAL(SR,C) SR == C #endif /*! Evolvotron XML Reader. Expects to see an `` followed by nested ``...`` wrapping ``...``, ``...``, `

`...`

` and more `` declarations. */ class LoadHandler : public QXmlStreamReader { protected: std::unique_ptr& _root; bool* _ret_sinusoidal_z; bool* _ret_spheremap; //! Stack just used to track our progress through the nested ``...`` declarations. /*! Ownership is entirely under _root and the pointr-container in FunctionNodeInfo. */ std::stack _stack; bool _expect_top_level_element; bool _expect_characters; bool _expect_characters_type; bool _expect_characters_iterations; bool _expect_characters_parameter; public: QString warning; LoadHandler(const char* document, std::unique_ptr& root, bool* sinz, bool* smap) : QXmlStreamReader(document) ,_root(root) ,_ret_sinusoidal_z(sinz) ,_ret_spheremap(smap) ,_expect_top_level_element(true) ,_expect_characters(false) ,_expect_characters_type(false) ,_expect_characters_iterations(false) ,_expect_characters_parameter(false) { _root.reset(); } bool startDocument() { std::clog << "Reading document...\n"; return true; } bool endDocument() { std::clog << "...completed document\n"; if (_root.get()==0) { raiseError("Error: No root function node found\n"); return false; } return true; } //! Called for start elements. bool startElement(const QStringRef& localName, const QXmlStreamAttributes& atts) { if (_expect_characters) { QString msg("Error: Expected character data but got start element \""); msg.append(localName); msg.append("\"\n"); raiseError(msg); return false; } if (_expect_top_level_element) { if (QS_EQUAL(localName, "evolvotron-image-function")) { _expect_top_level_element=false; QStringRef version = atts.value(QString(), "version"); if (version.isEmpty()) { warning += "Warning: File does not include evolvotron version\n"; } else if (version != QString(APP_VERSION)) { warning += "Warning: File saved from a different evolvotron version: "; warning += version; warning += "\n(This is version " APP_VERSION ")\n"; } QStringRef zsweep = atts.value(QString(), "zsweep"); if (zsweep.isEmpty()) { warning += "Warning: zsweep attribute not found\nDefaulting to sinusoidal\n"; *_ret_sinusoidal_z=true; } else { if (zsweep==QString("sinusoidal")) *_ret_sinusoidal_z=true; else if (zsweep==QString("linear")) *_ret_sinusoidal_z=false; else { QString msg("Error: zsweep attribute expected \"sinusoidal\" or \"linear\", but got \""); msg.append(zsweep); msg.append("\"\n"); raiseError(msg); return false; } } QStringRef projection = atts.value(QString(), "projection"); if (projection.isEmpty()) { warning += "Warning: projection attribute not found\nDefaulting to planar\n"; *_ret_spheremap=false; } else { if (projection==QString("spheremap")) *_ret_spheremap=true; else if (projection==QString("planar")) *_ret_spheremap=false; else { QString msg("Error: projection attribute expected \"spheremap\" or \"planar\", but got \""); msg.append(projection); msg.append("\"\n"); raiseError(msg); return false; } } } else { QString msg("Error: Expected but got \""); msg.append(localName); msg.append("\"\n"); raiseError(msg); return false; } } else { if (QS_EQUAL(localName, "f")) { std::unique_ptr f(new FunctionNodeInfo()); if (_stack.empty()) { if (_root.get()==0) { _stack.push(f.get()); _root.reset(f.release()); } else { raiseError("Error: Multiple top level elements encountered\n"); return false; } } else { FunctionNodeInfo*const it=f.get(); _stack.top()->args().push_back(f.release()); _stack.push(it); } } else if (QS_EQUAL(localName, "type")) { _expect_characters=true; _expect_characters_type=true; } else if (QS_EQUAL(localName, "i")) { _expect_characters=true; _expect_characters_iterations=true; } else if (QS_EQUAL(localName, "p")) { _expect_characters=true; _expect_characters_parameter=true; } else { QString msg("Error: Expected , , or

but got \""); msg.append(localName); msg.append("\"\n"); raiseError(msg); return false; } } return true; } //! We don't need to check this matches startElement bool endElement(const QStringRef& localName) { if (_expect_characters) { QString msg("Error: Expected character data but got end element \""); msg.append(localName); msg.append("\"\n"); raiseError(msg); return false; } if (QS_EQUAL(localName, "f")) _stack.pop(); return true; } bool characters(const QStringRef& s) { if (s.trimmed().isEmpty()) { // Just keep going and hope something good turns up (maybe next line ?) return true; } else { if (!_expect_characters) { QString msg("Error: Unexpected character data : \""); msg.append(s); msg.append("\"\n"); raiseError(msg); return false; } } //std::clog << "Non-blank expected character data\n"; if (_expect_characters_type) { _stack.top()->type(s.toLocal8Bit().data()); _expect_characters_type=false; } else if (_expect_characters_iterations) { bool ok; _stack.top()->iterations(s.toUInt(&ok)); _expect_characters_iterations=false; if (!ok) { QString msg("Error: Couldn't parse \""); msg.append(s); msg.append("\" as an integer\n"); raiseError(msg); return false; } } else if (_expect_characters_parameter) { bool ok; _stack.top()->params().push_back(s.toFloat(&ok)); _expect_characters_parameter=false; if (!ok) { QString msg("Error: Couldn't parse \""); msg.append(s); msg.append("\" as a real\n"); raiseError(msg); return false; } } _expect_characters=false; return true; } }; /*! If NULL is returned, then the import failed: error message in report. If an image is returned then report contains warning messages (probably version mismatch). */ boost::shared_ptr MutatableImage::load_function(const FunctionRegistry& function_registry,std::istream& in,std::string& report) { // Don't want to faff with Qt's file classes so just read everything into a string. std::string in_data; char buf[1024]; while (in.read(buf, sizeof(buf))) in_data.append(buf, sizeof(buf)); in_data.append(buf, in.gcount()); // The LoadHandler will set this to point at the root node. std::unique_ptr info; bool sinusoidal_z; bool spheremap; LoadHandler xml(in_data.c_str(), info, &sinusoidal_z, &spheremap); while (! xml.atEnd()) { switch (xml.readNext()) { case QXmlStreamReader::StartDocument: xml.startDocument(); break; case QXmlStreamReader::EndDocument: xml.endDocument(); break; case QXmlStreamReader::StartElement: xml.startElement(xml.name(), xml.attributes()); break; case QXmlStreamReader::EndElement: xml.endElement(xml.name()); break; case QXmlStreamReader::Characters: xml.characters(xml.text()); break; default: break; } } if (xml.hasError()) { report = "Parse error: "; report.append(xml.errorString().toLocal8Bit().data()); report.push_back('\n'); return boost::shared_ptr(); } // Might be a warning message in there. report = xml.warning.toLocal8Bit().data(); assert(info.get()); std::unique_ptr root(FunctionNode::create(function_registry,*info,report)); info.reset(); if (root.get()) { if (!root->is_a_FunctionTop()) { // Build a FunctionTop wrapper for compataibility with old .xml files boost::ptr_vector a; a.push_back(root.release()); const TransformIdentity ti; std::vector tiv=ti.get_columns(); std::vector p; p.insert(p.end(),tiv.begin(),tiv.end()); p.insert(p.end(),tiv.begin(),tiv.end()); root=std::unique_ptr(new FunctionTop(p,a,0)); } assert(root->is_a_FunctionTop()); std::unique_ptr root_as_top(root.release()->is_a_FunctionTop()); // Interestingly, if is_a_FunctionTop threw, the root would be leaked. return boost::shared_ptr(new MutatableImage(root_as_top,sinusoidal_z,spheremap,false)); } else { return boost::shared_ptr(); } } evolvotron-0.8.3/libevolvotron/license.h0000644000175000017500000000303315230700302017071 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Header for license boilerplate. */ #ifndef _license_h #define _license_h_ //! String containing GPL text. extern const char*const license_string; #endif evolvotron-0.8.3/libevolvotron/license.cpp0000644000175000017500000004752615230700302017443 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief License string boilerplate. */ #include "license.h" const char*const license_string= "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.\n" "\n" "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.\n" "\n" "GNU GENERAL PUBLIC LICENSE\n" "Version 2, June 1991\n" "\n" " Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n" " Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.\n" "\n" "Preamble\n" "\n" " The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.\n" " When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.\n" "\n" " To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.\n" "\n" " For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.\n" "\n" " We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy,distribute and/or modify the software.\n" "\n" " Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.\n" "\n" " Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.\n" "\n" " The precise terms and conditions for copying, distribution and\n" "modification follow.\n" "\n" "GNU GENERAL PUBLIC LICENSE\n" "TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n" "\n" " 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The \"Program\", below, refers to any such program or work, and a \"work based on the Program\" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term \"modification\".) Each licensee is addressed as \"you\".\n" "\n" "Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.\n" "\n" " 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.\n" "\n" "You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.\n" " 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:\n" "\n" " a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.\n" "\n" " b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.\n" "\n" " c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)\n" "\n" "These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.\n" "\n" "Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.\n" "\n" "In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.\n" "\n" " 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:\n" "\n" " a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,\n" "\n" " b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,\n" "\n" " c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)\n" "\n" "The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.\n" "\n" "If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.\n" "\n" " 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.\n" "\n" " 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.\n" "\n" " 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.\n" "\n" " 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.\n" "\n" "If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.\n" "\n" "It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.\n" "\n" "This section is intended to make thoroughly clear what is believed tobe a consequence of the rest of this License.\n" "\n" " 8. If the distribution and/or use of the Program is restricted incertain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.\n" "\n" " 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.\n" "\n" "Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and \"any later version\", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.\n" "\n" " 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.\n" "\n" "NO WARRANTY\n" "\n" " 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSEDOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n" "\n" " 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n" "\n" "END OF TERMS AND CONDITIONS\n" "\n" "How to Apply These Terms to Your New Programs\n" "\n" " If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.\n" "\n" " To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the \"copyright\" line and a pointer to where the full notice is found.\n" "\n" " \n" " Copyright (C) \n" "\n" " 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.\n" "\n" " This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n" " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.\n" "\n" " 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\n" "\n" "Also add information on how to contact you by electronic and paper mail.\n" "\n" "If the program is interactive, make it output a short notice like this when it starts in an interactive mode:\n" "\n" " Gnomovision version 69, Copyright (C) year name of author\n" " Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n" " This is free software, and you are welcome to redistribute it\n" " under certain conditions; type `show c' for details.\n" "\n" "The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.\n" "\n" "You should also get your employer (if you work as a programmer) or your school, if any, to sign a \"copyright disclaimer\" for the program, if necessary. Here is a sample; alter the names:\n" "\n" " Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n" " `Gnomovision' (which makes passes at compilers) written by James Hacker.\n" "\n" " , 1 April 1989\n" " Ty Coon, President of Vice\n" "\n" "This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.\n" ; evolvotron-0.8.3/libevolvotron/libevolvotron.pro0000644000175000017500000000042715230700302020730 0ustar karlkarlTEMPLATE = lib QT += widgets TARGET = evolvotron # Have to override this or we get "liblibevolvotron" include (../common.pro) CONFIG += staticlib CONFIG += c++11 INCLUDEPATH += ../libfunction DEPENDPATH += ../libfunction HEADERS += $$files(*.h) SOURCES += $$files(*.cpp) evolvotron-0.8.3/libevolvotron/evolvotron_main.h0000644000175000017500000003365415230700302020704 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class EvolvotronMain. */ #ifndef _evolvotron_main_h_ #define _evolvotron_main_h_ #include "common.h" #include "function_registry.h" #include "transform_factory.h" #include "mutatable_image.h" #include "mutatable_image_display.h" #include "mutatable_image_computer_farm.h" #include "mutation_parameters_qobject.h" #include "render_parameters.h" class DialogAbout; class DialogHelp; class DialogMutationParameters; class DialogRenderParameters; class DialogFunctions; class DialogFavourite; //! Utility class to expand "restart with" menu picks /*! A boost::bind kind of thing */ class SignalExpanderRestartWith : public QObject { private: Q_OBJECT const FunctionRegistration*const _fn; public: SignalExpanderRestartWith(QObject* parent,const FunctionRegistration* fn) :QObject(parent) ,_fn(fn) {} public slots: void restart_with() { emit restart_with(_fn); } signals: void restart_with(const FunctionRegistration*); }; //! Top level GUI component for evolvotron application class EvolvotronMain : public QMainWindow { private: Q_OBJECT protected: //! Class encapsulating everything needed for undo functionality. /*! \todo This is too big to be a nested class. */ class History { protected: //! Pointer to main app. EvolvotronMain*const _main; typedef std::map > ArchiveRecordEntries; typedef std::pair ArchiveRecord; typedef std::deque Archive; //! Each deque slot contains the collection of display-image pairs replaced by an single action (and a string naming that action). /*! We use a deque rather than a stack because we want to clean up the tail end (limited number of Undos). */ Archive _archive; //! Number of slots retained for history. const uint max_slots; //! Clean up the last slot in the queue. void purge(); //! Write some info to std::clog. void log_status() const; public: //! Constructor. History(EvolvotronMain*); //! Destructor. ~History(); //! Eliminate any references to the display (and clean up any undo actions which are empty as a result). void goodbye(MutatableImageDisplay*); //! Record that we are overwriting the given display. void replacing(MutatableImageDisplay* display); //! Returns true if the most recent action has the given name. bool last_action_named(MutatableImageDisplay*, const char* name); //! Starts a new action slot void begin_action(const std::string& action_name); //! Ends an action slot and updates the undoable state. void end_action(); //! Returns true if there is stuff to undo bool undoable(); //! Implements an undo. void undo(); }; protected: //! Convenience typedef for pointer to member function implementing a kind of spawn. typedef void (EvolvotronMain::* SpawnMemberFn)(const boost::shared_ptr& image,MutatableImageDisplay* display,bool one_of_many); //! Instance of History object to track activity. std::unique_ptr _history; //! Sweep z linearly through animations /*! \todo Move to mutation or render paraemeters ? */ const bool _linear_zsweep; //! Generate spheremaps /*! \todo Move to mutation or render paraemeters ? */ const bool _spheremap; //! Name of files to load on a reset. std::vector _startup_filenames; //! Whether to shuffle startup files (if any). const bool _startup_shuffle; //! Instance of mutation parameters for the app /*! This used to be held by DialogMutationParameters, but now we want to share it around a bit (although modifications should always be via the dialog slots, to keep the dialogs up to date) */ MutationParametersQObject _mutation_parameters; //! Instance of render parameters for the app RenderParameters _render_parameters; //! Somewhere to report what's going on QStatusBar* _statusbar; //! Label for displaying number of tasks running (more permanent than StatusBar's message method). QLabel* _statusbar_tasks_label; //! Number of main tasks the statusbar is currently reporting as active /*! Cached to avoid unnecessarily regenerating message */ uint _statusbar_tasks_main; //! Number of enlargement tasks the statusbar is currently reporting as active /*! Cached to avoid unnecessarily regenerating message */ uint _statusbar_tasks_enlargement; //! The "About" dialog widget. DialogAbout* _dialog_about; //! The "Help" dialog widget (quick reference text) DialogHelp* _dialog_help_short; //! The "Help" dialog widget (full manual text) DialogHelp* _dialog_help_long; //! The dialog for adjusting MutationParameters. DialogMutationParameters* _dialog_mutation_parameters; //! The dialog for adjusting RenderParameters. DialogRenderParameters* _dialog_render_parameters; //! Dialog for controlling which functions are in use. DialogFunctions* _dialog_functions; //! Dialog for selecting a favourite function (also holds the state for favourite stuff) DialogFavourite* _dialog_favourite; //! The file menu. QMenu* _popupmenu_file; //! The edit menu. QMenu* _popupmenu_edit; //! ID for the undo item (so we can disable it). QAction* _popupmenu_edit_undo_action; //! The settings menu QMenu* _popupmenu_settings; //! Action for setting fullscreen QAction* _menu_action_fullscreen; //! Action for hiding menubar QAction* _menu_action_hide_menu; //! The help menu. QMenu* _popupmenu_help; //! Select autocooling (also serves to reset the generation count). QCheckBox* _checkbox_autocool_enable; //! Report number of generations. QLabel* _label_autocool_enable; //! Button to reheat QPushButton* _button_autocool_reheat; //! Grid for image display areas QWidget* _grid; //! Timer to drive tick() slot QTimer* _timer; //! Two farms of compute threads. One for the main display, one for enlargements. std::unique_ptr _farm[2]; //! All the displays in the grid. std::vector _displays; //! Keeps track of which displays are still available for display (they might have been destroyed while an image was computing). /*! Non-const because we might need to notify them about various things */ std::set _known_displays; //! Keeps track of which displays are still resizing std::set _resizing; //! The last image spawned (used to regenerate single displays). boost::shared_ptr _last_spawned_image; //! Pointer to member function used for last spawn. SpawnMemberFn _last_spawn_method; //! An owned pointer to the current transform factory (needed for Respawn). std::unique_ptr _transform_factory; //! Accessor. const boost::shared_ptr last_spawned_image() const { return _last_spawned_image; } //! Accessor. SpawnMemberFn last_spawn_method() const { return _last_spawn_method; } //! Not just an accessor. Takes ownership of a deepclone of the image void last_spawned_image(const boost::shared_ptr& image,SpawnMemberFn method); //! Accessor const TransformFactory& transform_factory() const { // We shouldn't be here unless transform_factory has been set to something. assert(_transform_factory.get()!=0); return *_transform_factory; } //! Not just an accessor. Takes ownership of a deepclone of the argument. void transform_factory(const TransformFactory& tfactory) { _transform_factory=tfactory.clone(); } //@{ //! Perform a particular type of spawn from an individiual image to an individual display. (Locking not checked). void spawn_normal(const boost::shared_ptr& image,MutatableImageDisplay* display,bool one_of_many); void spawn_recoloured(const boost::shared_ptr& image,MutatableImageDisplay* display,bool one_of_many); void spawn_warped(const boost::shared_ptr& image,MutatableImageDisplay* display,bool one_of_many); //@} //! Spawn the specified display using the specified method. void spawn_all(MutatableImageDisplay* display,SpawnMemberFn method,const std::string& action_name); public: QString functionPath; //!< Last browsed function load/save directory. QString imagePath; //!< Last browsed image save directory. QPixmap lockPix; //! Constructor. EvolvotronMain ( QWidget* parent, const QSize& grid_size, uint frames, uint framerate, uint n_threads, bool separate_farm_for_enlargements, int niceness_grid, int niceness_enlargements, bool start_fullscreen, bool start_menuhidden, bool autocool, bool jitter, uint multisample_level, bool function_debug_mode, bool linear_zsweep, bool spheremap, const std::vector& startup_filenames, bool startup_shuffle ); //! Destructor. ~EvolvotronMain(); //! Accessor. Returns true if function name recognised. Forwards to DialogFavourite. bool favourite_function(const std::string& f); //! Accessor. Forwards to DialogFavourite. void favourite_function_unwrapped(bool v); //! Accessor. std::vector& displays() { return _displays; } //! Accessor. /*! NB Only const version made available publicly as modifications should be through an appropriate dialog slot. */ const MutationParameters& mutation_parameters() const { return _mutation_parameters; } //! Accessor. /*! NB Only const version made available publicly as modifications should be through an appropriate dialog slot. */ const RenderParameters& render_parameters() const { return _render_parameters; } //! Returns which farm to use for purpose. MutatableImageComputerFarm& farm(bool enlargement) { return *_farm[enlargement && _farm[1].get()]; } //! Accessor. History& history() { return *_history; } //! Called by History when performing undo. void restore(MutatableImageDisplay* display,const boost::shared_ptr&,bool one_of_many); //! Called by History to change undo menu status. void set_undoable(bool v,const std::string& name); //! Regenerates a single display using last spawn method and source. void respawn(MutatableImageDisplay* display); //! Mutates the image held by the given display to all the other displays owned. void spawn_normal(MutatableImageDisplay* spawning_display); //! Similar to spawn except just changes the colouration of the image. void spawn_recoloured(MutatableImageDisplay* spawning_display); //! Similar to spawn except just changes the input co-ordinates to the image. void spawn_warped(MutatableImageDisplay* spawning_display,const TransformFactory& tfactory); //! Called from display constructor to indicate the display is available for the disposal of its completed tasks. void hello(MutatableImageDisplay*); //! Called from display destructor to indicate the display is no longer available for the disposal of its completed tasks. void goodbye(MutatableImageDisplay*); //! Returns true if the display is known. bool is_known(MutatableImageDisplay* disp) const; //! Write a list of known displays (for debugging) void list_known(std::ostream& out) const; protected: void closeEvent(QCloseEvent* e); //! Handle key-presses void keyPressEvent(QKeyEvent* e); //! Reset the specified display. void reset(MutatableImageDisplay* display); protected slots: //! Signalled by timer. void tick(); //! Signalled by menu item. Forwards to History object. void undo(); //! Signalled by menu item. Simplifies all functions. void simplify_constants(); public slots: //! Signalled by menu item. void toggle_hide_menu(); //! Signalled by menu item void toggle_fullscreen(); //! Signalled by menu item. Public because called from evolvotron app wrapper. void reset(bool reset_mutation_parameters,bool reset_locks); //! Forwards to reset(false) void reset_warm(); //! Forwards to reset(true) void reset_cold(); //! Resets and randomizes function weightings void reset_randomized(); //! So we can update any exposed mutation parameters (e.g autocool enable, generation count) void mutation_parameters_changed(); //! So we can re-render when render parameters change void render_parameters_changed(); }; #endif evolvotron-0.8.3/libevolvotron/evolvotron_main.cpp0000644000175000017500000006255715230700302021243 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of class EvolvotronMain. \todo Eliminate need to include function.h (and instantiate lots of stuff) by moving more into function_node.h/.cpp */ #include #include #include #include "evolvotron_main.h" #include "dialog_about.h" #include "dialog_help.h" #include "dialog_mutation_parameters.h" #include "dialog_render_parameters.h" #include "dialog_functions.h" #include "dialog_favourite.h" #include "function_node.h" #include "function_post_transform.h" #include "function_pre_transform.h" #include "function_top.h" void EvolvotronMain::History::purge() { if (_archive.size()>0) _archive.pop_back(); } EvolvotronMain::History::History(EvolvotronMain* m) :_main(m) ,max_slots(32) { // Don't call _main->set_undoable because menus probably haven't been constructed yet. } EvolvotronMain::History::~History() {} void EvolvotronMain::History::log_status() const { std::clog << "[History: " << _archive.size() << " records ("; for (Archive::const_iterator it=_archive.begin();it!=_archive.end();it++) std::clog << (it!=_archive.begin() ? "," : "") << (*it).second.size(); std::clog << ")]\n"; } void EvolvotronMain::History::goodbye(MutatableImageDisplay* display) { // First pass to delete any individual items for that display. for (Archive::iterator it=_archive.begin();it!=_archive.end();it++) (*it).second.erase(display); // Second pass to delete any undo items which are now empty Archive::iterator it=_archive.begin(); while (it!=_archive.end()) { if ((*it).second.empty()) it=_archive.erase(it); it++; } // Set menu label again in case we've changed the topmost item const std::string action_name(_archive.empty() ? "" : _archive.front().first); _main->set_undoable(undoable(),action_name); } void EvolvotronMain::History::replacing(MutatableImageDisplay* display) { if (_archive.size()==0) { begin_action(""); } const boost::shared_ptr image_function=display->image_function(); if (image_function.get()) { const boost::shared_ptr saved_image_function(image_function->deepclone(image_function->locked())); _archive.front().second.insert(std::make_pair(display,saved_image_function)); } } bool EvolvotronMain::History::last_action_named(MutatableImageDisplay* display, const char* name) { if (_archive.empty()) return false; const ArchiveRecord& record = _archive.front(); if (record.first != name || record.second.empty()) return false; return record.second.find(display) != record.second.end(); } /*! Only creates a new slot for display-image pairs if the current top one (if any) isn't empty. */ void EvolvotronMain::History::begin_action(const std::string& action_name) { if (_archive.size()==0 || _archive.front().second.size()!=0) { _archive.push_front(ArchiveRecord()); assert(_archive.front().second.size()==0); } _archive.front().first=action_name; while (_archive.size()>max_slots) { purge(); } } void EvolvotronMain::History::end_action() { const std::string action_name(_archive.empty() ? "" : _archive.front().first); _main->set_undoable(undoable(),action_name); log_status(); } bool EvolvotronMain::History::undoable() { if (_archive.size()==0) { return false; } else if (_archive.front().second.size()==0) { _archive.pop_front(); return undoable(); } else { return true; } } void EvolvotronMain::History::undo() { if (_archive.size()==0) { // Shouldn't ever see this if Undo menu item is correctly greyed out. QMessageBox::warning(_main,"Evolvotron","Sorry, cannot undo any further"); } else if (_archive.front().second.size()==0) { _archive.pop_front(); undo(); } else { for (ArchiveRecordEntries::iterator it=_archive.front().second.begin(); it!=_archive.front().second.end(); it++ ) { _main->restore((*it).first,(*it).second,_archive.size()>1); } _archive.pop_front(); } const std::string action_name(_archive.empty() ? "" : _archive.front().first); _main->set_undoable(undoable(),action_name); } void EvolvotronMain::last_spawned_image(const boost::shared_ptr& image,SpawnMemberFn method) { _last_spawned_image=image; _last_spawn_method=method; } /*! Constructor sets up GUI components and fires up QTimer. Initialises mutation parameters using time, so different every time. */ EvolvotronMain::EvolvotronMain ( QWidget* parent, const QSize& grid_size, uint frames, uint framerate, uint n_threads, bool separate_farm_for_enlargements, int niceness_grid, int niceness_enlargements, bool start_fullscreen, bool start_menuhidden, bool autocool, bool jitter, uint multisample_level, bool function_debug_mode, bool linear_zsweep, bool spheremap, const std::vector& startup_filenames, bool startup_shuffle ) :QMainWindow(parent) ,_history(new EvolvotronMain::History(this)) ,_linear_zsweep(linear_zsweep) ,_spheremap(spheremap) ,_startup_filenames(startup_filenames) ,_startup_shuffle(startup_shuffle) ,_mutation_parameters(time(0),autocool,function_debug_mode,this) ,_render_parameters(jitter,multisample_level,this) ,_statusbar_tasks_main(0) ,_statusbar_tasks_enlargement(0) ,_last_spawn_method(&EvolvotronMain::spawn_normal) { lockPix = QPixmap(":/icons/lock.png"); setMinimumSize(640,480); // Need to create this first or DialogMutationParameters might cause one to be created too. _statusbar=new QStatusBar; _statusbar->setSizeGripEnabled(true); setStatusBar(_statusbar); _statusbar->addWidget(_statusbar_tasks_label=new QLabel("Ready")); _dialog_about=new DialogAbout(this,n_threads,separate_farm_for_enlargements); _dialog_help_short=new DialogHelp(this,false); _dialog_help_long=new DialogHelp(this,true); _dialog_mutation_parameters=new DialogMutationParameters(this,&_mutation_parameters); _dialog_render_parameters=new DialogRenderParameters(this,&_render_parameters); _dialog_functions=new DialogFunctions(this,&_mutation_parameters); _dialog_favourite=new DialogFavourite(this); #if QT_VERSION >= 0x060400 #define KEY_ACTION(menu, L, M, K) menu->addAction(L, K, this, M) #else #define KEY_ACTION(menu, L, M, K) menu->addAction(L, this, M, K) #endif _popupmenu_file=menuBar()->addMenu("&File"); KEY_ACTION(_popupmenu_file, "Reset (Reset mutation parameters, clear locks)", SLOT(reset_cold()), QKeySequence("r")); KEY_ACTION(_popupmenu_file, "Restart (Preserve mutation parameters and locks)", SLOT(reset_warm()), QKeySequence("t")); KEY_ACTION(_popupmenu_file, "Remix (Randomize function weights and restart)", SLOT(reset_randomized()), QKeySequence("x")); _popupmenu_file->addSeparator(); KEY_ACTION(_popupmenu_file, "&Quit", SLOT(close()), QKeySequence::Quit); _popupmenu_edit=menuBar()->addMenu("&Edit"); _popupmenu_edit_undo_action= KEY_ACTION(_popupmenu_edit, "Undo", SLOT(undo()), QKeySequence("u")); _popupmenu_edit_undo_action->setEnabled(false); _popupmenu_edit->addSeparator(); _popupmenu_edit->addAction("Simplify all functions",this,SLOT(simplify_constants())); _popupmenu_settings=menuBar()->addMenu("Se&ttings"); _popupmenu_settings->addAction("Mutation parameters...",_dialog_mutation_parameters,SLOT(show())); _popupmenu_settings->addAction("Function weightings...",_dialog_functions,SLOT(show())); _popupmenu_settings->addAction("Favourite function...",_dialog_favourite,SLOT(show())); _popupmenu_settings->addSeparator(); _popupmenu_settings->addAction("Render parameters...",_dialog_render_parameters,SLOT(show())); _popupmenu_settings->addSeparator(); _menu_action_fullscreen= KEY_ACTION(_popupmenu_settings, "Fullscreen", SLOT(toggle_fullscreen()), QKeySequence(Qt::CTRL | Qt::Key_F)); _menu_action_fullscreen->setCheckable(true); _menu_action_fullscreen->setChecked(start_fullscreen); _menu_action_hide_menu= KEY_ACTION(_popupmenu_settings, "Hide menu and statusbar", SLOT(toggle_hide_menu()), QKeySequence(Qt::CTRL | Qt::Key_M)); _menu_action_hide_menu->setCheckable(true); _menu_action_hide_menu->setChecked(start_menuhidden); //! This doesn't seem to do anything (supposed to push help menu over to far end ?) menuBar()->addSeparator(); _popupmenu_help=menuBar()->addMenu("&Help"); _popupmenu_help->addAction("Quick &Reference",_dialog_help_short,SLOT(show())); QAction* act = _popupmenu_help->addAction("User &Manual",_dialog_help_long,SLOT(show())); act->setShortcut(QKeySequence::HelpContents); _popupmenu_help->addSeparator(); _popupmenu_help->addAction("&About",_dialog_about,SLOT(show())); _checkbox_autocool_enable=new QCheckBox("Autocool"); _checkbox_autocool_enable->setToolTip("Autocooling gradually reduces the chance and magnitude of mutations with time."); _label_autocool_enable=new QLabel(""); // Used to display generation count _button_autocool_reheat=new QPushButton("Reheat"); _button_autocool_reheat->setToolTip("Reheat restarts the autocooling generation count, restoring the full strength of mutations."); connect(_checkbox_autocool_enable,SIGNAL(stateChanged(int)),_dialog_mutation_parameters,SLOT(changed_autocool_enable(int))); connect(_button_autocool_reheat,SIGNAL(clicked()),_dialog_mutation_parameters,SLOT(reheat())); _statusbar->addPermanentWidget(_checkbox_autocool_enable); _statusbar->addPermanentWidget(_label_autocool_enable); _statusbar->addPermanentWidget(_button_autocool_reheat); connect( &_render_parameters,SIGNAL(changed()), this,SLOT(render_parameters_changed()) ); connect( &_mutation_parameters,SIGNAL(changed()), this,SLOT(mutation_parameters_changed()) ); _farm[0]=std::unique_ptr(new MutatableImageComputerFarm(n_threads,niceness_grid)); if (separate_farm_for_enlargements) { _farm[1]=std::unique_ptr(new MutatableImageComputerFarm(n_threads,niceness_enlargements)); } _grid=new QWidget; QGridLayout*const grid_layout=new QGridLayout; _grid->setLayout(grid_layout); setCentralWidget(_grid); //! \todo frames and framerate should be retained and modifiable from the GUI for (int r=0;raddWidget(d,r,c); displays().push_back(d); } _timer=new QTimer(this); connect( _timer,SIGNAL(timeout()), this, SLOT(tick()) ); // Run tick() at 100Hz _timer->start(10); if (start_fullscreen) { showFullScreen(); } if (start_menuhidden) { menuBar()->hide(); statusBar()->hide(); } { QSettings settings; resize( settings.value("window-size", QSize(640, 480)).toSize() ); functionPath = settings.value("func-path").toString(); imagePath = settings.value("image-path").toString(); } } /*! If this is being destroyed then the whole application is going down. Could be ordering issues with the display destructors though. */ EvolvotronMain::~EvolvotronMain() { std::clog << "Evolvotron shut down begun...\n"; // Orphan any displays which outlived us (and clear their images) (look out: shutdown order is Qt-determined) std::clog << "(There are " << _known_displays.size() << " displays remaining)\n"; for (std::set::const_iterator it=_known_displays.begin();it!=_known_displays.end();it++) { (*it)->image_function(boost::shared_ptr(),true); (*it)->main(0); } std::clog << "...cleared displays, deleting farm...\n"; // Shut down the compute farms _farm[0].reset(); _farm[1].reset(); std::clog << "...deleted farm, deleting history...\n"; // Clean up records. _last_spawned_image.reset(); _history.reset(); std::clog << "...deleted history\n"; std::clog << "...completed Evolvotron shutdown\n"; } bool EvolvotronMain::favourite_function(const std::string& f) { return _dialog_favourite->favourite_function(f); } void EvolvotronMain::favourite_function_unwrapped(bool v) { _dialog_favourite->favourite_function_unwrapped(v); } void EvolvotronMain::spawn_normal(const boost::shared_ptr& image_function,MutatableImageDisplay* display,bool one_of_many) { boost::shared_ptr new_image_function; do { new_image_function=image_function->mutated(mutation_parameters()); } while (new_image_function->is_constant()); history().replacing(display); display->image_function(new_image_function,one_of_many); } void EvolvotronMain::spawn_recoloured(const boost::shared_ptr& image_function,MutatableImageDisplay* display,bool one_of_many) { std::unique_ptr new_root(image_function->top().typed_deepclone()); new_root->reset_posttransform_parameters(mutation_parameters()); history().replacing(display); boost::shared_ptr it(new MutatableImage(new_root,image_function->sinusoidal_z(),image_function->spheremap(),false)); display->image_function(it,one_of_many); } void EvolvotronMain::spawn_warped(const boost::shared_ptr& image_function,MutatableImageDisplay* display,bool one_of_many) { std::unique_ptr new_root=std::unique_ptr(image_function->top().typed_deepclone()); // Get the transform from whatever factory is currently set const Transform transform(transform_factory()(mutation_parameters().rng01())); new_root->concatenate_pretransform_on_right(transform); history().replacing(display); boost::shared_ptr it(new MutatableImage(new_root,image_function->sinusoidal_z(),image_function->spheremap(),false)); display->image_function(it,one_of_many); } void EvolvotronMain::restore(MutatableImageDisplay* display,const boost::shared_ptr& image_function,bool one_of_many) { if (is_known(display)) display->image_function(image_function,one_of_many); } void EvolvotronMain::set_undoable(bool v,const std::string& action_name) { _popupmenu_edit_undo_action->setText(QString(("Undo "+action_name).c_str())); _popupmenu_edit_undo_action->setEnabled(v); } void EvolvotronMain::respawn(MutatableImageDisplay* display) { if (display->locked()) { QMessageBox::warning(this,"Evolvotron","Cannot respawn a locked image.\nUnlock and try again."); } else { history().begin_action("respawn"); if (last_spawned_image()==0) { reset(display); } else { (this->*last_spawn_method())(last_spawned_image(),display,false); } history().end_action(); } } void EvolvotronMain::spawn_all(MutatableImageDisplay* spawning_display,SpawnMemberFn method,const std::string& action_name) { // Spawn potentially a bit sluggish so set the hourglass cursor. QApplication::setOverrideCursor(Qt::WaitCursor); history().begin_action(action_name); // Issue new images (except to locked displays and to originator) // This will cause them to abort any running tasks const boost::shared_ptr spawning_image_function(spawning_display->image_function()); last_spawned_image(spawning_image_function,method); for (std::vector::iterator it=displays().begin();it!=displays().end();it++) { if ((*it)!=spawning_display && !(*it)->locked()) { (this->*method)(spawning_image_function,(*it),true); } } history().end_action(); _mutation_parameters.autocool_generations_increment(); QApplication::restoreOverrideCursor(); } /*! If one of our sub displays has spawned, distribute a mutated copy of its image to the other non-locked images in the mutation grid. */ void EvolvotronMain::spawn_normal(MutatableImageDisplay* spawning_display) { spawn_all( spawning_display, &EvolvotronMain::spawn_normal, "spawn" ); } /*! This is the similar to spawn_normal, except images ARE NOT MUTATED after deepclone and have a final transform applied to change their colour. */ void EvolvotronMain::spawn_recoloured(MutatableImageDisplay* spawning_display) { spawn_all( spawning_display, &EvolvotronMain::spawn_recoloured, "spawn recoloured" ); } /*! This is the similar to spawn_normal, except images ARE NOT MUTATED after deepclone and have an initial transform (obtained from the supplied TransformFactory) applied to spatially warp them. */ void EvolvotronMain::spawn_warped(MutatableImageDisplay* spawning_display,const TransformFactory& tfactory) { transform_factory(tfactory); spawn_all( spawning_display, &EvolvotronMain::spawn_warped, "spawn warped" ); } void EvolvotronMain::hello(MutatableImageDisplay* disp) { _known_displays.insert(disp); } void EvolvotronMain::goodbye(MutatableImageDisplay* disp) { _history->goodbye(disp); _known_displays.erase(disp); } bool EvolvotronMain::is_known(MutatableImageDisplay* disp) const { return (_known_displays.find(disp)!=_known_displays.end()); } void EvolvotronMain::list_known(std::ostream& out) const { for (std::set::const_iterator it=_known_displays.begin();it!=_known_displays.end();it++) { out << (*it) << " "; } out << "\n"; } /*! Periodically report number of remaining compute tasks and check farm's done queue for completed tasks. */ void EvolvotronMain::tick() { const uint tasks_main=_farm[0]->tasks(); const uint tasks_enlargement=(_farm[1].get() ? _farm[1]->tasks() : 0); if (tasks_main!=_statusbar_tasks_main || tasks_enlargement!=_statusbar_tasks_enlargement) { std::ostringstream msg; msg << ""; if (tasks_main+tasks_enlargement==0) { msg << "Ready"; } else { msg << tasks_main; if (tasks_enlargement) { msg << "+" << tasks_enlargement; } msg << " tasks remaining"; } _statusbar_tasks_label->setText(msg.str().c_str()); _statusbar_tasks_main=tasks_main; _statusbar_tasks_enlargement=tasks_enlargement; } boost::shared_ptr task; // If there are aborted jobs in the todo queue // shift them straight over to done queue so the compute threads don't have to worry about them. _farm[0]->fasttrack_aborted(); if (_farm[1].get()) _farm[1]->fasttrack_aborted(); QElapsedTimer watchdog; watchdog.start(); for (int which_farm=0;which_farm<(_farm[1].get() ? 2 : 1);which_farm++) { while ((task=_farm[which_farm]->pop_done())!=0) { if (is_known(task->display())) { task->display()->deliver(task); } else { // If we don't know who owns it we just have to trash it // (probably a top level window which was closed with incomplete tasks). task.reset(); } // Timeout in case we're being swamped by incoming tasks (maintain app responsiveness). if (watchdog.elapsed()>20) break; } } } void EvolvotronMain::closeEvent(QCloseEvent* e) { QSettings settings; settings.setValue("window-size", size()); settings.setValue("func-path", functionPath); settings.setValue("image-path", imagePath); QMainWindow::closeEvent(e); } void EvolvotronMain::keyPressEvent(QKeyEvent* e) { if (e->key()==Qt::Key_Escape) { // Esc key used to back out of menu hide and full screen mode // Might rescue a few users who have got into those states accidentally showNormal(); menuBar()->show(); statusBar()->show(); _menu_action_fullscreen->setChecked(false); _menu_action_hide_menu->setChecked(false); } else if (e->key()==Qt::Key_Z && !(e->modifiers()^Qt::ControlModifier)) { //Ctrl-Z does an undo undo(); } else { // Perhaps it's for someone else e->ignore(); } } void EvolvotronMain::toggle_fullscreen() { if (isFullScreen()) { showNormal(); _menu_action_fullscreen->setChecked(false); } else { showFullScreen(); _menu_action_fullscreen->setChecked(true); } } void EvolvotronMain::toggle_hide_menu() { if (menuBar()->isHidden()) { menuBar()->show(); _menu_action_hide_menu->setChecked(false); } else if (menuBar()->isVisible()) { menuBar()->hide(); _menu_action_hide_menu->setChecked(true); } if (statusBar()->isHidden()) statusBar()->show(); else if (statusBar()->isVisible()) statusBar()->hide(); } /*! Set up an initial random image in the specified display. If a favourite function was specified then we use that as the top level node. */ void EvolvotronMain::reset(MutatableImageDisplay* display) { std::unique_ptr root; if (_dialog_favourite->favourite_function().empty()) { root=std::unique_ptr(FunctionTop::initial(mutation_parameters())); } else { root=std::unique_ptr ( FunctionTop::initial ( mutation_parameters(), mutation_parameters().function_registry().lookup(_dialog_favourite->favourite_function()), _dialog_favourite->favourite_function_unwrapped() ) ); } history().replacing(display); const boost::shared_ptr image_function(new MutatableImage(root,!_linear_zsweep,_spheremap,false)); display->image_function(image_function,true); } void EvolvotronMain::undo() { history().undo(); } void EvolvotronMain::simplify_constants() { history().begin_action("simplify all"); uint nodes_eliminated=0; for (std::vector::iterator it=_displays.begin();it!=_displays.end();it++) { nodes_eliminated+=(*it)->simplify_constants(false); } history().end_action(); std::stringstream msg; msg << "Eliminated " << nodes_eliminated << " redundant function nodes\n"; QMessageBox::information(this,"Evolvotron",msg.str().c_str(),QMessageBox::Ok); } /*! Reset each image in the grid, and the mutation parameters. */ void EvolvotronMain::reset(bool reset_mutation_parameters,bool clear_locks) { history().begin_action("reset/restart"); if (reset_mutation_parameters) { // Invoking reset on the 1st dialog actually resets the parameters _dialog_mutation_parameters->reset(); // This one just serves to setup the function dialog from the now reset parameters _dialog_functions->setup_from_mutation_parameters(); } else { // Seems odd if we don't restart the count. _mutation_parameters.autocool_generations(0); } for (size_t i=0;ilock(false,false); // lock method mustn't make it's own history recording } if (_startup_shuffle) { std::random_device rd; std::mt19937 gen(rd()); std::shuffle(_startup_filenames.begin(), _startup_filenames.end(), gen); } for (size_t i=0;ilocked()) { if (i<_startup_filenames.size()) displays()[i]->load_function_file(_startup_filenames[i].c_str()); else reset(displays()[i]); } } last_spawned_image(boost::shared_ptr(),&EvolvotronMain::spawn_normal); history().end_action(); } void EvolvotronMain::reset_randomized() { _mutation_parameters.randomize_function_weightings_for_classifications(static_cast(-1)); reset(false,false); } void EvolvotronMain::reset_warm() { reset(false,false); } void EvolvotronMain::reset_cold() { reset(true,true); } void EvolvotronMain::mutation_parameters_changed() { _checkbox_autocool_enable->setChecked(_mutation_parameters.autocool_enable()); if (_mutation_parameters.autocool_enable()) { _label_autocool_enable->setText(QString("Generations:")+QString::number(_mutation_parameters.autocool_generations())); _label_autocool_enable->show(); if (_mutation_parameters.autocool_generations()>0) _button_autocool_reheat->show(); else _button_autocool_reheat->hide(); } else { _label_autocool_enable->hide(); _button_autocool_reheat->hide(); } } void EvolvotronMain::render_parameters_changed() { for (std::set::iterator it=_known_displays.begin();it!=_known_displays.end();it++) (*it)->image_function((*it)->image_function(),true); } evolvotron-0.8.3/libevolvotron/dialog_render_parameters.h0000644000175000017500000000531715230700302022477 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class DialogRenderParameters. */ #ifndef _dialog_render_parameters_h_ #define _dialog_render_parameters_h_ #include "common.h" #include "render_parameters.h" //! Provides an dialog box for controlling RenderParameters. class DialogRenderParameters : public QDialog { private: Q_OBJECT protected: //! Instance of MutationParameters under dialog control. /*! NB it's fairly important no-one modifies this except through methods of this class (or another class responsible for another part), else GUI components will get out of sync */ RenderParameters*const _render_parameters; //! Enables jittered samples. QCheckBox* _checkbox_jittered_samples; //! Chooses between multisampling levels. QWidget* _buttonvbox; //! Chooses between multisampling levels. QButtonGroup* _buttongroup; //! Button to close dialog. QPushButton* _ok; //! Reload from _render_parameters. void setup_from_render_parameters(); public: //! Constructor. DialogRenderParameters(QMainWindow* parent,RenderParameters* rp); //! Destructor. ~DialogRenderParameters(); public slots: //! Signalled by checkbox. void changed_jittered_samples(int buttonstate); //! Signalled by radio buttons. void changed_oversampling(int id); //! Signalled by mutation parameters void render_parameters_changed(); }; #endif evolvotron-0.8.3/libevolvotron/dialog_render_parameters.cpp0000644000175000017500000001033015230700302023021 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of class DialogRenderParameters. */ #include "dialog_render_parameters.h" DialogRenderParameters::DialogRenderParameters(QMainWindow* parent,RenderParameters* rp) :QDialog(parent) ,_render_parameters(rp) { setWindowTitle("Render Parameters"); setSizeGripEnabled(true); QBoxLayout* lo = new QVBoxLayout(this); lo->addWidget(_checkbox_jittered_samples=new QCheckBox("Jittered samples")); _checkbox_jittered_samples->setToolTip("Jitter moves sampling positions randomly within a pixel. This helps to break up aliasing and moire patterns."); _buttonvbox=new QGroupBox("Oversampling (antialiasing)"); QBoxLayout* loB = new QVBoxLayout(_buttonvbox); lo->addWidget(_buttonvbox); QRadioButton* button[4]; loB->addWidget(button[0]=new QRadioButton("1x1")); loB->addWidget(button[1]=new QRadioButton("2x2")); loB->addWidget(button[2]=new QRadioButton("3x3")); loB->addWidget(button[3]=new QRadioButton("4x4")); button[0]->setToolTip("No oversampling"); button[1]->setToolTip("Enables a final antialiased rendering with 4 samples per pixel"); button[2]->setToolTip("Enables a final antialiased rendering with 9 samples per pixel"); button[3]->setToolTip("Enables a final antialiased rendering with 16 samples per pixel"); _buttongroup=new QButtonGroup(_buttonvbox); _buttongroup->addButton(button[0],1); _buttongroup->addButton(button[1],2); _buttongroup->addButton(button[2],3); _buttongroup->addButton(button[3],4); setup_from_render_parameters(); connect(_checkbox_jittered_samples,SIGNAL(stateChanged(int)),this,SLOT(changed_jittered_samples(int))); connect(_buttongroup, #if QT_VERSION >= 0x051500 SIGNAL(idClicked(int)), #else SIGNAL(buttonClicked(int)), #endif this,SLOT(changed_oversampling(int))); lo->addStretch(); _ok=new QPushButton("OK"); _ok->setDefault(true); lo->addWidget(_ok); connect( _ok,SIGNAL(clicked()), this,SLOT(hide()) ); connect( _render_parameters,SIGNAL(changed()), this,SLOT(render_parameters_changed()) ); } DialogRenderParameters::~DialogRenderParameters() {} void DialogRenderParameters::setup_from_render_parameters() { _checkbox_jittered_samples->setChecked(_render_parameters->jittered_samples()); QAbstractButton*const which_button=_buttongroup->button(_render_parameters->multisample_grid()); if (which_button) { which_button->click(); } } void DialogRenderParameters::changed_jittered_samples(int buttonstate) { if (buttonstate==Qt::Checked) _render_parameters->jittered_samples(true); else if (buttonstate==Qt::Unchecked) _render_parameters->jittered_samples(false); } void DialogRenderParameters::changed_oversampling(int id) { assert(1<=id && id<=4); _render_parameters->multisample_grid(id); } void DialogRenderParameters::render_parameters_changed() { setup_from_render_parameters(); } evolvotron-0.8.3/libevolvotron/dialog_mutation_parameters.h0000644000175000017500000001023515230700302023053 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class DialogMutationParameters. */ #ifndef _dialog_mutation_parameters_h_ #define _dialog_mutation_parameters_h_ #include "common.h" #include "mutation_parameters_qobject.h" //! Provides an dialog box for controlling MutationParameters. class DialogMutationParameters : public QDialog { private: Q_OBJECT typedef QDialog Superclass; protected: //! Scale to spinbox's integer values. const int _scale; //! Owner of dialog (probably EvolvotronMain), used to access a statusbar. QMainWindow*const _parent; //! Instance of MutationParameters under dialog control. /*! NB it's fairly important no-one modifies this except through methods of this class (or another class responsible for another part), else GUI components will get out of sync */ MutationParametersQObject*const _mutation_parameters; //! Tabs for base parameters and autocool QTabWidget* _tabs; //! Tab for base mutation parameter controls QWidget* _vbox_base_mutation; //! Grid for buttons; QWidget* _grid_buttons; //! Grid for base parameter control spinners QWidget* _grid_base_mutation; //! Grid for autocool parameters QWidget* _grid_autocool; //! Label to show number of generations QLabel* _label_autocool_generations; //! Button to reheeat autocooling QPushButton* _button_autocool_reheat; //@{ //! Button for quick adjustment of MutationParameters QPushButton* _button_reset; QPushButton* _button_cool; QPushButton* _button_heat; QPushButton* _button_shield; QPushButton* _button_irradiate; //@} //@{ //! Spinners for detailed control of specific parameters QSpinBox* _spinbox_magnitude; QSpinBox* _spinbox_parameter_reset; QSpinBox* _spinbox_glitch; QSpinBox* _spinbox_shuffle; QSpinBox* _spinbox_insert; QSpinBox* _spinbox_substitute; QSpinBox* _spinbox_autocool_halflife; //@} //! Control autocooling QCheckBox* _checkbox_autocool_enable; //! Button to close dialog. QPushButton* _ok; //! Reload spinboxes from _mutation_parameters. void setup_from_mutation_parameters(); public: //! Constructor. DialogMutationParameters(QMainWindow* parent,MutationParametersQObject* mp); //! Destructor. ~DialogMutationParameters(); public slots: //@{ //! Signalled by button. void reset(); void heat(); void cool(); void irradiate(); void shield(); void reheat(); //@} //! Signalled by checkbox. void changed_autocool_enable(int buttonstate); //@{ //! Signalled by spinbox. void changed_magnitude(int v); void changed_parameter_reset(int v); void changed_glitch(int v); void changed_shuffle(int v); void changed_insert(int v); void changed_substitute(int v); void changed_autocool_halflife(int v); //@} //! Signalled by mutation parameters void mutation_parameters_changed(); }; #endif evolvotron-0.8.3/libevolvotron/dialog_mutation_parameters.cpp0000644000175000017500000002573015230700302023414 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of class DialogMutationParameters. */ #include "dialog_mutation_parameters.h" DialogMutationParameters::DialogMutationParameters(QMainWindow* parent,MutationParametersQObject* mp) :QDialog(parent) ,_scale(100) ,_parent(parent) ,_mutation_parameters(mp) { assert(_parent!=0); setWindowTitle("Mutation Parameters"); setSizeGripEnabled(true); QBoxLayout* lo = new QVBoxLayout(this); _tabs=new QTabWidget(); lo->addWidget(_tabs); _vbox_base_mutation=new QWidget; _vbox_base_mutation->setLayout(new QVBoxLayout); _tabs->addTab(_vbox_base_mutation,"Base"); _grid_buttons=new QWidget; _vbox_base_mutation->layout()->addWidget(_grid_buttons); QGridLayout* grid = new QGridLayout(_grid_buttons); grid->addWidget(_button_reset=new QPushButton("&Reset",_grid_buttons),0,0); grid->addWidget(_button_cool=new QPushButton("&Cool",_grid_buttons),0,1); grid->addWidget(_button_shield=new QPushButton("&Shield",_grid_buttons),0,2); grid->addWidget(_button_heat=new QPushButton("&Heat",_grid_buttons),0,3); grid->addWidget(_button_irradiate=new QPushButton("&Irradiate",_grid_buttons),0,4); _button_cool->setToolTip("Decrease size of constant perturbations during mutation."); _button_heat->setToolTip("Increase size of constant perturbations during mutation."); _button_shield->setToolTip("Decrease probability of function tree structural mutations."); _button_irradiate->setToolTip("Increase probability of function tree structural mutations."); connect(_button_reset, SIGNAL(clicked()),this,SLOT(reset())); connect(_button_cool, SIGNAL(clicked()),this,SLOT(cool())); connect(_button_heat, SIGNAL(clicked()),this,SLOT(heat())); connect(_button_shield, SIGNAL(clicked()),this,SLOT(shield())); connect(_button_irradiate,SIGNAL(clicked()),this,SLOT(irradiate())); _grid_base_mutation=new QWidget; _vbox_base_mutation->layout()->addWidget(_grid_base_mutation); QGridLayout* grid_base = new QGridLayout(_grid_base_mutation); grid_base->addWidget(new QLabel("Perturbation magnitude:"),0,0); grid_base->addWidget(_spinbox_magnitude=new QSpinBox,0,1); _spinbox_magnitude->setRange(0,_scale); _spinbox_magnitude->setSingleStep(maximum(1,_scale/1000)); _spinbox_magnitude->setSuffix(QString("/%1").arg(_scale)); _spinbox_magnitude->setToolTip("Scale of function parameter perturbations."); grid_base->addWidget(new QLabel("p(Parameter reset)"),1,0); grid_base->addWidget(_spinbox_parameter_reset=new QSpinBox,1,1); _spinbox_parameter_reset->setRange(0,_scale); _spinbox_parameter_reset->setSingleStep(maximum(1,_scale/1000)); _spinbox_parameter_reset->setSuffix(QString("/%1").arg(_scale)); _spinbox_parameter_reset->setToolTip("Probability of function parameters being completely reset."); grid_base->addWidget(new QLabel("p(Glitch)"),2,0); grid_base->addWidget(_spinbox_glitch=new QSpinBox,2,1); _spinbox_glitch->setRange(0,_scale); _spinbox_glitch->setSingleStep(maximum(1,_scale/1000)); _spinbox_glitch->setSuffix(QString("/%1").arg(_scale)); _spinbox_glitch->setToolTip("Probability of function branch being replaced by new random stub."); grid_base->addWidget(new QLabel("p(Shuffle)"),3,0); grid_base->addWidget(_spinbox_shuffle=new QSpinBox,3,1); _spinbox_shuffle->setRange(0,_scale); _spinbox_shuffle->setSingleStep(maximum(1,_scale/1000)); _spinbox_shuffle->setSuffix(QString("/%1").arg(_scale)); _spinbox_shuffle->setToolTip("Probability of function branches being reordered."); grid_base->addWidget(new QLabel("p(Insert)"),4,0); grid_base->addWidget(_spinbox_insert=new QSpinBox,4,1); _spinbox_insert->setRange(0,_scale); _spinbox_insert->setSingleStep(maximum(1,_scale/1000)); _spinbox_insert->setSuffix(QString("/%1").arg(_scale)); _spinbox_insert->setToolTip("Probability of function branch having random stub inserted."); grid_base->addWidget(new QLabel("p(Substitute)"),5,0); grid_base->addWidget(_spinbox_substitute=new QSpinBox,5,1); _spinbox_substitute->setRange(0,_scale); _spinbox_substitute->setSingleStep(maximum(1,_scale/1000)); _spinbox_substitute->setSuffix(QString("/%1").arg(_scale)); _spinbox_substitute->setToolTip("Probability of function node's type being changed."); _grid_autocool = new QWidget; _tabs->addTab(_grid_autocool, "Autocool"); QGridLayout* grid_ac = new QGridLayout(_grid_autocool); grid_ac->addWidget(_checkbox_autocool_enable=new QCheckBox("Enable autocool"),0,1); _checkbox_autocool_enable->setToolTip("Autocooling reduces the strength and probablility of mutations with increasing numbers of generations."); grid_ac->addWidget(new QLabel("Half-life"),1,0); grid_ac->addWidget(_spinbox_autocool_halflife=new QSpinBox,1,1); _spinbox_autocool_halflife->setRange(1,1000); _spinbox_autocool_halflife->setSingleStep(1); _spinbox_autocool_halflife->setToolTip("Number of generations needed to halve mutation influence when autocooling."); grid_ac->addWidget(_label_autocool_generations=new QLabel(""),2,0); grid_ac->addWidget(_button_autocool_reheat=new QPushButton("Reheat"),2,1); connect(_button_autocool_reheat,SIGNAL(clicked()),this,SLOT(reheat())); grid_ac->setRowStretch(3, 1); setup_from_mutation_parameters(); // Do this AFTER setup connect(_spinbox_magnitude,SIGNAL(valueChanged(int)),this,SLOT(changed_magnitude(int))); connect(_spinbox_parameter_reset,SIGNAL(valueChanged(int)),this,SLOT(changed_parameter_reset(int))); connect(_spinbox_glitch,SIGNAL(valueChanged(int)),this,SLOT(changed_glitch(int))); connect(_spinbox_shuffle,SIGNAL(valueChanged(int)),this,SLOT(changed_shuffle(int))); connect(_spinbox_insert,SIGNAL(valueChanged(int)),this,SLOT(changed_insert(int))); connect(_spinbox_substitute,SIGNAL(valueChanged(int)),this,SLOT(changed_substitute(int))); connect(_checkbox_autocool_enable,SIGNAL(stateChanged(int)),this,SLOT(changed_autocool_enable(int))); connect(_spinbox_autocool_halflife,SIGNAL(valueChanged(int)),this,SLOT(changed_autocool_halflife(int))); lo->addStretch(); _ok=new QPushButton("OK"); lo->addWidget(_ok); _ok->setDefault(true); connect( _ok,SIGNAL(clicked()), this,SLOT(hide()) ); connect( _mutation_parameters,SIGNAL(changed()), this,SLOT(mutation_parameters_changed()) ); } DialogMutationParameters::~DialogMutationParameters() {} void DialogMutationParameters::setup_from_mutation_parameters() { _spinbox_magnitude ->setValue(static_cast(0.5+_scale*_mutation_parameters->base_magnitude_parameter_variation())); _spinbox_parameter_reset ->setValue(static_cast(0.5+_scale*_mutation_parameters->base_probability_parameter_reset())); _spinbox_glitch ->setValue(static_cast(0.5+_scale*_mutation_parameters->base_probability_glitch())); _spinbox_shuffle ->setValue(static_cast(0.5+_scale*_mutation_parameters->base_probability_shuffle())); _spinbox_insert ->setValue(static_cast(0.5+_scale*_mutation_parameters->base_probability_insert())); _spinbox_substitute ->setValue(static_cast(0.5+_scale*_mutation_parameters->base_probability_substitute())); _checkbox_autocool_enable->setChecked(_mutation_parameters->autocool_enable()); _spinbox_autocool_halflife->setValue(_mutation_parameters->autocool_halflife()); _label_autocool_generations->setText(QString("Generations: ")+QString::number(_mutation_parameters->autocool_generations())); // Grey-out any irrelevant settings _spinbox_autocool_halflife->setEnabled(_mutation_parameters->autocool_enable()); _button_autocool_reheat->setEnabled(_mutation_parameters->autocool_enable() && _mutation_parameters->autocool_generations()>0); } void DialogMutationParameters::reset() { _mutation_parameters->reset(); setup_from_mutation_parameters(); } void DialogMutationParameters::heat() { _spinbox_magnitude->stepUp(); } void DialogMutationParameters::cool() { _spinbox_magnitude->stepDown(); } void DialogMutationParameters::irradiate() { _spinbox_parameter_reset->stepUp(); _spinbox_glitch->stepUp(); _spinbox_shuffle->stepUp(); _spinbox_insert->stepUp(); _spinbox_substitute->stepUp(); } void DialogMutationParameters::shield() { _spinbox_parameter_reset->stepDown(); _spinbox_glitch->stepDown(); _spinbox_shuffle->stepDown(); _spinbox_insert->stepDown(); _spinbox_substitute->stepDown(); } void DialogMutationParameters::reheat() { _mutation_parameters->autocool_generations(0); } void DialogMutationParameters::changed_autocool_enable(int buttonstate) { if (buttonstate==Qt::Checked) _mutation_parameters->autocool_enable(true); else if (buttonstate==Qt::Unchecked) _mutation_parameters->autocool_enable(false); } void DialogMutationParameters::changed_magnitude(int v) { _mutation_parameters->base_magnitude_parameter_variation(v/static_cast(_scale)); } void DialogMutationParameters::changed_parameter_reset(int v) { _mutation_parameters->base_probability_parameter_reset(v/static_cast(_scale)); } void DialogMutationParameters::changed_glitch(int v) { _mutation_parameters->base_probability_glitch(v/static_cast(_scale)); } void DialogMutationParameters::changed_shuffle(int v) { _mutation_parameters->base_probability_shuffle(v/static_cast(_scale)); } void DialogMutationParameters::changed_insert(int v) { _mutation_parameters->base_probability_insert(v/static_cast(_scale)); } void DialogMutationParameters::changed_substitute(int v) { _mutation_parameters->base_probability_substitute(v/static_cast(_scale)); } void DialogMutationParameters::changed_autocool_halflife(int v) { _mutation_parameters->autocool_halflife(v); } void DialogMutationParameters::mutation_parameters_changed() { setup_from_mutation_parameters(); } evolvotron-0.8.3/libevolvotron/dialog_mutatable_image_display.h0000644000175000017500000000453615230700302023644 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class DialogMutatableImageDisplay. */ #ifndef _dialog_mutatable_image_display_h_ #define _dialog_mutatable_image_display_h_ #include "common.h" //! Provides a "Properties" style dialog box for manipulating /*! Make this modal for simplicity: avoids spawned images changing underneath us, and the possibility of opening one for every display. */ class DialogMutatableImageDisplay : public QDialog { private: Q_OBJECT protected: //! Tabs for info and xml (summary and detail) QTabWidget* _tabs; //! Message displaying some info about the image. QLabel* _label_info; //! Scrolling text area for XML description. QTextEdit* _textedit_xml; //! Button to close dialog. QPushButton* _ok; public: //! Constructor. DialogMutatableImageDisplay(QWidget* parent); //! Destructor. ~DialogMutatableImageDisplay(); //! Set content of main text and scrolling area. void set_content(const std::string& m,const std::string& x); }; #endif evolvotron-0.8.3/libevolvotron/dialog_mutatable_image_display.cpp0000644000175000017500000000454715230700302024201 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of class DialogMutatableImageDisplay. */ #include "dialog_mutatable_image_display.h" DialogMutatableImageDisplay::DialogMutatableImageDisplay(QWidget* parent) :QDialog(parent) { setWindowTitle("Image Properties"); setSizeGripEnabled(true); setLayout(new QVBoxLayout); _tabs=new QTabWidget; layout()->addWidget(_tabs); _label_info=new QLabel(QString("")); _tabs->addTab(_label_info,"Summary"); _textedit_xml=new QTextEdit; _textedit_xml->setReadOnly(true); _tabs->addTab(_textedit_xml,"Detail"); _ok=new QPushButton("OK"); _ok->setDefault(true); layout()->addWidget(_ok); connect( _ok,SIGNAL(clicked()), this,SLOT(hide()) ); } DialogMutatableImageDisplay::~DialogMutatableImageDisplay() {} void DialogMutatableImageDisplay::set_content(const std::string& m,const std::string& x) { _label_info->setText(QString(m.c_str())); _label_info->adjustSize(); _textedit_xml->setPlainText(x.c_str()); adjustSize(); updateGeometry(); } evolvotron-0.8.3/libevolvotron/dialog_help.h0000644000175000017500000000340715230700302017723 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class DialogHelp. */ #ifndef _dialog_help_h_ #define _dialog_help_h_ #include "common.h" //! Provides a dialog box with some user documentation. /*! More of a quick reference guide than a manual. */ class DialogHelp : public QDialog { private: Q_OBJECT public: //! Constructor. DialogHelp(QWidget* parent,bool full); //! Destructor. ~DialogHelp(); }; #endif evolvotron-0.8.3/libevolvotron/dialog_help.cpp0000644000175000017500000000712715230700302020261 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of class DialogHelp. */ #include "dialog_help.h" #include "license.h" //! The text to be displayed /*! \todo Should obtain this from processing external (X)HTML docs, if there were any. */ static const char*const helptext_short= "" "

Evolvotron Quick Reference

" "

Keyboard

" "
    " "
  • " " Ctrl-F - Toggle fullscreen mode" "
  • " "
  • " " Ctrl-M - Hide menu and status bars" "
  • " "
  • " " Esc - Returns to normal mode from full-screen/menu-hidden mode." "
  • " "
  • " " R - Reset (reset mutation parameters and locks)" "
  • " "
  • " " T - Restart (preserve mutation parameters and locks)" "
  • " "
  • " " X - Remix (randomize function weights and restart)" "
  • " "
  • " " Ctrl-Z or U - Undo" "
  • " "
" "

Mouse

" "

Left-click

" "
    " "
  • Spawns mutant offspring.
  • " "
  • Toggle lock (in upper right).
  • " "
" "

Middle-drag

" "
    " "
  • " " Unmodified - pan" "
  • " "
  • " " Shift - isotropic zoom" "
  • " "
  • " " Alt-Shift - anisotropic zoom" "
  • " "
  • " " Ctrl - rotate about centre" "
  • " "
  • " " Ctrl-Alt - shear" "
  • " "
" "

Right-click

" "
  • Brings up context menu.
" "

Mouse Wheel

" "
  • Zooms the image in and out.
" "

Command Line Options

" "

" "Command line options are described in the user manual." "A short summary can be obtained by invoking evolvotron with the -h or --help option" "

" "
" ; static const char*const helptext_long= #include "usage_text.h" ; DialogHelp::DialogHelp(QWidget* parent,bool full) :QDialog(parent) { setWindowTitle(full ? "Evolvotron User Manual" : "Evolvotron Quick Reference"); setMinimumSize(480,360); setSizeGripEnabled(true); setLayout(new QVBoxLayout); QTextBrowser*const browser=new QTextBrowser; layout()->addWidget(browser); browser->setText(full ? helptext_long : helptext_short); QPushButton*const ok=new QPushButton("OK"); layout()->addWidget(ok); ok->setDefault(true); connect ( ok,SIGNAL(clicked()), this,SLOT(hide()) ); } DialogHelp::~DialogHelp() {} evolvotron-0.8.3/libevolvotron/dialog_functions.h0000644000175000017500000001035115230700302020777 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class DialogFunctions. */ #ifndef _dialog_functions_h_ #define _dialog_functions_h_ #include "common.h" #include "mutation_parameters_qobject.h" class EvolvotronMain; //! Utility class for DialogFunctions. Expands changed(int) to changed(src,int) /*! Would ideally live in dialog_functions.cpp, but that causes (moc-related?) problems with linking; seems to need wider visibility. \todo Move to own file and only include in dialog_functions.cpp */ class SignalExpanderValueChangedQSlider : public QObject { private: Q_OBJECT QSlider*const _src; public: SignalExpanderValueChangedQSlider(QObject* parent,QSlider* src) :QObject(parent) ,_src(src) {} public slots: void valueChanged(int v) { emit valueChanged(_src,v); } signals: void valueChanged(QSlider*,int); }; //! Similar to SignalExpanderQSlider except attaches an integer argument to the clicked signal class SignalExpanderClickedUint : public QObject { private: Q_OBJECT uint _arg; public: SignalExpanderClickedUint(QObject* parent,uint arg) :QObject(parent) ,_arg(arg) {} public slots: void clicked() { emit clicked(_arg); } signals: void clicked(uint); }; //! Provides a dialog for controlling which functions are available. class DialogFunctions : public QDialog { private: Q_OBJECT protected: //! Owner of dialog EvolvotronMain*const _parent; //! Instance of MutationParameters under dialog control. /*! \warning Careful of modifying things which might make DialogMutationParameters get out of sync */ MutationParametersQObject*const _mutation_parameters; //! Top level holder of all the dialog content. QWidget* _dialog_content; //! Notification of undiluted branching ratio. QLabel* _branching_ratio; //! Required branching ratio after dilution QSlider* _slider_target_branching_ratio; //! Proportion of diluting nodes which are pure constants QSlider* _slider_proportion_constant; //! Proportion of non-constant nodes which are 12-parameter transforms QSlider* _slider_identity_supression; //! Lookup from each slider in the weighting controls area to corresponding function. std::map _slider_to_function; public: //! Constructor. DialogFunctions(EvolvotronMain* parent,MutationParametersQObject* mp); //! Destructor. ~DialogFunctions(); //! Reload from _mutation_parameters void setup_from_mutation_parameters(); protected slots: //@{ //! Signalled by sliders. void changed_target_branching_ratio(int v); void changed_proportion_constant(int v); void changed_identity_supression(int v); void changed_function_weighting(QSlider*,int v); //@} //! Signalled by randomization methods void clicked_button_rand(uint mask); public slots: //! Signalled by mutation parameters void mutation_parameters_changed(); }; #endif evolvotron-0.8.3/libevolvotron/dialog_functions.cpp0000644000175000017500000002741515230700302021343 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of class DialogFunctions. */ #include "dialog_functions.h" #include "evolvotron_main.h" #include "function_registry.h" /*! Dialog controls function weightings and related parameters. */ DialogFunctions::DialogFunctions(EvolvotronMain* parent,MutationParametersQObject* mp) :QDialog(parent) ,_parent(parent) ,_mutation_parameters(mp) { assert(_parent!=0); setWindowTitle("Functions"); setMinimumSize(480,360); // Have to scroll through tabs if don't set this setSizeGripEnabled(true); setLayout(new QVBoxLayout); QTabWidget*const tabs=new QTabWidget; layout()->addWidget(tabs); QPushButton*const ok=new QPushButton("OK"); layout()->addWidget(ok); ok->setDefault(true); for (int c=-1;csetLayout(tab_content_layout); tabs->addTab(tab_content,(c==-1 ? "All" : function_classification_name[c])); QWidget*const buttons=new QWidget; buttons->setLayout(new QHBoxLayout); tab_content->layout()->addWidget(buttons); QPushButton*const button_less=new QPushButton("Less"); QPushButton*const button_rand=new QPushButton("Randomize"); QPushButton*const button_more=new QPushButton("More"); buttons->layout()->addWidget(button_less); buttons->layout()->addWidget(button_rand); buttons->layout()->addWidget(button_more); SignalExpanderClickedUint*const bx_rand=new SignalExpanderClickedUint(this,(c==-1 ? 0xffffffff : (1<setWidgetResizable(true); tab_content->layout()->addWidget(scrollarea); tab_content_layout->setStretchFactor(scrollarea,1); QWidget*const scrollcontent=new QWidget; scrollcontent->setLayout(new QVBoxLayout); scrollarea->setWidget(scrollcontent); const FunctionRegistry& reg = _parent->mutation_parameters().function_registry(); for (const auto& it : reg) { const FunctionRegistration* fn = it.second; if (c==-1 || fn->classification & (1<name.c_str()); scrollarea->widget()->layout()->addWidget(g); g->setLayout(new QHBoxLayout); QSizePolicy spx(QSizePolicy::Expanding,QSizePolicy::Preferred); g->setSizePolicy(spx); g->layout()->addWidget(new QLabel("2^-10")); QSlider*const s=new QSlider(Qt::Horizontal); g->layout()->addWidget(s); s->setMinimum(-10); s->setMaximum(0); s->setValue(0); s->setTickInterval(1); s->setTickPosition(QSlider::TicksBothSides); s->setSizePolicy(spx); g->layout()->addWidget(new QLabel("1")); _slider_to_function.insert(std::make_pair(s,fn)); SignalExpanderValueChangedQSlider*const sx=new SignalExpanderValueChangedQSlider(this,s); connect( s,SIGNAL(valueChanged(int)), sx,SLOT(valueChanged(int)) ); connect( sx,SIGNAL(valueChanged(QSlider*,int)), this,SLOT(changed_function_weighting(QSlider*,int)) ); // Wire up buttons #if QT_VERSION >= 0x050000 // New Qt5 style supports lambdas! connect( button_less,&QPushButton::clicked, s,[s](){s->triggerAction(QAbstractSlider::SliderSingleStepSub);} ); connect( button_more,&QPushButton::clicked, s,[s](){s->triggerAction(QAbstractSlider::SliderSingleStepAdd);} ); #else // Otherwise fall back to old way // Fortunately the deprecated subtractStep/addStep members are still available in Qt4 connect( button_less,SIGNAL(clicked()), s,SLOT(subtractStep()) ); connect( button_more,SIGNAL(clicked()), s,SLOT(addStep()) ); #endif } } } // And add another tab for all the branching-ratio/dilution controls { QWidget*const vbox=new QWidget; vbox->setLayout(new QVBoxLayout); tabs->addTab(vbox,"Dilution"); _branching_ratio=new QLabel; vbox->layout()->addWidget(_branching_ratio); QGroupBox*const c0=new QGroupBox("Required branching ratio after dilution"); c0->setLayout(new QHBoxLayout); vbox->layout()->addWidget(c0); c0->layout()->addWidget(new QLabel("0.1")); _slider_target_branching_ratio=new QSlider(Qt::Horizontal); c0->layout()->addWidget(_slider_target_branching_ratio); _slider_target_branching_ratio->setMinimum(10); _slider_target_branching_ratio->setMaximum(90); _slider_target_branching_ratio->setValue(50); _slider_target_branching_ratio->setTickInterval(10); _slider_target_branching_ratio->setTickPosition(QSlider::TicksBothSides); _slider_target_branching_ratio->setToolTip("The branching ratio must be diluted to <1.0 to prevent formation of infinitely large function-trees.\nWarning: setting a high value results in complex function trees taking a long time to compute.\nSetting a low value results in very simple images."); c0->layout()->addWidget(new QLabel("0.9")); QGroupBox*const c1=new QGroupBox("Of diluting nodes, proportion constant:"); c1->setLayout(new QHBoxLayout); vbox->layout()->addWidget(c1); c1->layout()->addWidget(new QLabel("0.0")); _slider_proportion_constant=new QSlider(Qt::Horizontal,c1); c1->layout()->addWidget(_slider_proportion_constant); _slider_proportion_constant->setMinimum(0); _slider_proportion_constant->setMaximum(100); _slider_proportion_constant->setValue(50); _slider_proportion_constant->setTickInterval(10); _slider_proportion_constant->setTickPosition(QSlider::TicksBothSides); _slider_proportion_constant->setToolTip("This specifies the proportion of diluting nodes which will be constant."); c1->layout()->addWidget(new QLabel("1.0")); QGroupBox*const c2=new QGroupBox("Of non-constant diluting nodes, proportion transforms"); c2->setLayout(new QHBoxLayout); vbox->layout()->addWidget(c2); c2->layout()->addWidget(new QLabel("0.0")); _slider_identity_supression=new QSlider(Qt::Horizontal,c2); c2->layout()->addWidget(_slider_identity_supression); _slider_identity_supression->setMinimum(0); _slider_identity_supression->setMaximum(100); _slider_identity_supression->setValue(50); _slider_identity_supression->setTickInterval(10); _slider_identity_supression->setTickPosition(QSlider::TicksBothSides); _slider_identity_supression->setToolTip("This specifies the proportion of non-constant diluting nodes which will be transforms (c.f identity nodes)."); c2->layout()->addWidget(new QLabel("1.0")); connect( _slider_target_branching_ratio,SIGNAL(valueChanged(int)), this,SLOT(changed_target_branching_ratio(int)) ); connect( ok,SIGNAL(clicked()), this,SLOT(hide()) ); connect( _slider_proportion_constant,SIGNAL(valueChanged(int)), this,SLOT(changed_proportion_constant(int)) ); connect( _slider_identity_supression,SIGNAL(valueChanged(int)), this,SLOT(changed_identity_supression(int)) ); } setup_from_mutation_parameters(); connect( _mutation_parameters,SIGNAL(changed()), this,SLOT(mutation_parameters_changed()) ); } DialogFunctions::~DialogFunctions() {} void DialogFunctions::setup_from_mutation_parameters() { const real b=_mutation_parameters->random_function_branching_ratio(); const real s=_mutation_parameters->proportion_basic(); const real br=(1.0-s)*b; std::stringstream msg; msg << "Undiluted random function branching ratio is " << b << "\n" << "Diluting in proportion " << s << " to obtain required branching ratio."; _branching_ratio->setText(msg.str().c_str()); _slider_target_branching_ratio->setValue(static_cast(100.0*br+0.5)); _slider_proportion_constant->setValue(static_cast(0.5+100.0*_mutation_parameters->proportion_constant())); _slider_identity_supression->setValue(static_cast(0.5+100.0*_mutation_parameters->identity_supression())); for (std::map::const_iterator it=_slider_to_function.begin(); it!=_slider_to_function.end(); it++ ) { const real w=_mutation_parameters->get_weighting((*it).second); const int iw=static_cast(floor(0.5+(log(w)*(1.0/M_LN2)))); if (iw!=(*it).first->value()) { (*it).first->setValue(iw); } } } void DialogFunctions::changed_target_branching_ratio(int v) { const real target_branching_ratio=v/100.0; // Want to solve tgt=proportion_basic*0.0+(1.0-proportion_basic)*random_function_branching_ratio const real proportion_basic=1.0-target_branching_ratio/_mutation_parameters->random_function_branching_ratio(); std::clog << "Basic-node dilution proportion set to " << proportion_basic << " giving a branching ratio of " << (1.0-proportion_basic)*_mutation_parameters->random_function_branching_ratio() << "\n"; _mutation_parameters->proportion_basic(proportion_basic); setup_from_mutation_parameters(); } void DialogFunctions::changed_proportion_constant(int v) { _mutation_parameters->proportion_constant(v/100.0); } void DialogFunctions::changed_identity_supression(int v) { _mutation_parameters->identity_supression(v/100.0); } void DialogFunctions::changed_function_weighting(QSlider* s,int v) { std::map::const_iterator it=_slider_to_function.find(s); if (it==_slider_to_function.end()) { std::clog << "DialogFunctions::changed_function_weighting : unknown source slider, ignoring\n"; } else { const FunctionRegistration* fn = (*it).second; const real w=pow(2,v); std::clog << fn->name << " weighting changed to " << w << "\n"; _mutation_parameters->change_function_weighting(fn,w); } } void DialogFunctions::clicked_button_rand(uint mask) { std::clog << "Randomizing functions matching mask " << mask << "\n"; _mutation_parameters->randomize_function_weightings_for_classifications(mask); } void DialogFunctions::mutation_parameters_changed() { //std::clog << "[DialogFunctions::mutation_parameters_changed()]\n"; setup_from_mutation_parameters(); } evolvotron-0.8.3/libevolvotron/dialog_favourite.h0000644000175000017500000000605415230700302021000 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class DialogFavourite. */ #ifndef _dialog_favourite_h_ #define _dialog_favourite_h_ #include "common.h" class EvolvotronMain; //! Provides a dialog for controlling which functions are available. class DialogFavourite : public QDialog { private: Q_OBJECT protected: //! Owner. EvolvotronMain* _parent; //! Function name to be used as the root node of new image function tres (no favourite if empty) std::string _favourite_function; //! Flag specifying whether favourite function should be exposed bool _favourite_function_unwrapped; //! Map function names to combo box entries. std::map _favourite_fn_to_index; //! Look up function names from combo box. std::map _index_to_favourite_fn; //! Select favourite function, if any. QComboBox* _favourite; //! Controls unwrapped state. QCheckBox* _unwrapped; //! Make GUI match _favourite_function and _favourite_function_unwrapped state void update_gui_from_state(); protected slots: //! Invoked on combo-box selection. void changed_favourite(int i); //! Invoked on checkbox toggle. void changed_unwrapped(bool b); public: //! Constructor. DialogFavourite(EvolvotronMain* parent); //! Destructor. ~DialogFavourite(); //! Accessor const std::string& favourite_function() const { return _favourite_function; } //! Accessor. Returns true if function name recognised. bool favourite_function(const std::string& f); //! Accessor. bool favourite_function_unwrapped() const { return _favourite_function_unwrapped; } //! Accessor. void favourite_function_unwrapped(bool v); }; #endif evolvotron-0.8.3/libevolvotron/dialog_favourite.cpp0000644000175000017500000001044115230700302021326 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of class DialogFavourite. */ #include "dialog_favourite.h" #include "function_registry.h" #include "evolvotron_main.h" DialogFavourite::DialogFavourite(EvolvotronMain* parent) :QDialog(parent) ,_parent(parent) ,_favourite_function_unwrapped(false) { setWindowTitle("Favourite"); setSizeGripEnabled(true); QBoxLayout* lo = new QVBoxLayout(this); QGroupBox*const group0=new QGroupBox("Function"); group0->setLayout(new QVBoxLayout); lo->addWidget(group0); group0->layout()->addWidget(new QLabel("Root node for new image functions:")); _favourite=new QComboBox; group0->layout()->addWidget(_favourite); _favourite_fn_to_index[""]=_favourite->count(); _index_to_favourite_fn[_favourite->count()]=""; _favourite->addItem("- No preference -"); const FunctionRegistry& reg = _parent->mutation_parameters().function_registry(); for (const auto& it : reg) { const std::string& fname = it.second->name; _favourite_fn_to_index[fname] = _favourite->count(); _index_to_favourite_fn[_favourite->count()] = fname; _favourite->addItem(fname.c_str()); } QGroupBox*const group1=new QGroupBox("Wrapping"); group1->setLayout(new QVBoxLayout); lo->addWidget(group1); _unwrapped=new QCheckBox("Disable additional space/colour transforms"); group1->layout()->addWidget(_unwrapped); lo->addStretch(); //! \todo: Add OK & reset/restart versions ? QPushButton*const ok=new QPushButton("OK"); lo->addWidget(ok); ok->setDefault(true); update_gui_from_state(); connect(_favourite,SIGNAL(activated(int)),this,SLOT(changed_favourite(int))); connect(_unwrapped,SIGNAL(toggled(bool)),this,SLOT(changed_unwrapped(bool))); connect(ok,SIGNAL(clicked()),this,SLOT(hide())); } DialogFavourite::~DialogFavourite() {} void DialogFavourite::changed_favourite(int i) { const std::map::const_iterator it=_index_to_favourite_fn.find(i); if (it!=_index_to_favourite_fn.end()) { _favourite_function=(*it).second; } update_gui_from_state(); } void DialogFavourite::changed_unwrapped(bool b) { _favourite_function_unwrapped=b; update_gui_from_state(); } void DialogFavourite::update_gui_from_state() { const std::map::const_iterator it=_favourite_fn_to_index.find(_favourite_function); if (it!=_favourite_fn_to_index.end()) _favourite->setCurrentIndex((*it).second); else _favourite->setCurrentIndex(0); _unwrapped->setChecked(_favourite_function_unwrapped); _unwrapped->setEnabled(!_favourite_function.empty()); } bool DialogFavourite::favourite_function(const std::string& f) { if (_parent->mutation_parameters().function_registry().lookup(f)) { _favourite_function=f; update_gui_from_state(); return true; } else return false; } void DialogFavourite::favourite_function_unwrapped(bool v) { _favourite_function_unwrapped=v; update_gui_from_state(); } evolvotron-0.8.3/libevolvotron/dialog_about.h0000644000175000017500000000346515230700302020111 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class DialogAbout. */ #ifndef _dialog_about_h_ #define _dialog_about_h_ #include "common.h" //! Provides an "About" dialog box. /*! About dialog displays author info, web addresses and license info. */ class DialogAbout : public QDialog { private: Q_OBJECT public: //! Constructor. DialogAbout(QWidget* parent,int n_threads,bool separate_farm_for_enlargements); //! Destructor. ~DialogAbout(); }; #endif evolvotron-0.8.3/libevolvotron/dialog_about.cpp0000644000175000017500000000635215230700302020442 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of class DialogAbout. */ #include #include "dialog_about.h" #include "license.h" DialogAbout::DialogAbout(QWidget* parent,int n_threads,bool separate_farm_for_enlargements) :QDialog(parent) { assert(parent!=0); setWindowTitle("About Evolvotron"); setMinimumSize(480,360); setSizeGripEnabled(true); setLayout(new QVBoxLayout); QTabWidget*const tabs=new QTabWidget; layout()->addWidget(tabs); QWidget*const tab_info=new QWidget; tab_info->setLayout(new QVBoxLayout); tabs->addTab(tab_info,"Info"); QWidget*const tab_license=new QWidget; tab_license->setLayout(new QVBoxLayout); tabs->addTab(tab_license,"License"); std::ostringstream about_string; about_string << "

Evolvotron

\n" << "

" APP_BUILD "

\n" << "

Using " << (separate_farm_for_enlargements ? "2 pools" : "1 pool") << " of " << n_threads << " compute thread" << (n_threads>1 ? "s" : "") << "

\n" "

Authors: Tim Day, " "Karl Robillard

\n" "

[Home Page]" "  " "[Project Page]" "

\n"; QLabel*const label=new QLabel(about_string.str().c_str()); tab_info->layout()->addWidget(label); label->setIndent(32); label->setAlignment(Qt::AlignTop); label->setOpenExternalLinks(true); QTextEdit*const license=new QTextEdit; tab_license->layout()->addWidget(license); license->setReadOnly(true); license->setPlainText((std::string("License:\n")+std::string(license_string)).c_str()); QPushButton* ok=new QPushButton("OK"); layout()->addWidget(ok); ok->setDefault(true); connect ( ok,SIGNAL(clicked()), this,SLOT(hide()) ); } DialogAbout::~DialogAbout() {} evolvotron-0.8.3/libevolvotron/common.h0000644000175000017500000000466715230700302016755 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Precompiled header for libevolvotron Could load this up with Qt headers maybe. */ #ifndef _libevolvotron_precompiled_h_ #define _libevolvotron_precompiled_h_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define APP_VERSION "0.8.3" #ifdef DEBUG #define APP_BUILD APP_VERSION " (Debug)" #else #define APP_BUILD APP_VERSION #endif #endif evolvotron-0.8.3/extras/0000755000175000017500000000000015230700302013701 5ustar karlkarlevolvotron-0.8.3/extras/spheremap.sh0000755000175000017500000000023215230700302016221 0ustar karlkarl#!/bin/bash # Disclaimer: I'm using povray version "3.5 Unix". Which is probably quite old now. povray spheremap.pov +KFI1 +KFF100 +H240 +W320 +Of.png evolvotron-0.8.3/extras/spheremap.pov0000644000175000017500000000036015230700302016412 0ustar karlkarl#include "colors.inc" camera {perspective location <0,1,-4.5> look_at <0,0,0> angle 45} light_source {<100,100,-100> color White} sphere { <0,0,0>,1 pigment { image_map {png "spheremap.png" map_type 1} } rotate <0,clock*360,0.0> } evolvotron-0.8.3/extras/evolvotron_complexity0000755000175000017500000001311715230700302020324 0ustar karlkarl#!/bin/bash # SPDX-License-Identifier: GPL-2.0-or-later #BEGIN# # Evolvotron_complexity # http://freaknet.org/alpt/src/misc/evolvotron_complexity # # # This script is based on `evolvotron' a wonderful program which mutates # algorithmically generated images. You can get it here: # http://www.bottlenose.demon.co.uk/share/evolvotron/index.htm # # This script mutates an initial random image in only one direction, that of # the minimum redundancy, or in another words that of the maximum complexity. # # *** Usage # # evolvotron_complexity [new [function.xml]] # evolvotron_complexity [frame_number] # # 1) Copy the script into an empty directory and go there # # mkdir ev; cp evolvotron_complexity ev/ ; cd ev/ # # 2) Launch the script for the first time # # ./evolvotron_complexity new # # In this way it starts from a random function and runs forever (until you # kill it). # The evolution can also start from an existing function, f.e. a function # generated by evolvotron: # # ./evolvotron_complexity new function.xml # # All the generate images and function will be saved in the current # directory with the good_NUMBER.xml and good_NUMBER.ppm file name. # # 3) If you've halted the script, you can continue from the previous mutation # by simply running: # ./evolvotron_complexity. # If you want to continue from a specific frame (let's say good_17.xml), # specify it: # ./evolvotron_complexity 17 # # 4) Render the final high quality image # # cat good_NUMBER.xml | evolvotron_render -s 1024 1024 rendered_image.ppm # Where good_NUMBER.xml is the function of the final image # # 5) Enjoy ^_^ # # Note: After some time you'll see that the output images will degenerate. If # you let the degenerated images evolve, they will be more and # more like a /dev/urandom image: # cat /dev/urandom | rawtoppm 1024 768 > TEST.ppm; display TEST.ppm # # When you've reached this point, you won't go further very much, so # it's better to stop the script, choose the really last good frame, # increasing resolution and continuing from there. Ex: # - We are at good_37.xml, but it is already degenerated. Let's # continue from good_20.xml # - ./evolvotron_complexity 20 # For more info on this problem, read the "Parameters" section below. # # # AlpT (@freaknet.org) # #END# ## #### Parameters ## # With higher resolutions the measurement of the complexity is more accurate # but the rendering times increase. # # With inaccurate measurement the evolutions won't happen often, because the # script cannot distinguish well the complexity of two images, f.e. in the # extreme case, if you set the 1x1 (one pixel) resolution, it won't ever # mutate. # # High resolution give awesome result (try for example 2048 2048). # In the other hand, high resolution requires high computational power to # render each mutated image. # # If the evolution is blocked try doubling the resolution. #resolution="4096x4096" #resolution="2048x2048" resolution="1024x1024" #resolution="512x512" #resolution="256x256" # Retrieve the resolution from the `resolution' file [ -f resolution ] && resolution=$(< resolution) echo "Resolution is set to $resolution" #### abort() { echo aborted exit 1 } trap "abort" SIGINT SIGQUIT check() { while [ 0 ] ; do if [ -f xxx.ppm ]; then display xxx.ppm; fi done } # get_complexity function.xml output.ppm get_complexity() { cat $1 | evolvotron_render -s $resolution -o $2; bzip2 -f $2 stat -c %s $2.bz2 } if test "$1" = "help" -o "$1" = "-h" -o "$1" = "--help" then echo "Usage:" echo " evolvotron_complexity [new [function.xml]]" echo "" cat $0 | sed -ne '/\#BEGIN\#/,/\#END\#/p' | less exit 1 fi ## #### New evolution ## if [ "$1" == "new" ] then if [ -f fn_ok.xml ] then echo "fn_ok.xml already exists. Remove it and retry." exit 1 fi if [ ! -z "$2" ] then if [ -f "$2" ] then echo "Starting the evolution from $2" cp $2 fn_ok.xml else echo "$2 doesn't exist" exit 1 fi else evolvotron_mutate -g > fn_ok.xml fi echo 0 > last_frame elif [ ! -z "$1" ] then if [ -f "$1" ] && echo $1 | grep -q '\.xml$' then echo "Continuing evolution from $1" cp $1 fn_ok.xml else last_frame="$1" fi fi best_size=0 frame=0 # # Start from the last frame (if any) # if [ -f last_frame ] then frame=`cat last_frame` else echo 0 > last_frame fi if [ ! -z "$last_frame" ] then frame=$last_frame fi if [ "$frame" -gt 0 ] then echo "Continuing from the $frame-th frame" cp good_$frame.xml fn_ok.xml if [ -f good_$frame.ppm ] then echo "Reading good_$frame.ppm size" bzip2 -fk good_$frame.ppm best_size="`stat -c %s good_$frame.ppm.bz2`" rm good_$frame.ppm.bz2 elif [ -f good_$frame.xml ] then echo "Calculating good_$frame.xml size" best_size="`get_complexity good_$frame.xml xxx.ppm`" fi elif [ -f fn_ok.xml ] then echo "Calculating fn_ok size" best_size="`get_complexity fn_ok.xml xxx.ppm`" else echo "fn_ok.xml and good_$frame.xml don't exist." echo "Maybe you want to use:" echo " ./evolvotron_complexity new" exit 1 fi #check & ## #### The core of evolvotron_complexity # loop: # mutate_and_render # compress # if compressed_size > best_size # best_size=compressed_size # goto loop ## while [ 0 ] do cat fn_ok.xml | evolvotron_mutate > fn_new.xml size="`get_complexity fn_new.xml xxx.ppm`" if [ $size -gt $best_size ] then best_size=$size cp fn_new.xml fn_ok.xml echo "" echo $((++frame)) > last_frame echo "new $frame" cp fn_new.xml good_$frame.xml cp xxx.ppm.bz2 good_$frame.ppm.bz2 bunzip2 -f good_$frame.ppm.bz2 fi printf "." done evolvotron-0.8.3/extras/README0000644000175000017500000000045315230700302014563 0ustar karlkarl --- spheremap.sh is a script to animate a spheremap applied to a rotating sphere. The scene description is in spheremap.pov. It assumes the existence of a file called spheremap.png, which you should create by saving an (enlarged, probably) image from evolvotron running in -spheremap mode. --- evolvotron-0.8.3/experiment/0000755000175000017500000000000015230700302014553 5ustar karlkarlevolvotron-0.8.3/experiment/svg/0000755000175000017500000000000015230700302015352 5ustar karlkarlevolvotron-0.8.3/experiment/svg/svg.pro0000644000175000017500000000106215230700302016672 0ustar karlkarlTEMPLATE = app CONFIG+= qt opengl stl exceptions release # release debug QT += opengl svg SOURCES += svg.cpp ####################################### # Disable assertions in release version QMAKE_CXXFLAGS_RELEASE += -DNDEBUG QMAKE_CFLAGS_RELEASE += -DNDEBUG ###################################### # Other stuff: # Disable implicit cast from QString to char* QMAKE_CXXFLAGS_RELEASE += -DQT_NO_ASCII_CAST QMAKE_CXXFLAGS_DEBUG += -DQT_NO_ASCII_CAST ###################################### # Hide those crufty moc_ files away MOC_DIR = moc OBJECTS_DIR = obj evolvotron-0.8.3/experiment/svg/svg.cpp0000644000175000017500000000255315230700302016662 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ evolvotron-0.8.3/experiment/svg/drawing0.svg0000644000175000017500000002235715230700302017617 0ustar karlkarl image/svg+xml evolvotron-0.8.3/experiment/svg/GLTRACE.INI0000644000175000017500000000553115230700302017000 0ustar karlkarl;-------------------------------------------------------------------------- ; ;Sample GLTRACE.INI for GLQuake inspection ; ;(Blank lines OK, comment lines must begin with ';' character) ; ;[Configuration]: ; LogCalls : Write function calls to the log. Can be toggled on/off. ; CountCalls : Write a table of call counts at end of log file. ; Verbose : Write all function arguments and return values. ; LogTime : Write the time of each function call to the log file. ; FPS_White : Display FPS counter in white numbers. Can be toggled on/off. ; FPS_Black : Display FPS counter in black numbers. Can be toggled on/off. ; FPS_Yellow : Display FPS counter in yellow numbers. Can be toggled on/off. ; DisableExt : Disable extensions; wglGetProcAddress or glXGetProcAddressARB ; will always return NULL. ; ;[Keys] ; User specified keys. Valid keys include any un-shifted character, function ; keys, shift, alt, ctrl, tab, up, down, left, right, insert, delete, home, ; end, pageup, pagedn, backsp, enter, or space. ; ; Option key : Log optional calls while down. ; One frame key : Log ALL calls for one full rendering frame. ; FPS key : Toggle FPS counter on/off if enabled. ; On-off key : Toggles normal logging on/off if enabled. ; ;[Implementation]: Specify name and location of OpenGL DLL or shared library to call from ; debugging shell ; ;[Output}: Specify text file to contain resulting debug trace ; If not specified, trace will be written to stdout ; ;[Exclude]: List of functions to exclude from debug trace ; (e.g., extremely common functions like glVertex2f that can ; bog down the application under test if calls to it are ; traced) ; ;[Optional]: List of functions to be included in debug trace ONLY while ; Shift or Alt held down (allows application to run at ; near-normal speed until tracing requested by user) ; ;-------------------------------------------------------------------------- [Configuration] LogCalls Verbose CountCalls FPS_Yellow [Keys] ; keys MUST be in the order listed ; Option key shift ; One frame key F1 ; FPS toggle key F2 ; On-Off toggle key Z [Implementation] ; ;(GLTRACE.DLL = renamed copy of opengl32.dll from 3Dfx, or other implementation ;compatible with GLQuake, or blank to use the default opengl32.dll) ; [Output] gltrace.txt [Exclude] [Optional] ;glTexCoord2f ;glVertex2f ;glColor3f ;glVertex3f ;glVertex3fv ;glBegin ;glEnd evolvotron-0.8.3/experiment/svg/BUILD0000755000175000017500000000004315230700302016134 0ustar karlkarl#!/bin/sh qmake-qt4 svg.pro make evolvotron-0.8.3/experiment/program_options/0000755000175000017500000000000015230700302017775 5ustar karlkarlevolvotron-0.8.3/experiment/program_options/pair.cpp0000644000175000017500000000444415230700302021442 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ #include #include namespace boost { namespace program_options { BOOST_PROGRAM_OPTIONS_DECL typed_value >* intpair(std::pair*); } } using namespace boost::program_options; int main(int argc,char** argv) { bool flag; int number; std::pair pair; options_description options_desc("General options"); options_desc.add_options() ("flag,f" ,bool_switch(&flag) ,"Control a bool") ("number,n" ,value(&number)->default_value(23) ,"Specify a number") ("pair,p" ,intpair(&pair)->default_value(std::make_pair(2,3)) ,"Specify 2 numbers") ; variables_map options; store(parse_command_line(argc,argv,options_desc),options); notify(options); std::cout << "Flag: " << flag << "\n" << "Number: " << number << "\n" << "Pair: " << pair.first << " " << pair.second << "\n"; return 0; } evolvotron-0.8.3/experiment/program_options/makefile0000644000175000017500000000011415230700302021471 0ustar karlkarlall: pair pair: pair.cpp g++ pair.cpp -O2 -o pair -lboost_program_options evolvotron-0.8.3/evolvotron_render/0000755000175000017500000000000015230700302016147 5ustar karlkarlevolvotron-0.8.3/evolvotron_render/evolvotron_render.pro0000644000175000017500000000056215230700302022450 0ustar karlkarlTEMPLATE = app QT += widgets CONFIG += c++11 include (../common.pro) SOURCES += $$files(*.cpp) DEPENDPATH += ../libevolvotron ../libfunction INCLUDEPATH += ../libevolvotron ../libfunction TARGETDEPS += ../libevolvotron/libevolvotron.a ../libfunction/libfunction.a LIBS += ../libevolvotron/libevolvotron.a ../libfunction/libfunction.a -lboost_program_options evolvotron-0.8.3/evolvotron_render/evolvotron_render.cpp0000644000175000017500000001505015230700302022430 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Standalone renderer for evolvotron function files. */ #include "function_registry.h" #include "mutatable_image.h" #include "random.h" #include //! Application code int main(int argc,char* argv[]) { { uint frames; bool help; bool jitter; int multisample; std::string output_filename; std::string size; bool verbose; boost::program_options::options_description options_desc("Options"); boost::program_options::positional_options_description pos_options_desc; { using namespace boost::program_options; options_desc.add_options() ("frames,f" ,value(&frames)->default_value(1) ,"Frames in an animation") ("help,h" ,bool_switch(&help) ,"Print command-line options help message and exit") ("jitter,j" ,bool_switch(&jitter) ,"Enable rendering jitter") ("multisample,m",value(&multisample)->default_value(1),"Multisampling grid (NxN)") ("output,o" ,value(&output_filename) ,"Output filename (.png or .ppm suffix). (Or use first positional argument.)") ("size,s" ,value(&size)->default_value("512x515"),"Generated image size") ("verbose,v" ,bool_switch(&verbose) ,"Log some details to stderr") ; pos_options_desc.add("output",1); } boost::program_options::variables_map options; boost::program_options::store ( boost::program_options::command_line_parser(argc,argv) .options(options_desc).positional(pos_options_desc).run() ,options ); boost::program_options::notify(options); if (help) { std::cerr << options_desc; return 0; } if (verbose) std::clog.rdbuf(std::cerr.rdbuf()); else std::clog.rdbuf(sink_ostream.rdbuf()); //! \todo Could be done better maybe (set 'x' as input separator) const std::string::size_type p=size.find("x"); if (p==std::string::npos || p==0 || p==size.size()-1) { std::cerr << "--size option argument isn't in x format\n"; return 1; } else { size[p]=' '; } int width=512; int height=512; std::stringstream(size) >> width >> height; if (frames<1) { std::cerr << "Must specify at least 1 frame (option: -f )\n"; return 1; } if (output_filename.empty()) { std::cerr << "Must specify an output filename\n"; return 1; } FunctionRegistry function_registry; std::string report; const boost::shared_ptr imagefn(MutatableImage::load_function(function_registry,std::cin,report)); if (imagefn.get()==0) { std::cerr << "evolvotron_render: Error: Function not loaded due to errors:\n" << report; return 1; } else if (!report.empty()) { std::cerr << "evolvotron_render: Warning: Function loaded with warnings:\n" << report; } // Seed value pretty unimportant; only used for sample jitter. Random01 r01(23); for (uint frame=0;frame image_data; image_data.reserve(width*height); uint pixels=0; uint report=1; const uint reports=20; for (int row=0;rowsampling_coordinate(col,row,frame,width,height,frames)); const XYZ colour(imagefn->get_rgb(col,row,frame,width,height,frames,(jitter ? &r01 : 0),multisample)); const uint col0=lrint(clamped(colour.x(),0.0,255.0)); const uint col1=lrint(clamped(colour.y(),0.0,255.0)); const uint col2=lrint(clamped(colour.z(),0.0,255.0)); image_data.push_back(((col0<<16)|(col1<<8)|(col2))); pixels++; if (pixels>=(report*width*height)/reports) { std::clog << "[" << (100*report)/reports << "%]"; report++; } } std::clog << "\n"; { //! \todo If filename is "-", write PPM to stdout (QImage save only supports write-to-a-filenames though) QString save_filename(QString::fromLocal8Bit(output_filename.c_str())); const char* save_format="PPM"; if (save_filename.toUpper().endsWith(".PPM")) { save_format="PPM"; } else if (save_filename.toUpper().endsWith(".PNG")) { save_format="PNG"; } else { std::cerr << "evolvotron_render: Warning: Unrecognised file suffix. File will be written in " << save_format << " format.\n"; } if (frames>1) { QString frame_component = QString::asprintf(".f%06d",frame); int insert_point=save_filename.lastIndexOf(QString(".")); if (insert_point==-1) { save_filename.append(frame_component); } else { save_filename.insert(insert_point,frame_component); } } QImage image ( reinterpret_cast(&(image_data[0])), width, height, QImage::Format_RGB32 ); if (!image.save(save_filename,save_format)) { std::cerr << "evolvotron_render: Error: Couldn't save file " << save_filename.toLocal8Bit().data() << "\n"; return 1; } std::clog << "Wrote file " << save_filename.toLocal8Bit().data() << "\n"; } } } return 0; } evolvotron-0.8.3/evolvotron_mutate/0000755000175000017500000000000015230700302016167 5ustar karlkarlevolvotron-0.8.3/evolvotron_mutate/evolvotron_mutate.pro0000644000175000017500000000056215230700302022510 0ustar karlkarlTEMPLATE = app QT += widgets CONFIG += c++11 include (../common.pro) SOURCES += $$files(*.cpp) DEPENDPATH += ../libevolvotron ../libfunction INCLUDEPATH += ../libevolvotron ../libfunction TARGETDEPS += ../libevolvotron/libevolvotron.a ../libfunction/libfunction.a LIBS += ../libevolvotron/libevolvotron.a ../libfunction/libfunction.a -lboost_program_options evolvotron-0.8.3/evolvotron_mutate/evolvotron_mutate.cpp0000644000175000017500000001004515230700302022467 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Standalone mutator for evolvotron function files. */ #include "mutatable_image.h" #include "mutation_parameters.h" #include "function_top.h" #include //! Application code int main(int argc,char* argv[]) { { bool genesis; bool help; bool linear; bool spheremap; bool verbose; boost::program_options::options_description options_desc("Options"); { using namespace boost::program_options; options_desc.add_options() ("genesis,g" ,bool_switch(&genesis) ,"Create a new function to stdout (without this option, a function will be read from stdin)") ("help,h" ,bool_switch(&help) ,"Print command-line options help message and exit") ("linear,l" ,bool_switch(&linear) ,"Sweep z linearly in animations") ("spheremap,p",bool_switch(&spheremap),"Generate spheremap") ("verbose,v" ,bool_switch(&verbose) ,"Log some details to stderr") ; } boost::program_options::variables_map options; boost::program_options::store(boost::program_options::parse_command_line(argc,argv,options_desc),options); boost::program_options::notify(options); if (help) { std::cerr << options_desc; return 0; } if (verbose) std::clog.rdbuf(std::cerr.rdbuf()); else std::clog.rdbuf(sink_ostream.rdbuf()); // Normally would use time(0) to seed random number generator // but can imagine several of these starting up virtually simultaneously // so need something with higher resolution. // Adding the process id too to keep things unique. QTime t(QTime::currentTime()); uint seed=getpid()+t.msec()+1000*t.second()+60000*t.minute()+3600000*t.hour(); std::clog << "Random seed is " << seed << "\n"; MutationParameters mutation_parameters(seed,false,false); std::string report; boost::shared_ptr imagefn_out; if (genesis) { std::unique_ptr fn_top(FunctionTop::initial(mutation_parameters)); imagefn_out=boost::shared_ptr(new MutatableImage(fn_top,!linear,spheremap,false)); } else { const boost::shared_ptr imagefn_in ( MutatableImage::load_function(mutation_parameters.function_registry(),std::cin,report) ); if (imagefn_in.get()==0) { std::cerr << "evolvotron_mutate: Error: Function not loaded due to errors:\n" << report; return 1; } else if (!report.empty()) { std::cerr << "evolvotron_mutate: Warning: Function loaded with warnings:\n" << report; } imagefn_out=imagefn_in->mutated(mutation_parameters); } imagefn_out->save_function(std::cout); } return 0; } evolvotron-0.8.3/evolvotron/0000755000175000017500000000000015230700302014610 5ustar karlkarlevolvotron-0.8.3/evolvotron/icons/0000755000175000017500000000000015230700302015723 5ustar karlkarlevolvotron-0.8.3/evolvotron/icons/lock.png0000644000175000017500000000156415230700302017367 0ustar karlkarl‰PNG  IHDR szzô pHYsnn„P_$tEXtSoftwarewww.inkscape.org›î<IDATX…í’_HSQǿǹ•am"k»:éeÕ°‡ZîÞûb*¢�ùäK°—À "ÈabÏ=˜ AO‰æSD&To:ózÍ�6ÉÊÑ+ʦMw·Ý{N…-ÛÐ"hß—s~ßÏïœäõ¿‹äÒ\WWW�Ç/B.ðpHX!„L2ÆK’ô ÛwQÏSJû<Ïñ††TTT€ã8PJ‹Å‰D 177¢”^“eùõ¾ð<ËápÜnkk3y<,,,`vvŠ¢Àb±€ã8x½^¸\.„Ãaô÷÷ªª¶MOOßÛ3€ ×Ýnwgg'4MÃÀÀÂápÀcì=!„8M¹$ÂñÖÖV†�žž¶´´ä—$i(›!3JÅÊÆÆÆ¤,Ë, ²úúz�çù«™À[ZZL>Ÿïfss³.Ë2›œœdµµµqQ]»y˜v+–••ÝñûýÞÊÊJtwwCUÕË’$ fê�F£LQ” «Õ[\\¼ÐÔÔ]×-‘H¤PQ”ç9MUUU‡jjj’óóólxx˜ñ<ÿ4Ë£„çyillŒMMM1QWüªù×…‚‚3n·Ûb6› …@y˜%0233»ÝŽòòò£‚ Ë€rÔf³ÖÖÖ@)ý�%!UUØl6PJí90›Ífc &“ÉÈ€1¦¥R©ì`3%�t�N�»‘ØNú}¾³}†’z·ÔJ–Ú‰ÏH¥¶ S šÒ: S€R = ¨jú„å ãJuõ9ŒOŒÃn'}EEE÷ÛÛï…~ ÐÛÛtÄå¬Z>yª¶XKl@KlBÓ6¿­ßãdrºÁ`è †�¯{ƒAß—”Xáp–bk‹ÆÕØVy 0´ù£ßOOPHÍ€â¬î/7›L¸�ÉÝþÀ_Q �Èäþ=€ðéO™Fzý·OVÝos¼ ×væ 35¿xùîÖƒá7CËË«‡÷n½«u%îtîÊTý.ëSõïLØSIEND®B`‚evolvotron-0.8.3/evolvotron/icons.qrc0000644000175000017500000000010215230700302016423 0ustar karlkarl icons/lock.png evolvotron-0.8.3/evolvotron/evolvotron.pro0000644000175000017500000000061115230700302017545 0ustar karlkarlTEMPLATE = app QT += widgets CONFIG += c++11 include (../common.pro) RESOURCES = icons.qrc SOURCES += $$files(*.cpp) DEPENDPATH += ../libevolvotron ../libfunction INCLUDEPATH += ../libevolvotron ../libfunction TARGETDEPS += ../libevolvotron/libevolvotron.a ../libfunction/libfunction.a LIBS += ../libevolvotron/libevolvotron.a ../libfunction/libfunction.a -lboost_program_options evolvotron-0.8.3/evolvotron/evolvotron.cpp0000644000175000017500000002107715230700302017540 0ustar karlkarl/**************************************************************************/ /* Copyright 2012 Tim Day */ /* */ /* This file is part of Evolvotron */ /* */ /* Evolvotron 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 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron 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 Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Application code for evolvotron executable (contains "main"). */ /*! \mainpage Evolvotron : image evolver \author Tim Day \section introduction Introduction "Evolvotron" is an interactive tool for producing "generative art". Images are generated from function trees, which are then mutated and evolved through a process of user selection. \todo For new features to be added, see the TODO file. */ #include "evolvotron_main.h" #include "platform_specific.h" #include //! Application code int main(int argc,char* argv[]) { QApplication app(argc,argv); // General options bool autocool; bool fullscreen; std::string grid; bool help; bool jitter; bool menuhide; uint multisample; bool spheremap; std::vector startup; bool startup_shuffle; boost::program_options::options_description options_desc("General options"); { using namespace boost::program_options; options_desc.add_options() ("autocool,a" ,bool_switch(&autocool) ,"Enable autocooling") ("fullscreen,F" ,bool_switch(&fullscreen) ,"Fullscreen window") ("grid,g" ,value(&grid)->default_value("6x5"),"Columns x rows in image grid") ("help,h" ,bool_switch(&help) ,"Print command-line options help message and exit") ("jitter,j" ,bool_switch(&jitter) ,"Enable rendering jitter") ("multisample,m",value(&multisample)->default_value(1) ,"Multisampling grid (NxN)") ("menuhide,M" ,bool_switch(&menuhide) ,"Hide menus") ("spheremap,p" ,bool_switch(&spheremap) ,"Generate spheremaps") ("startup,S" ,value >(&startup) ,"Startup function (multiples allowed, or positional)") ("shuffle,U" ,bool_switch(&startup_shuffle) ,"Shuffle startup functions") ; } // Animation options int framerate; int frames; bool linear; boost::program_options::options_description animation_options_desc("Animation options"); { using namespace boost::program_options; animation_options_desc.add_options() ("frames,f" ,value(&frames)->default_value(1) ,"Frames in an animation") ("linear,l" ,bool_switch(&linear) ,"Sweep z linearly in animations") ("fps,s" ,value(&framerate)->default_value(8) ,"Animation speed (frames-per-second)") ; } // Advanced options bool debug; bool enlargement_threadpool; std::string favourite; int niceness_enlargement; int niceness_grid; uint threads; bool unwrapped; bool verbose; boost::program_options::options_description advanced_options_desc("Advanced options"); { using namespace boost::program_options; advanced_options_desc.add_options() ("debug,D" ,bool_switch(&debug) ,"Enable function debug mode") ("enlargement-threadpool,E",bool_switch(&enlargement_threadpool) ,"Enlargements computed using a separate threadpool") ("nice,n" ,value(&niceness_grid)->default_value(4) ,"Niceness of compute threads for image grid") ("Nice,N" ,value(&niceness_enlargement)->default_value(8) ,"Niceness of compute threads for enlargements (if separate pool)") ("threads,t" ,value(&threads)->default_value(get_number_of_processors()) ,"Number of threads in a thread pool") ("unwrapped,u" ,bool_switch(&unwrapped) ,"Don't wrap favourite function") ("verbose,v" ,bool_switch(&verbose) ,"Log some details to stderr") ("favourite,x" ,value(&favourite) ,"Favourite function") ; } boost::program_options::positional_options_description positional_options_desc; positional_options_desc.add("startup",-1); options_desc.add(animation_options_desc); options_desc.add(advanced_options_desc); boost::program_options::variables_map options; boost::program_options::store( boost::program_options::command_line_parser( argc,argv ).options( options_desc ).positional( positional_options_desc ).run() ,options ); boost::program_options::notify(options); if (help) { std::cerr << options_desc; return 0; } if (verbose) std::clog.rdbuf(std::cerr.rdbuf()); else std::clog.rdbuf(sink_ostream.rdbuf()); //! \todo Could be done better maybe (set 'x' as input separator) const std::string::size_type p=grid.find("x"); if (p==std::string::npos || p==0 || p==grid.size()-1) { std::cerr << "--grid option argument isn't in x format\n"; return 1; } else { grid[p]=' '; } int cols=6; int rows=5; std::stringstream(grid) >> cols >> rows; if (cols*rows<2) { std::cerr << "Must be at least 2 display grid cells\n"; return 1; } if (frames<1) { std::cerr << "Must specify at least 1 frame\n"; return 1; } if (framerate<1) { std::cerr << "Must specify framerate of at least 1\n"; return 1; } std::clog << "Evolvotron version " APP_BUILD " starting with " << cols << " by " << rows << " display cells and " << threads << " compute threads per farm (niceness " << niceness_grid << " and " << niceness_enlargement << ")\n"; if (!startup.empty()) { std::clog << "Startup functions to be loaded: "; for (size_t i=0;i0) std::clog << ", "; std::clog << startup[i]; } std::clog << "\n"; } app.setOrganizationName("Evolvotron"); app.setApplicationName("Evolvotron"); #ifdef __linux { QIcon icon("/usr/share/icons/hicolor/48x48/apps/evolvotron.png"); app.setWindowIcon(icon); } #endif EvolvotronMain*const main_widget=new EvolvotronMain ( 0, QSize(cols,rows), frames, framerate, threads, enlargement_threadpool, niceness_grid, niceness_enlargement, fullscreen, menuhide, autocool, jitter, multisample, debug, linear, spheremap, startup, startup_shuffle ); main_widget->mutation_parameters().function_registry().status(std::clog); if (!favourite.empty()) { std::clog << "Selected specific function: " << favourite << (unwrapped ? " (unwrapped)" : " (wrapped)") << "\n"; if (!main_widget->favourite_function(favourite)) { std::cerr << "Unrecognised function name specified for -x/-X option\n"; return 1; } main_widget->favourite_function_unwrapped(unwrapped); } main_widget->show(); // NB Do this here rather than in constructor so that compute threads aren't being fired off during general GUI set-up std::clog << "Resetting main widget...\n"; main_widget->reset_cold(); // NB No need to worry about deleting EvolvotronMain... QApplication seems to do it for us. std::clog << "Commencing main loop...\n"; return app.exec(); std::clog << "...returned from main loop\n"; return 0; } evolvotron-0.8.3/evolvotron.html0000644000175000017500000007271515230700302015512 0ustar karlkarl Evolvotron User Manual

Evolvotron User Manual

Evolvotron is interactive "generative art" software to evolve images/textures/patterns through an iterative process of random mutation and user-selection driven evolution.

On starting the application, a grid of images is displayed. Resize or maximise the application if you like, but the more pixels have to be calculated, the slower it will be. (For the default 2D image mode, you will need a fast machine or patience. For the optional animation mode, you will need both.)

Simply repeat the following until bored:

  • Click (singleclick) on an image you like to spawn the next generation of its mutant offspring.
  • Wait until variations on it are regenerated in sufficient detail that you can decide which one you like best again.

IMPORTANT: Initially you should select images with some sort of variation. If you select a uniform image, you may get stuck in a degenerate zone with little to mutate and therefore little chance of escape to more interesting images. You can always reset/restart from the "File" menu (the difference is that "reset" also resets the mutation parameters to their default values). Selecting one of the "warp" options from a context menu (right-click on an image) can also help by introducing an additional opportunity for mutation on subsequent spawns.

Note that various spirals, grids and tiles, although complex looking, are actually implemented by a single function node and may leave you stuck too.

Command Line Options

The following are equivalent:

  • evolvotron --grid 12x8
  • evolvotron --grid=12x8
  • evolvotron -g 12x8

General Options

  • -a, --autocool
    Enable autocooling by default, and cause resets of mutation parameters to re-enable autocooling if it was disabled.

  • -F, --fullscreen
    Start in "fullscreen" mode (NB for Qt on X11 this means a screen-filling borderless/undecorated window is used; it's not simply maximising the window, and it's not the sort of framebuffer hijacking used by SDL games). The Qt documentation claims some window managers may not be entirely cooperative with this (in which case sorry, you're on your own). evolvotron actions which bring up dialog boxes (e.g save) seem to generally behave fairly sensibly but child windows (e.g enlargements or dialogs) can show some "interesting" behaviour. Fullscreen mode can be toggled within the application using CTRL-F key. The Esc key will also exit it.

  • -g, --grid colsxrows
    Sets size of the grid of image display cells in the main application area (defaults to 5x6)

  • -h, --help
    Print summary of command line options and exit.

  • -j, --jitter
    Enable sample jittering. Samples will be made at a random position within a pixel instead of on a regular grid, providing some antialiasing.

  • -m, --multisample multisample grid
    Enables additional antialiasing passes. Specifying 2 or 3 will provide an additional pass with 2x2 or 3x3 samples per pixel. Specifying 4 (or higher) will provide a 2x2 and a final 4x4 pass. Specifying 1 provides the default behaviour of one sample per pixel. For best rendering quality also specify -j.

  • -M, --menuhide
    Start with menu and status bar hidden. Nice with --fullscreen. Hiding can be toggled within the application using CTRL-M. The Esc key will also bring them back.

  • -p, --spheremap
    Images are produced by sampling the underlying 3D function on the latitude-longitude grid of a sphere. The resulting images should be usable as spheremaps/spherical environment maps. Animations vary the radius of the sphere. NB when in spheremap mode, middle mouse button adjustments do not yet behave like you'd expect.

  • -S, --startup function_filename
    Specify a function filename (evolvotron's XML format) to load on startup (or reset). The option can be provided multiple times, and this is also the interpretation of any positional arguments. Startup functions are placed in the grid from left to right, top to bottom.

  • -U, --shuffle
    Use in conjunction with -S / --startup options, to display the specified functions in random order, both on application startup and on each reset of the application.

Animation Options

  • -f, --frames frames
    Number of frames in animations (defaults to 1 i.e no animation)

  • -l, --linear
    Vary z linearly with time rather than sinusoidally. Sinusoidal variation generally looks better when animations are "bounced" forwards and backwards, but this option is useful when generating slices to use as volumetric textures.

  • -s, --fps framerate
    Rate at which frames are displayed per second (integer). (Defaults to 8).

Power-user & Debug Options

Note that the usual Qt/X11 options (for example, -geometry widthxheight option to set on-screen size in pixels) are processed and removed before evolvotron options are checked.

  • -D, --debug
    Puts the certain aspects of the app into a more debug oriented mode. Currently (ie this may change) it simply changes function weightings so virtually all function nodes are FunctionNoiseOneChannel. By itself this is a pretty pointless thing to do, but in conjunction with the -X options it's useful for examining the behaviour of specific functions.

  • -E, --enlargement-threadpool
    Use a separate thread pool for computing enlargements. Using this option ensures computation of enlargements continue to make some progress even while the main grid is being actively worked on. However, this will be at the expense of main grid rendering performance. Without this option, enlargements' final high-resolution renderings are invariably lower priority than computation for images in the main grid. See also the -N option to control the priority of threads in this pool.

  • -n, --nice niceness
    Sets additional niceness (relative to the main application thread) of the compute (rendering) thread(s). It's useful to run compute threads at a slightly lower priority ("nice 4" is the default without this option) than the main (GUI) part of the program (but note that this means other normal/lowish priority tasks running on your machine may slow evolvotron down a bit more than expected).

  • -N, --Nice enlargement niceness
    Sets additional niceness (relative to the main application thread) of the compute thread(s) computing enlargements (default value is 8). Only effective in conjunction with -E option.

  • -t, --threads threads
    Sets number of compute threads. If this is not specified, then as many compute threads are created as there are processors on the system (unless this cannot be discovered in which case only a single compute thread is created). Non-linux builds will likely not include code to determine processor count (suitable patches gratefully received).

  • -u, --unwrapped
    Modifies -F behaviour so that the specified "favourite" function is NOT wrapped by space/colour transforms. NB For functions without leaf nodes or parameters (e.g FunctionSphericalToCartesian) this doesn't leave any scope for variation or future mutation. Function name recognition is case sensitive. Example: evolvotron -F FunctionKaleidoscope -u

  • -v, --verbose
    Verbose mode, writes various things to application stderr. This is primarily intended to assist debugging. This option used to be useful for getting a list of supported function names for use with the -F option, but those can also be inspected via the Settings dialogs.

  • -x, --favourite functionname
    Force a specific "favourite" function type to be used at the top level of all function trees. The specified function is still wrapped by spatial and colour warping functions which may disguise it considerably. A list of all the function names understood by evolvotron is output during app startup when the -v option is specified. Function name recognition is case sensitive. Example: evolvotron -F FunctionSpiralLinear

Mouse Control

Left-click

A left-click on an image in the main window can either mutate it or toggle its lock. The lock is toggled when clicking in the upper right corner. Clicking elsewhere spawns the mutant offspring of that image to all the other (non-locked) displays in the grid.

Right-click Context Menu

Right clicking on an image gets you a few more options:

  • "Respawn" regenerates just the current image from whatever it was spawned from (and using recolour or warp, if that's what was used to produce it). The main use of this is to make your grid of images look nice for screendumps, by regenerating any which aren't up to scratch. NB May not work as expected after an "undo".

  • "Spawn" is the same as clicking an image. It generates mutated images to all unlocked images in the grid.

  • "Recolour" to produce different coloured variants of the selected image

  • "Warp"'s sub-options produce variants of the image which have been zoomed/rotated/panned.

  • "Lock" to prevent an image from being overwritten by spawns from other images (select again to toggle).

  • "Enlarge" to produce a blow-up of the image in a single window. Submenu items select either a freely resizable window or a scrollable view of a fixed size image. If the application is running in fullscreen mode (NB this is NOT the same as a simply "maximised" window) then the enlarged image will also be fullscreen (the "Resizeable" mode is probably what you want in this case as the image will automatically be rendered at the correct resolution).

  • "Save image" to save the image in a file (.ppm or .png). You generally want to save an enlarged image: if you save a small image from the grid, the size you see on the screen is the size you get in the file. Save isn't allowed until the full resolution image has been generated; if you try to save too early a dialog box will be displayed telling you to try again later.

  • "Save function" to store the function to an XML file.

  • "Load function" to load a stored function from an XML file. NB if the file was saved from a different version numbered evolvotron, a warning message will be generated. Save/load of functions is an experimental feature and you should not count on future versions of evolvotron being able to load files saved from old versions, or producing the same image from a loaded function. Attempting to load functions from later versions into earlier versions is even less likely to succeed.

  • "Simplify" prunes the function tree of redundant branches where possible (the same action can be applied to all images from the main "Edit" menu). This doesn't change the appearance of the image, but may make it recompute faster.

  • "Properties" brings up a dialog box containing some information about the image (e.g the number of function nodes it contains).

Middle Mouse Button

[NB This feature will probably only be of practical use to those with high-end machines].

You can use the middle mouse button to drag-adjust individual images. This is useful for "final composition" type tweaks, e.g centering an image's most interesting feature, or just for satisfying your curiosity about what's off the edge of the image.

It also works on enlarged images, although it's virtually unusable without a bit of practice on smaller, faster ones (just boldly make the adjustment you want, release the button... and wait).

Changes made can be rolled-back on the main Edit/Undo menu item, one drag-action at a time.

An unmodified middle-mouse drag pans the image around following the mouse motion.

A SHIFT-middle drag zooms the image in and out with scaling proportional to the distance from the centre of the image. Beware of generating huge zooms by clicking too near the centre of the image.

An ALT-SHIFT-middle drag is similar but anisotropic: the scaling may be different in X and Y. Warning: this technique is very sensitive and can be quite tricky to use! In particular, if you initially click near the centre axes of the image the zoom factor can be HUGE, so the best way to start using this is to click about halfway on a diagonal between the image centre and a corner and gently move in and out radially. Dragging from one side of the image to the other flips it over (the degenerate case of infinite zoom at the centre is handled cleanly I think). If it all goes horribly wrong, undo and try again.

A CTRL-middle drag rotates the image about its centre.

A CTRL-ALT-middle drag shears the image (the best way to see what this does is to click in the corner of an image and move the mouse horizontally or vertically).

Mouse Wheel

Scrolling the mouse wheel zooms the image in and out.

Keyboard Control

There are some keyboard shortcuts.

Main Window

  • "r"/"t"/"x" perform various starts of reset/restart.

  • "CTRL-Q" quits the application.

  • "u" (and also CTRL-Z) does an undo.

  • "CTRL-F": full-screen mode. See also "-F" command line option. Fullscreen mode propagates to enlarged image display windows. NB The application may completely disappear from the screen for a brief interval while switching mode.

  • "CTRL-M": hides status and menu-bar hiding, which can be nice when in full-screen or window-maximised mode. See also "-M" command line option. Also note that while the menu bar is hidden, most of these keyboard shortcuts won't function as they're tied to the menu system.

  • Esc: exits full-screen and/or menu-hiding mode, putting the application into its normal default state.

Enlargement Windows

The image display windows created by selecting "Enlarge" from a context menu also have a couple of keyboard operations:

  • "f" : [NB only available with fullscreen build option] toggles full-screen mode. When returning to normal mode, if the main app window was fullscreen then it will also drop back to normal mode.

  • Esc : [NB only available with fullscreen build option] completely closes a fullscreen-mode enlargement window.

Gui Elements

Main Menu Bar

  • File menu: Items to restart, reset and quit the application. The difference between restart and reset is that reset sets the mutation parameters back the their default values. The "randomize function weights" version of restart scrambles the relative probability of the various function types (if you think evolvotron just keeps generating the same kinds of images give it a try). The "restart with specific function" item duplicates the functionality of the "-x" and "-X" command-line options.
  • Edit menu: "Undo" lets you undo certain actions: e.g spawn, middle-button adjustment, simplification and lock/unlock. There is a large but limited number of levels of undo. "Simplify" is of curiosity value only: it prunes redundant branches from images ("junk DNA"); this may help them recompute faster but at the cost of there being less mutatable material.
  • Settings menu: "Mutations" brings up a dialog to modify the amount of change spawned images are subject to. (See "advanced usage" below.) "Functions" brings up a dialog to modify the relative probability of functions being used. By default all functions are equally likely except for iterative functions and fractals, which are almost but not completely suppressed. But if you think there are too many spirals or grids (or not enough fractals) then this is the place to adjust the frequency with which they appear. If the software was built with the fullscreen option, that can also be controlled from this menu. "Favourite" brings up a dialog which allows you to select a specific function type to always be used as the root node of any new functions. The function can be wrapped by some other random stuff, or unwrapped. See also the -X and -x command line options.
  • Help menu: Items to bring up documentation, and the usual "About" box (which includes the license).

Status Bar

An area on the status bar shows how many compute "tasks" are outstanding (or "Ready" when there are none). When two task totals are reported, the first is for the main grid and the second for any enlargements being computed. Each "task" is the recomputation of an image at some resolution. Tasks are prioritised by their number of pixels (small image implies higher priority). This is why, if the main grid is still recomputing, recalculations of enlargements will appear to freeze after they have reached a certain resolution, at least until other lower resolution tasks have completed.

The status bar also provides some control over the "autocool" mechanism which reduces mutation strength with time. See the advanced usage section below.

Tips

  • Don't start a session with any preconceived ideas about the kind of image you want to get out of it. You will be disappointed.
  • I get the best results when I click the image which most immediately catches my eye as they start appearing. If you stop to think about it too much then things seem to go downhill.
  • If you seem to be just getting the same old spirals and grids all the time, stop clicking on spirals and grids! (The same goes for random mush).
  • Don't get too hung up on using the warp and middle-mouse drag adjustments every iteration... use those tools for final polishing of your masterpiece.
  • You can quickly cycle through a lot of initial images (until you find one with real potential) by bashing on CTRL-R to repeatedly restart.
  • To add variety to an image's mutations, nudge it with a small middle-mouse drag. This introduces a top level transform, and therefore more parameters to be varied.
  • Enlargements take a long time to complete their final high-resolution rendering pass (especially with multisampling enabled). Most convenient practice seems to be to go away and leave them to complete, then come back and save them later. Continuing to click away on the main grid effectively starves them of CPU, unless the -E command-line option is used.

Animation

As of version 0.2.0 evolvotron contains some experimental support for generation of animations (although so far the results have been pretty disappointing IMHO, but it's still early days).

NB THIS IS EVEN MORE COMPUTATIONALLY AND MEMORY INTENSIVE THAN THE STATIC IMAGE MODE.

Simply supply a -f frames command line option and evolvotron will generate animated sequences with the specified number of frames. These will be displayed at the frame rate specified by the optional -s framerate option (default 8). So "evolvotron -s 24" will generate 3 second long animations. Animations reverse direction at each end to avoid a sudden jump.

If you save an animation as PPM or PNG, multiple files will be saved with .fnnnnnn (where nnnnnn is the zero-filled frame number) inserted in each filename before the filetype qualifier.

For example, if you enter foo.ppm as the filename to save, files foo.f000000.ppm, foo.f000001.ppm... will be saved. If you have the ImageMagick tools you can convert these to an animated GIF playing at approx. 8 frames per second with:

convert -delay 12 foo.f??????.ppm foo.gif

Advanced Usage

Evolvotron's idea of an image is a function which converts XYZ co-ordinates to an RGB colour (however we can only display a 2D plane for now so the input Z is fixed to zero, or varied with time when animating).

The image functions are constructed from trees of function nodes. (In the mathematical expression 1+(2*x) the "+" and the "*" would be function nodes.) Evolvotron's functions tend to correspond to geometric or colour-space operations or anything else which can be applied to a 3D vector.

By mutating the structure of the function tree (adding random branches, for example) and the values of the constant embedded within it, the image can be changed.

The mutation parameters are under control from the dialogs accessible via the Settings menu, and the "autocool" mechanism exposed in the status bar also has some influence.

There are two kinds of mutation: perturbations to the magnitude of constants, and structural mutations which re-arrange the function tree of an image. Four types of structural mutations are currently implemented:

  • replacement of a function branch by a new random stub (a "Glitch" mutation).
  • a random shuffle of a node's sub-nodes
  • insertion of random nodes between a node and it's sub-nodes
  • the substitution of a node with one of a different type, with sub-nodes unaffected where possible).

The probability (per function node) of these mutations is controlled from spinboxes on the "Mutation Parameters" dialog (expressed as chances-in-a-hundred), as is the size of perturbations to constants.

It is useful to think of the perturbations to constant parameters as being a thermal effect (hence the "heat" and "cool" buttons), while structural alterations are more drastic and are caused by high energy gamma rays or something (hence "irradiate" and "shield" buttons to adjust the probability of structural mutations).

So why would you want to change the mutation parameters from the initial defaults ? Basically, if you're getting too much variation in spawned images (this tends to happen after many generations of images, by which time the function trees have grown quite large and therefore are experiencing a lot of mutations) then cool and/or shield. If all the images look too similar, heat and/or irradiate.

The "autocool" mechanism (enabled from the statusbar or mutation parameters dialog) automatically reduces the strength of mutations from the base values with successive generations. The cooling can be cancelled by disabling autocooling or pressing the "Reheat" button to zero the number of generations counted for cooling. The effect of the cooling is a compound halving of the mutation strength after some number of generations (this number is the "half-life" controllable from the mutation parameters dialog). Note that if autocooling is enabled then eventually, after a number of iterations more than many multiples of the half-life has passes, spawned images will differ very little from their parents (hence the need for "reheat").

There is also a dialog accessible from "Functions..." on the "Settings" menu. This allows control over the relative proportions in which functions occur. There is a tab showing the relative weighting of all functions (log-2 scale: each tick halves the probability of the function occurring), and additional tabs for various classifications of function for quicker access. The "Randomize" button on each tab assigns random weightings and helps increase the uniqueness of your session.

The "Functions" dialog also has a "Dilution" tab which allows the average function-tree branching ratio to be controlled (by changing the proportion of trivial zero-branch functions added): note that using a high branching ratio results in very complex images which will take a long time to compute, while reducing the ratio results in simple, boring images.

3 types of function node are considered fundamental: constant nodes (which return a constant), identity nodes (which return their position argument) and transform nodes (which transform their position argument by random parameters). On the "Dilution" tab of the "Functions" dialog there are two slider controls to affect things related to these:

  • "proportion constant" controls the proportion of diluting fundamental nodes which are constants. Changing this from its default value of 0.5 doesn't actually seem to have much effect.
  • "proportion transforms" sets the proportion of non-constant nodes diluting which are transforms (as opposed to identity nodes). The main effect of this is that images are less commonly obviously centred on the origin or aligned with the axes. I think this is a good thing, so the value is at 1.0 by default.

Other Executables

This release also builds some other command-line driven (non-GUI, non-interactive) utilities. Consult the man pages for full details.

evolvotron_render reads a XML function description from its standard input and renders it to the file specified.

evolvotron_mutate reads an XML function description from its standard input and outputs a mutated version. A command line option allows the "genesis" situation of creating a random function description with no input.

Examples

Evolving and mutating on the command line:

evolvotron_mutate -g | tee fn.xml | evolvotron_render /tmp/xxx.ppm ; display /tmp/xxx.ppm

cat fn.xml | evolvotron_mutate | evolvotron_render -j -m 4 /tmp/xxx.ppm ; display /tmp/xxx.ppm

Animating a function ani.xml saved from evolvotron in animation mode:

cat ani.xml | evolvotron_render -f 100 -v -s 256 256 ani.ppm ; animate ani.f??????.ppm

Future Developments

Please check the TODO file first before you send me suggestions!

Please don't ask me to port evolvotron to proprietary platforms. You are of course Free under the terms of the GPL to do so yourself, but please read http://www.fefe.de/nowindows/ first.

Thanks

To those who have contributed feedback, suggestions and patches:

  • Dmitry Kirsanov
  • Jonathan Melhuish
  • Karl Robillard
  • Linc Davis
  • Paolo Greppi
  • Marcin Wojtczuk
  • Michael Sterrett
  • Massimiliano Guastafierro
  • Goetz Waschk
  • Forrest Walter
  • "chr_bl" at web.de

And to the anonymous Linspire reviewer who perhaps came up with the best summary of evolvotron yet: "Fascinating. Utterly pointless, but fascinating."

The friezegroups wouldn't have been possible without http://michaelshepperd.tripod.com/resources/groups.html

Thanks to www.di.fm, www.somafm.com and Trance4Ever for music to code to.

Thanks especially to a SIGGRAPH conference panel many years ago (likely including Karl Sims, the pioneer in this area) who first got me interested in this stuff.

Why ?

I have always admired those who have the skill to wield a pen or paintbrush and fill a sheet of paper or a canvas with some striking image from their imagination. Unfortunately I lack the patience to learn such skills, and probably the necessary manual dexterity and imagination too.

Evolvotron, and several predecessors developed on and off over a decade since I first came across the idea, are an attempt to compensate for this using the skills I do have i.e some mathematical sensibility and the ability to write working code (well, sometimes). If you like an image it produces, then as far as I'm concerned that's as satisfying a result as if you liked something I'd drawn myself.

Tim Day evolvotron-0.8.3/dist/0000755000175000017500000000000015230700302013336 5ustar karlkarlevolvotron-0.8.3/dist/icon-48.png0000644000175000017500000001000315230700302015217 0ustar karlkarl‰PNG  IHDR00Wù‡ÊIDATxlÓSt+}ßÇákŠ´M4NÝ­×¶mÛ¶mëøµmÛ¶­ÛØww“6iRÄžgºvV׃ûà»~Ç×|æ„a ñ{ot4Ig?m”Î¿ç •ßënæS×ñ|ür­è|¹ ® ¦¨*ãd¾ît¸î3ë"š&XEIV£eãì­Î]ûvÕTf5ùá©­vMòêÔÆÅ™µfÝòe‹pn–ÎÊóa¶|ÕÙªt/SÛñ�?¬-íüÌ—xÇÀ-àì�ßâ£Vºíï &ãr¸3MfŒ39Ãt^/UÐN\m4WKêŠN£�È9ªÓ%}&]tc›H²œbë #HÇ¡d^SÔd#Èf‰·NÅÎÏ,·¯„««¦¹¢a®¬Ÿ­¸Îlk&·ž®î~þgxßß¿üíÕw|äf¿õ³ñN3¶~Ýk_Xéµ³™Ùú†I*k˜)èG�N2‚Ä Z±¢FPRSRUp,éÑtY³ÏèÕ!KH År’­±¹â@ÝžjTä1dë:*r‰ «Í3KÃ�ùfÊ(_6ˆ íq‘ÞîÕ×w?âãƒÿÃà+Ã' šÿ’Ÿ7 ÙISzÔ’ì5E×MÆò G˜n¦EE Ò$u)i­E�¥Dѱ”ãÉŠÆ�Q‹½R‘+Ir7�Õ™;AÛ�SDyAzUĿũõfÍêe“ 0É òÝ­ŠËôΣóÄÎ[¯7›GeiôµmeŠÎåÃ¦Üø\zØ”ì6%ÚçÖ¯ÏÅ:W‚é$ª7Êäõ3ŨHÑU¢AJêäTÙ£[Ȳó>ã.Ú¯TdI¤ˆ%)%¸³2qäÂ�š]d\•ëTe®jQ�µóšèCš%Ó†7ˆì¶«ÌöWªá¿®%¼yzƒÒê\%Úa4•D˜ù¹ìè\fpn³s.AÖÚMË7ickF©¬~:‚¤J.#H3v)‹Šˆ ^ “ŽÇK.zL]L°�Ò$6Ù]çîrß‘†}U;ó¨é *zR—UñE�03Ê–õr•¿ üqx.&/�,Ѷ’”Wfvôm»Tvþ3mØ6¤»&ª²qÝëwÌ—WD½tI;Ut/9�•�%'*É{8�;®»„\ Š’ȱ”%›à(6w'¸v¨fOÕö¤ªÐ=‘¹ù­ZUëÍ3Álb¼U<|W*`L±ÁR…ÄÅ2;±±]mMe ÅyCnaz ÉN]âêÒ6_ZŽ 9�r�,¹ˆ õ•²Se'Ñ^’õpsÚgÍ?¢Ž2`G¬WØÙàn0tgQc7ªQrµõ[ü[=®Qô0Lzi²äòyæ?„ýÅB\a‹¥7$—£•¨†KGªöœ¨Œ£�¨ÆeUTc¼~u>÷¹�á îco±â¢J ñˆ O°½HÛÃ1žÅó8'¾IåÍú¼×¥×{‡†;¹º#Ó«K_�Ù¼nXžŽ ãiítÙåM�(çÙm�’ýæ„ÚO¼î¾ÒGìá Â’jÀugmñ¸]C¸¶æR¦s@\Ä/,‚¬.~�5/@Fc(â8¥jF3æF…;Œ%Æ›RÑH6ÍfGÛ6ÆPeÌtM€-Þzoóy«Çómé %êí‰6Y÷ÕwZeA(©dHgƒã”‹[ñ™ª¤†mÀ”]BÃRº!Çö8aRY£ ¬y³`=-F<´+,ò)h>;åø˜ZŽÙÈ;?(%íÄX•Ñ ‰_;<øMÊ{û#é|U�åä‰DÖžÓГÿä†9>?�÷ReS`JØ_Aÿàs£ÀfüÑÞu‚/4ºëØ?C€ð•ÎuXßvž ßY.„ÀbpAì{ùþù§Î„ø<Êšk˜çôý¨ßŽ®Lˆæûü.fÄïÊÛiGg-Aþ¸.?Õ?!K/Û`ögç�ÏóÎØc�9_Z³åÒ§QKF/†c‡&Îì�:s£‰Ì9ÌY飸¦£„H6°ÊéÖg�·¦ LÏU¹Pm°ä~¨¾«ö¶;Ž™|¶æÎ�r¬Å†{CLÆÜ˵57K@@»B@1t$ňùçjì5|—Û›…ÐaDk_ÓšÅ(4çWW•± +Ç~ýœv:(Sš3ƒ¹dښﲉ¡q*?ù¤!úu…`¬3Q(cɶ±:8‘k˵b=—rúÍ ç¡Ã‰3×áüŦ ÐÐ.R8Vþ]`Ðöðw§#ÌRµìKó%·…ÚË �ÕØãl Û-œ+‘5b,\^ªMÚ„U.ÕwC€šæ" Çœ¶«K 3Éв…ÖŽWT¯«f1HMµwÜ?ý—³àS�;Šýžy* Þ §›V§Y5Y±”XF¬q–L©{DÝ•z] ƒ>óN�å�ÀžNC²OH;œ›Aû&øÕ40/ùó¦ù„þ¯Uâëæ4œ}= �€¡›ÎM‡JTJ݀ܠSý©¬P¥Êfí×YËìTPM¹'â¥Ybþ6 Íp*~àšÿÿù¿ÿy`ˆž¥(7IEND®B`‚evolvotron-0.8.3/dist/icon-128.png0000644000175000017500000003323515230700302015312 0ustar karlkarl‰PNG  IHDR€€Ã>aË6dIDATxœ™´$KÖ…#Ò™¿mŽmÛ¶mÛ¶mcqlÛ¶m»ß­JgÌŽŒùNtÝZ·û½5ßÚÕýÐUYßìs"®V'ù×÷¾tíÝ1ÍÏ.>¤Å¹‡4ÿ�>-þ®Oò¨OŠìµq¡º¤PmT¨F…Ôd�«•Ê�R©•Qj="A=(5Õƒãóøß³L@ƒ¤ 2$Áÿ�%r× ”Q;j@¶`�×5Y« Y!K‹©U1­U1Ô`­²®VY¿V©M�XÚZŰÙÔ*ê!uÛÐ4JM“RIªLQÌL¹§T#s°dåªÏ«c}V™.-�uYõ‹&­¾>ÝÄÕÇj]}ã¦úZæd¾Ï Œ9üßÿÕ»Îó?S–ß|Jóë!ÿ¨1Í@rÕg…$~ %ˆ‰Þ"‚ÈÕLŽ×‰¬ñl'BLøåoÏ()I!F`7vìi…/¯)ÂEØõ"Pˆ�4¶"ôÈÞ �©ÍÖÊ@ HÔ lv�}øÊd™�_ü"eòÊŠ zfÚt¦±"¬£�Wâݼî–ê*<ô ×úäøýËÿé¯MšÞÓ¤ÙL–ÿ5PÞ$D@‚Y€×ƒM+rHlZ Hœ«vn…Rµ‹öÑå|ŒEÀjΩ� Á T ¦o÷WtD�(q"ì ÷bß–4¾ –f`#°|#ˆ�A€üDEhl#Ô°o<ÒJå9$ eÈ e°‰&P=²K�MJâêÛk½ó¼³WÞN]n8Íüöu§»8Ì|¶ú3iÔ”±ÿršÍ–âËGæ!��0d€m€„¹ltØé()C b¼F˜SEh6Çà ˆ"!CòÄŠÀFˆ¤›£°� ˜ÜXØÚ”!jÖ*æXˆØ�Á}°$m ÆBaÇ�¡§-€gší¨&q"ÔQõHp÷[©+û¤øÙG/u›¨oŸ¡û®Œºv®(Ý[UQ¤Ì,EÍ0f�¯Ù § H�‘h$¡²r$ǃb< Àô'Ø è£÷•)¥‘¹ ¾ÀFplì ňf €mÊ(Áœ!©&£”}®áXàHðX�ÁH qõSì·¼™ºú{NX€o}ûf÷Múîñ@Ç}«¢¾ÈÌ"Pˆ¡Ÿ¦‰c7»‚V BˆaM Æ’�àÆC£(@)[éEÐÁµÂzp º¹'†Í…Q6Â6!4Ø&ÂGÃÒ .Ù`^ñî'AÁEqi…2cAŠÀý@kÑ¡€YåDÑ�ÅJ€d¬Ö�àÆêÚ¯>R€OþæÁ·I†ö@'ø¢‘*îÑœ�¡§ ]ëZaæÿšÁ6;Í2àMŠ1fl„YŽÂÑ ÆEàX��PƒU°4¦�¡fS)ʼn‹��DŒ†eG�£aØhÙ–Ò»#¸6`#¸‘`3‘"ŒÊàÆö1HÀÓBpJ Ü  ˆ•mpµè¼o«oê^tÑllÞ•�m‘â‹ H/C˜K;X @äe˜F1"œcØ ÛEH�• ™ÇE(VL'A)Dˆ€ È�À…ñ´‹ GÂöe1¡a#TrO0v4p? ZÀE‘�±xtÜ“0+µH±ˆFõ2°,ʱÖËn0ñiôK"CyJhÝH¸ÅEÿòA/×ßšÝ2V_¨"õ¿¥ÆÂEQŒ…�ô+Jü%Ò"e¨!A ¦É�ºÄ‚8Ûl‚[iõ-óv¼é+,•F¢ØÉPàµkáµFª‰­Ð!›­2È}¡˜E N±/Ô‹ IçEhãÁhw§0r<Œ^‚PÑ”`^·�…ÕB±(:šÞÿÐi iÀ$.Œò­"ðj™ð'�b,'@ФÁmÝHà~ N ²¸ F}çFkžøSÅjõ~ó5<ƒ3ª¾qÿ!"@)"�Q†*&Ú�ÿÜ,CE !(ÁÒpDÌí DÈ'AÒ¹v`#P`»Yã9Ûù–c –Á-ˆÝœÜ@­·ŽAbˆ@ ¶-ЇÝ#ü¤|f(@%o%<6nŒ… _|+ÛPfiVNŽ„™nå$�c¡áXð?SÐú°&x¿V¯7¿R­úûe±)Á_�~�Ä02_Z�D€#‚Ë#E�2B@$È02ûZ´Eè˜\£�?7‡Õ#EØX9:¶B›ˆ6Ðòþ€ÈÝ`A³ Âý “-@~ öA&N »ü½òp2°KöÝX`4b?`wl¹Jœ—Dm GÂÒ_Õê­¦ÃK—*[�šKNBþüøkP±Êb¥’~Šà#bK+Š`�ÒI€¬—=!¥H×lî 7ŽƒQ´� ”À_$�Æ�~ñµ”`s?ÇF'CÝr£Øñ×_ä3üK°4Xƒ‘"ü­$ò6q â’È6\WáX0v,8 „l— ÇO ËϸþT«3©–‚ol ¤æÍ„ÿ þÞ} £#ÓÜ"Ñ z9RŠ`3L0ÕVއz–€"P0‹@!¤ EÈ­b?ÈJ^$q,Ø/_4B­È¦l„/ÇÆS¤ÿ©£lƒ ü| ìñ‹Þ%ŸÝ1Ðò9ÿ#)B²„m oÙ»a³ 8ü’Ø¡¿œ”À5Eëù”`âùâèWZ=T ÉipGVà ±=߸߀ÿþ ­û‹Œ(@)l+ìˆV�BHr›f�@î A+ÌÔ®Z·ì(c��™“ ¼H"¥¸Qän ÛÛ  NŽ…ÍÓÂùœþ’쑘mð'>¿Œÿ'úÊÂ1ëÛ`_Þð&‘ 7Û 4`<2ó)´ °I ¸üA«›A€}VV)�¤4¼å›_3„=�þðßø ÿ‡ bTh‹�©È²+´jGÈ Ô®–ñà„àž€¤35D€"‚ʸK%,:ܤ¥¼DâX r,P$ð—I‰X�¼V6àÓà�lÊ=âE¨ÀÈgöG¦¡gC1"„?.&<),mPS‚!Á*<)ôò¤Ø)X.�ÚzÐêNà‡b¾oETV/ZaM|C£ÿ��§Ç¿zFüò¿(ÄòŸñšãaYk¦£ð�`e‘\)‚—´V'÷£Ô||2ŠÀý`‘ÙQ‚–ÔE ‡�… Dm0 üüO÷'J°Ù|^"øpfðŸîYǶ9“ãwƒI޹$R¤X%XqA”#MPþ̘öÁJMßä’R² ª-ìˆV0¢B€ø€Bã!¤gRª<;žÇ™>è^,�@Œ!DÁײÄž@ �Ü(ƒ ZŸz­Éç¹wˆû =8…c+¬Ø¢hQ½o§1H)�6øÏt”À߬@Í„î¸H V~A¤«Eý߯˜Ž/¿¿ÞÏ—ù¦«P‚í¿­Ð…„I ä‡Ô{‡ÿ̹ñ�.€Æ<òïìæÛsid„Bð‡œ„ ³Ülº£#p$þç Q´œ6r¹7â©‚›'…° ü%’vX4>ÞÑô�f«îmƒBh°òÍÉüoŸ"œO©#eGQ€åÞ`G¡¼Jž/Žxo°8þLÊYÀÆŽ,kø3{fÂÉÙÃ|—é133333333ƒð1333ÃeXÞNÆnS?ß”[Û*ùŽ7z’~UO„žþüÿUíq‚7¶�-8xûh(ÿØõ7Y×ëdȸb ‘rÂ@´ù%Ø~ ØySØ}¤a#7*¶ o}úê;‚ƒÀM mCÅž¨Hð�ÊØw5)xˆÄ2.Z¸ó ÜøP°Õ ¤€6ÿŽÓÂÍa?ÞÂ׃ùYXg Ò‘ Zàä"áP¦Ï R# ïmoÙ%% 7^ò_oÍ-7ËêÍŸ„B”¥Þ|õù@»ÃP[˜]‚ÍGáÔ{6ÜõÆÛw•¬©&qî?ÿ“¡—ƒÀ¹Â8�íhãT�\,¸¤tp‚8w½�çs�÷”qÞ+ç)V0=öaPþ½S,\ƒ¨bA@e¼%dïëç{Ù^à"Á9�TÁÂ:'ð#á�àìËl9üäÚôzú¯Sþù=Cêë!ÌW@ ×†5chd-º1¨‚dײý† gß«âÔîz d#ðÎä ×0:GÕBRKDH�P)ª+,ЦêÜ@E‚ê × , yÙWóßœR赎„8Tø=Â5`ÉÛÃÚ{ÂÆÙ¾ºc*‰ �ÁzSB%_jÿÉ–dÃñhFÕëE?—ð÷cë ²z³=Mƒ1P+–+ð£âæ k ³ší×3œy;Ã…·¯8÷z%[™Àà®bæ@x®Y”—3ZA¯Ê9Âò(lÓ(7Î „!ŠWW¿AÔ‘0 øÊ_JøŸ÷ûV›? B ”#‘pÛa‚äï[ïßë´ë1ÛÝ”À‚‚Z!øû‡Gˆò^)9ýU ÿúÕ1�) ¤!Ì€5 Á ž\Ÿ0íþá“:w(¬Ð”l=ЃðΆ+ïd8÷:†½mé2w–à@h¤¦MIÃH� �Oå“�:<*=7Ÿ$"ÿ‡œ¿~“kc¿û~l¨D �«×„pÖß ö>¶�@èz•Ý9Að“Ý/Xˆý{p)êŒ_z÷˜Wþn džÒá91°6ÁŠ¿e®aT/R(wpP”v8�-�´v¡äâÛî{/ÃÕ77œØ–Ö-ÅM ‚h8KðA0QSaƒ`è fªAÌ1ñ¼WþÜ™ApÔk{H½vmÆoÝ—Píç¦0w®ëD$t ß áYˆ6aûýáÔGÀîi;¼ÂvèA0Œ‰.º%Á/™µU˜a¢^Ás?­ÉyÕÿ¤ü䛯”×}rD±;7˜ÐV7‡„q „ (¬_0\éax¨‡áî7/¹k[â!Eúq@z„R~wW÷kSv mœ Þ¤`úZ‰¸ÑM ƒÉÊz?ççîO0û3 W�AQè®W»€ÒB¼ '>Μeït劔ˆW¿ë[mgT‘@P…BdtäüÁ÷%üÚ§'jó�r‚ß'¸ˆ�: Å4²žÁt„£ºy¡ä= �¾WÉ}on Ù�‚kÝ»ýµyÎ †¦°N‡8H\s( ^$Ì�ø‰€r@”KŒn #a:’Í¡¯[Cóü4¤§àâ—öúÀŠíÅÒÁ­ þêé/=  å˜P`(ÛœïzÇ„þ‘Š‚1BŠÍ_c„NEƒª+@�Zu€Á‡ÀÕ­†{ß¶ä�>Èðà[”ìäâ ñRœ «½‰ÁM ]CË‘²€à"A÷@Éœg{¾ïþ”¢¯0ó%º†`„ (t¨õ-o}M\añ°åògVÜý%[±Öšà_^ö©öè…ÍW+êçGÕ9‚Msþþ÷S¾í�Rl—MA 5L´#Lƒ ÿžݱÝ@=±lµxµäôƒ%�¾sÉë¿gɃoT²ˆ0HP âr’8�qB8§ f=3¾åþ„¥s­(>.²Îõ¡‘¬GukÐ>ÐXöÞÎpÿç—\~‡’�!°‚ÿúŸ�²]9@ÂQíA ˆsY÷õ+ß1åß�\ \b Y„Z÷z2Pk†%ÐÖjóAÉÝoÒƒð%oø.ýú~iäôA�I¡I²çRŸ¹6ãkîK9p �`.ßÏ Á4s r¨:�hi�’ RòZ_h¸øÈ’à_ÿ s4 C@%ˆ#äƒ#d°Èø«ßÍùò÷Ô. 7~„µ›?µŽ�ê˜q Ud,t•vo-Ÿ³EÉ#oSò¦ïSð&ïXrr÷¨O*QÔº(‘ï(\_PÆòs«û»œ¯³œ¶ÖŸûÈx½ÔÆkF@Xõ·F@8´€!Z,yè³K‚_{á×Ú� ÃzR’´†ÀTtuGC,n0¼µÓôú¬wÏù§?q�M9€^ ¹€  PUiÝ› B àpi[Õ¨ê�±w¾àõz»|Ç)xðá‚�yAЃrv@ÍHtk3þâ7g|ã»ejõò‚´/Áñœ`CC0á·•XyŒlìþ€=sÉpå>Ã=ymÃÅó†½MCLK×Á³kDðk_û©™‹€Aþg Ã8ò¦S ˆæ#›¹‰A0�«‡:&`J®ö¼ý”¼Ý{\:/¯rAÛJ=4ˆ&Î 6güÈWÌøé¯ÏÕ]¯×ž‚L P›?Ù#¬ýÿ àg,˜Á_ AX±½×Cð‚Šdw›v±ËË_–„°³]ñÂÿààN¯%TVÃàêŠu>(…$öA‡`<.DЬ€À›| œJ76NCàêúVÙGCÁ»¼Áë¿Á’í|IXÚ(¦’ÿËC“ÍøŒw›ñÏê6Üa¾‚™8Áñ!˜ŠUoʉj¿g¡ªAÆ«5l�€óg¡^ K,„X ¦‚ƒC¸Ý«h�È=M¹A.�„þËÅÍ=ûŸŠ‹ØÅÂ+Üà¶›šitíu÷Cïü~%½^L`jò…åìËõÛ1ó¶·oÍ�«Z‚M˜v•Ûøiœø{ë6|�‚¡€�-¸pÂjmv!N ÀÔpXÂ�þÖÐÅ@æ.z„0…,uÑsÀN4†ãȺô›ÄqÐ�£Óé˰µC`—loÖÌç �ýË ¸uºÄÝõÇ�ƒ ”LÔ9`´ ¬† €—XoãUu*`=‡{.A@UA[‹º‚â’^AU·—p­×A3À�+�Ä‚ë\îk-˜Ž‹¨¦ P øŸëf|“ÑŸÍP—0‹àÞ{¡iä»é,ä Ô<õ$ÜZ¢íÚ Rüé`ÚÍ€R ¤¸1 !Ð+ä}à¼À`'h+h�l`âÁ`Z¸¹„kÜn¡KVÀà”B¹˜€@­Ýœ‡Ç†Às3åRW/ˆSšš ºVÜ1NáàŠÆ�€ñþ Ì\$>6� X>¿~ l-]TLƒPBÚÁ#ça3 ¨„ƹ‚!–‹g�¸([¸Q³E_[ ÕáË�� ‚ ÖT“Xc:ÐnÐȤ0 Â!lepÿe¹ë#µmä{H3¹®ß„'ö¡ �ù8Ú¢Ö¦Ðn Ϧ‰NYË(pÿmq„²^û,l¥`†�ojWÎÜ� Jg¸SÃ~ Ϙ~�ën-Jbíꮟ˜pwÄôY�î äÓt$–ð:W!� 2àC„A’CÓÂãûð̰°˜Žƒ8v{¼¾ V7…¯3àÿ¬Ûtˆ+Æã „¬…×?Û)ãàÅ‚ïD:8ƒ áf O°ßÂ2P99(L'Ü`"*R× MLc:Ô§ˆc  öàâ˜R9A A8Dc&º]À+öûZsÑ*Òh* tÙ)ÞU©Ÿk•êö5ÇAÞÂÝ; ¸ž –�¹L £¥4“Ú„ð¬�Ç+x¦…&Q0¬pƒõ Ö�йÍ>F_pÛ5ˆã‘ ZÂVop^®·6½j‚^~³œæâ„�ß„WÝ‚:V± •÷%<^¨ÓB�@ðqÚªVrh2 Á›íÁN<8ACãÅD×Aä@ð\!>g™|>è„Wöºz1¸Á,˜€`‘Šq„)T$ Wðç†IÄ TC•~IÜ0ƒdˆÄ,—æðÅûðl=}F0:LL3`9î_j-hÔZäâ¡m ¼Ã X\c8Ð_{0¨h°ÂX¹A껂@a#¸ÖÁË <Ö�ñ¦ˆ,R 2ÀøÇÃzóWhéO ª|ƒp&‡Òø1à`ÐN 5Í嚟>„Þ€"sƒñ¦PŒ¦#!V0 ø€hÒ œJ+w»ƒàDo· épBØhT£Ø¸ ˆF@8²ËásÀ+kxI×B� ’§iB¼n' ˜­†`Ä n�­­\‹Ž�ûðð&”Ò¬„ ÉäZ�ò* ÿ{3¯ydL§›ÂÑHhø9kÝk'˜€@T¸>¡„+!¼ÝjÛ«Q“A¥ PýAj7Ðk�!ëeCéþ«†ÇBhRÉÇMôd0 }fàC0)Õ,áLoµ Fmº[;äU5ç"i¥>YÂÞ„b¤7zý_kgÜL®lÿŸ` I–á��™™™™™™™™™™™™™™™–ï&±=#éÕ·é*wuE·'ɺªKãlöÙçè4¨GYëÝÙÙÁ¡LUÅ�_l� l,è®;�kuˆÄn‚W ð²IÒʆ� tCyß*Ä ƒ= ð'�B„r€'+üG…Šp¥¢Áî]ËÀéÜìÀì¾m§ýxc�7»ê(� ‰„HI�”äó)—0,Ïb¡-p­¤|_K‚¸Ô®`~v0€N ßßš>‚�K£f[v ¼�<áº&C„É€>…¨# gH‹óÔ@ˆ ã"íýù7øû'ò}ÝhÀöTa l, zD0rº\nàío‚Ü`gU@+€&A6J ãB\Ä�ÀßÃnø®À«–ý¼_ч&�ÀÎ�d4ö¤ÜäMÔca“!‚ߪ€Mm<�ôµŒ9ï7"+ðð�²å¹ìẎ«X«]5·PdÈpR`µƒwYA °+´£µBÎ:;P£Ä�ø³'á‘°/…5øY�mVød{DŒ"Y2�s¹î@ìqàE�—Ö* ­ ,ðç¸Ø—•è1C{"D©yÿ«b"\ßYýúú˜f–Œ5ž�tùÜä³­ȵ&U>ÇR®‰ $( þöþy„&*�äù® 1Àû*è™AÀö ð”ÿšr³­!À¨‰à¸…iEÔ`0®ÀŽƒÄY_Êø$p¯X@¾”ž[PJµ¾}HÃòðfrnÒF>ëè’àl$W GɆVKø¯üñ)œŠKXGG:áo*8²�zÛÓBTcæ\Wpðrp}­­HÃÉ9®@”@ƒnÉ ÍŸ|Q¥à»ä<¿¨rè^œp´.ø}%x#àVE€©Oå Tf°4$ägòþ` Oðû§ðÐqÕÉW� ðÞ­©S¿t‹Vÿ„�dˆ`Ý‚N©^¸Q«@� MÁ�@�­@Ê=PñB‚ÌùD؉<¤4šç ” …ò1žG¾veR.Ϥ‡úgë ¥ÁŽgÐ2à øbú³>¯5� ê‚ÀÒôâY"D{F�ŸüB ðÑ’À¾o6e4dØ©�Æ…u *…T$Èöoÿ¨­â�Gz1B›™l�×¶P6»£»-´&ó×J ï5)óüm…?”³{oÔ@»j A ý‚PÁßP[÷B1p�ök<°2�K„¢€WªPäZÊÉ|ŸE˜€‡e/Ôuh2†f `2‚'$ÆxE ZðÕç' ¼tXeà¼"‘½ÎûžÜ;�ß,nV ;»…��i�¤¾ûeEùà;±IþûÊté.�¦žéÓGÇ­�ÛÕŠ˜MIûjU�$5´$ ' |_Š: Iˆ`ƒDJ_x\”ñÅ€­sÊø8vCÙ8RE0 º%‚¨À��ødþ7Ï‹*ȳ_VPì.êxt!‚¬(³oÜ´.èÎuµ1ŒÖ%$³ò…Qƾ("ˆ5!Ây®ß†ð¤u ê@§ÿ×%€²&$01€v4Eb-ÿ:(rKüÆøm™“Oïgà™^E B„&?[«Œa«ÜÀXØUp!"ˆ˜ÀP¿A­~!AT=Š)î¥?itˆ0©Ãž€�_¹€ÿ#_°À'�Évò^g¹·ú…¢ êéê¿–@÷¦gï ï¾i’:áÁº Kˆ £LäKœ,Ä,Ü`±Z— ²†�Muz(R­;ðÿÚÇ(€&¬�S»M,ÊݹVŸ½ èæÒÁ*�˜¤½šd!Á=V ,Þñ±&åUI?"d.gšI& x€‹CˆîÏd²§­ŠÿÔDе‚ su  JIî]€•d ƒ9æ®ÊŠ/BtÉXFE] ê*A6óWäýwா+¼Õ}�¬ 0ÈFL¸8øV!ì5 th;žCžz¾ Œª^ �—k[1ôI ÜB “¸…¨R^ùÝø dîû@Ðl ôI`Ü€&ÁJðŸª�äHàMþ«í·]óÙ˜„9AWSû%'“"¹à;nA× l€X'Éz)"øJ`‰ c[©¦’,×6íÓïÝ °§ÐíuQ`„ýuÕJ°WÐñ�˜[@òÁ·cÐà^•ÅÖ Ô–«Ž¨³ÎT�ôL„2gK„hb½;ØO]ϵÀgjh%@®«míV}ü6PL¾;˜ˆ êU‰ +J§Š!Ø ÐÉ — ¿èæïCÏÙÖšu6–™ï_Ôš\«“&EÕ.Aâƒ&A‰ï, æÇÖ·{×Nš¨ã�2BLF ò̔бì>_lZXÌþ€ŠÜù |UktF«öZÁºëfÅ3Çägó•¡"* kjß}¾ ¸Ö.¾òýX@T,åyÈž ø&Q€Ñ}øÖ5è´±ž£¿Lì� üë~ÁHV­ŸšçoyÁt•´PÕ5ìA°q€C€ÎûÀwÐ}2!‚¸‡€ª¨2òp… PÿÞ¥”@Æ�m2QíXD•OëÎâ+*Aõ A¾[PÁŸvôHÐ!À úæ“bjB}€bhŠ— ;ã3¦e¿ºÊhÑJ>>ˆ—ðû;;ߦ@«–Yý–¾~R+@ô®‹ÐVš.&AjEI 9Í$�Œó•à’DÐU·Ví–±!ÁEÝ€r]»«„£yœ¬œSÈVªÀ/((pû ;VT e;w‡¤*‡ œ&ÎÔÙz�æC�ìôY>ƒÞ(ºz] ú ûVlAHI¿ªc\¤‚¹�ÇÉ:ðm>ID ªz´K“ ʸ0×i¦ï�¾øÊ öì~AÎÏÌ&Q|&öš©L�² “7ÇŽ �_†ù Ï'LS.!jw 'è çƒ0ù€wI°S󔮺á2W#BÖ÷êíÛΦ‚jž}ÅÒÊiÇÀµf;}¡®ú™Oûß‹<ßdÂW åƒèùú [àmµp'µ�d³�+*A¹Z `z¤ˆ•mæâ¶µÙŒ ðÝšÊ"P-�WT„±!Mëýü9î Í]ý^á¨À´‚–Õ3»r¯ÀUS¢Ÿ'<‡áÂqJà[ ´ÙRìÎÙU y7I‡xµÚÀ Îù©2ÇÍìx CqYXùð+o„y¾ßÂ(VÕ.@ÅUýxÅ'À× ¬%õ�GA^ªG~ì\•0r[«� XÌÛ,JªÉqˆêñ­S`š¾-KÌ2S‰Ÿ›f�îX“2¶œÇ¨j-ݺ…³�øòŽ$ÿVµ’�Ä*°Ñ§ŠÚ�$K„NûVi�âåJÄKàÿ#� Ê…«G¼¦‹f ÊU A¯TÌó�žõ8Y1Y€3Çž¾°¯¬€ç2ÙA0¿×„Oˆ�èÔÐ%ƒì*Ú¢‹&à¹�›Œ?«àëa!ÂNÞ»PñJ8îh–"”‹»;?EU_.=·Àgè®ß5ðÂf…[§;¸¨¿Zù°"CuˆPœâ�£œBöÂ�«ÚKúöï‚–¹#i�âÌJ¥¨û8æd[óôSº´:>Õ@ÛxÙŠXP+ÒÞøTˆp¿Œ§† c‡]¨çó^YÞï:dÂ|–…�öà`3§ˆÔ ¶Ë¥‚Yµb¨¦×ÍÜÀ¤ Дÿ—nb |‚: ™Uv¼;¥â"†’ݤ¿t± Jp/ðß"Ç!‚Íj�Ê^S7ßöU… ÄNíà)à_€}5°¤œÕ8šô©dŠð òÄe€Gl2»�’XlÑŸ§ü7ÕQ€ü_àµ:+ÕúøDM1K† <ñß¡ý´Ç€É<ÐúiaxuhÏo»Î['°\Êç»øÉjŸÄ  ÊŠÿߢT: ÀB‚ÓG�i>øšÒ úÛÁYˆ87 žÚëŸ#³¥s]�Ð'�^…a€áÒÝPþÆ;  hV¥гzMàacÓ;_Ĭ<‹ü•(Sé¤�ÁÛ­Tïo—Ìd0�]1DzTÜâtqH`Û׿6±ø�ÖàÐ,_Â+ÃvÍ‚>vˆ`ÁKÐM3å4Ô ?ã?ÁÉßÃø 0©ÿ8z%8x=8)p2B홌ᤗòèwüg¨"qJ5Tø(rÿBHÚ¬Áï ÉS»�_T ¤ßB§~MQ³&À‡ÉaјÕÜüö_N¶°™ z-cš–TýNa†K8`¹�ñßáY Oþ Pàæ×„[Þ N¦3;ž`×­-rjÞ0‰+X<ÓïÀt€NSû­ëϼ �m ×!@RAé?‹K˜M‘$S¡¼l�"\ÿc­íî„ña(ÏÚK^¼žûà�}é§l Ltû¥ãƒã¼ÓEr†u<#ÁÑÖ­1ÞQ™*Üðò‘S2'#œTžO‹ròc0)nç‰àåFÿžú3³ˆ%üâóB{9h×ë\¾Cʪ@l))óßÏ•ÿS‘ `¸Ôž‰}n}´µe�| <Óý�í]�á¨òß4çžr�üƒkc‚£¡r¸Ø±-™§v™Ó‰³û_3›�ô‚–ÿNJúwÀŸõz:$òRÀ¤ÿ¿\³ßÌ ü¥"€!Â*Ã*Â: !b£§%p¢b‚]AHпtü±Œ½-à…&€Ìa[Ï€ Ø:�K¦Â讜8øB€ÃÜXÇ‘]Íœ”(àŸ­þ�§>Ú=&‡Äü"Ô»Œ+¸èêO2®ÕÙ† Ul“OBà�Z³àËHÈ05XEHA¡” · lÉÐ`Îé¤!ÃR°Ng ò!ÙÉã€þÊ1q€¢Oß{bWÇB|ùÜŒs�¼Å!€ŒÃ÷ÀñOé–µ™«?*ÐoTçg3§ª~ÿaüŽR€Î,1†cÅ*ÁüKèd†å!ÃZìPˆ¸«p,Ä“¢Ð¼Žå0Ïw®” 8|Z+›ÏWgÏOF¹ïÑ N~ Nþ{A¬*½ à·Ê.é¨*;)�Eð ~M)@ê“@Šk±e„ŠVµ*<§l<¨û P@˜Ü L çU¹^ˆˆ`›ö¤×ã·ÃuÀ³×¢vxæ‡áÞï„vjˆ÷óGg€·çдÛè(p0÷½¿ÜŽ (ð"ˆ[PD8U�Y™«UMÊ!Á ²‚e‚mA‚A{=ˆöçmÞ‰%ƒ¥D”Žc]ðuði²;f�}¬àñ_‡YUhW�o�üÏ PåÿÀn `kAïÍÃlÝ�_oR¸Mïæu‰ šEb· Z ªN`åÑ#AšG‚•Ê jÛï ì:÷psñÔÏt A§ŸlmÐ[ü¸Ãs;ºöq4ÀpRø�ïÄÃÀúyù9¡Ý»g…¹´Ñw}ÝBظ—Ç¿ÛbâVµ·?Ë�ŒÈ‘›"©ƒ3�Ìs1ï´Š#ý–xSNƒ¡‚þ´ËqïçïCˆ‹Ó™Gjæe»a`âYÝcwöy7B@F�ÑŒ Ò¸ƒ»®e0q»@¬£2Ä˼·²RtPèž?ÜÓG•+�`Pö¶�f¼"€R€u‚±ªÕß'¶ ¸¬{³dÓÅ' :%H…&¶màdŠgªZ÷êS °sâ+»nmüÿøóö^ÔÔóM§O‡ †ƒ0y!i¢Tʸ˜+ÊTäK¯N}­ °ˆ°Qgq‚>wÿÁ\Ç àž­þeœ[â¤øbÛIÀïÀ€o]�Q€å·Û~�‰7• Ã¢ù.!Éêâ 6zÅxÅ"€ä5—œ(n`çûÂK ª,g{Ñ '»;©s(H•ÒxüM…SíRûm÷êÞNp­7¡þ�ï üSû&>ó܆O¯ïÏŽbAªˆù̘�#g…Æ™¡Z�»9)`ñ\€ ˜©IÕ¯8y¿ÙwÐÖUGYýRînpZ§ºÈVt‘MÌ’ ª1uîõ âþš ü[{m ¿ÉD @Ÿ ‡òž… k�–ÕmÞ1sIÅãE‚²ì�* „`§’öáYó\™òýRl’LJîW÷{ ;‹Aï{³ È‚o>sZ² ʈüßíp*ü/`ndÿq%oóI�Eªw ÔâÌ2±¬ÐiÎéÅää¹ïâ“A|ï,ð�â–U#ýI\¦N¥§ópè½·>ÑÛo‘¬cÁo–×Ë;Úçî ŸÑ&pI 2cSª. ä† ¨�ܹS&ëTí„\­Aqå_Æ0oCe©ÔÅÄ0~y;uîaËÛ*ê"âïasÍ$x¦ôÀ÷7ØúÊ)û*K>ô�[Â7 ÚsøË±rSéíâ•ΦNtH 6–ZóWéEb�(Äj.Ä‚ã—8Aäx~UÓÙåÓ�ŸÔ3Ø5YõºÈT:Ø‘YŠiÛîî\^öŽÿ È+þGû¼ùô”ê´�[ö…ž˜IÄn 0¿�þÇÛŒQcòýr×2VÓÿèEýqN£L)1oÕÊ»êÛé²Âi·Ó»a_µ=XðaÿycøF€€¼øÇv‰?‰# šËÀÎóÉøVý>\À_'_² 3å¿Í#@–-çÑ]_gÕÛJf’ ©îcŒRúÀ÷Óø$ï@lÙ5• X|=ÍÜ¿6q–~‚œeÕgS—±~à_^Ÿ¾;„€K€ð'¼‰¯%q@R+Ï/Š¢4¿rçúíL—Të^,èÕis索fój¡4µ‘ク FW`ûU/-|í‘øÐ¿½!ü(Àl„?ä5I|‰—Ô ôýâ…H`z,~Q¨K€ÑÙdê–f�’ØU_¼]úó$Ø«uæƒo ;~Á-fX©UÍrà§Æ‡ýËMü5À… ~�I|4‰#q«VšÓ\;u‚ÁQ'wwUÄæÉÉ�#ü^ç>å$–“„'"÷ô`ß×NOF_þpYù ‘»Kã«·•oºëVN.KM„ç&ñž$Þ…Ì ïp” v£VÅ;ñDÏ�Ç…D'7ï‚Ñ}ê9Š;©Õ–Ñ-àÆš³ê;}"÷uùÛ ?´«|Ï=·ñöåÀñ{í€ÄË“xM2¯Dâ9€ÿM!1ј¨ÖL\ÇDp&_è¯2×'H úÀ‹aÁè]B€V=°�I^?·97$¦!óð*qï:qÇ"ñG4~gWùëþwØq�×ÿ‚ÅÇ7vú\IEND®B`‚evolvotron-0.8.3/dist/evolvotron.spec0000644000175000017500000000413215230700302016427 0ustar karlkarlSummary: Evolvotron Interactive Art Generator Name: evolvotron Version: 0.8.3 Release: %autorelease License: GPL-2.0-or-later URL: http://sourceforge.net/projects/evolvotron Source: https://github.com/WickedSmoke/evolvotron/archive/refs/tags/v%{version}.tar.gz BuildRequires: gcc-c++ boost-devel qt6-qtbase-devel %global debug_package %{nil} %description Evolvotron is interactive "generative art" software to evolve images/textures/patterns through an iterative process of random mutation and user-selection driven evolution. %prep %setup -q -n %{name}-%{version} %build qmake6 VERSION_NUMBER=%{version} main.pro make -j 4 %install mkdir -p $RPM_BUILD_ROOT/usr/bin $RPM_BUILD_ROOT/usr/share/man/man1 install -m 755 evolvotron/evolvotron $RPM_BUILD_ROOT/usr/bin install -m 755 evolvotron_mutate/evolvotron_mutate $RPM_BUILD_ROOT/usr/bin install -m 755 evolvotron_render/evolvotron_render $RPM_BUILD_ROOT/usr/bin install -m 644 man/man1/evolvotron.1 $RPM_BUILD_ROOT/usr/share/man/man1 install -m 644 man/man1/evolvotron_mutate.1 $RPM_BUILD_ROOT/usr/share/man/man1 install -m 644 man/man1/evolvotron_render.1 $RPM_BUILD_ROOT/usr/share/man/man1 install -D -m 644 dist/icon-48.png $RPM_BUILD_ROOT/usr/share/icons/hicolor/48x48/apps/evolvotron.png install -D -m 644 dist/icon-128.png $RPM_BUILD_ROOT/usr/share/icons/hicolor/128x128/apps/evolvotron.png install -D -m 644 dist/evolvotron.desktop $RPM_BUILD_ROOT/usr/share/applications/evolvotron.desktop %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) %{_bindir}/evolvotron %{_bindir}/evolvotron_mutate %{_bindir}/evolvotron_render %{_mandir}/man1/evolvotron.1* %{_mandir}/man1/evolvotron_mutate.1* %{_mandir}/man1/evolvotron_render.1* %{_datadir}/icons/hicolor/48x48/apps/evolvotron.png %{_datadir}/icons/hicolor/128x128/apps/evolvotron.png %{_datadir}/applications/evolvotron.desktop %changelog * Tue Apr 23 2024 Karl Robillard 0.8.2-1 - Update to build with Qt 6. * Sun Dec 18 2022 Karl Robillard 0.7.2-1 - Update for v0.7.2 * Fri Mar 28 2008 Karl Robillard - Initial package release. evolvotron-0.8.3/dist/evolvotron.ico0000644000175000017500000020407615230700302016260 0ustar karlkarl€€ ((€ ÿà ÿÆ>ÿÉ|ÿͳÿÐÐÿÐèÿÍëÿÉêÿÅèÿÂñÿ¾þÿºÿÿ·ÿÿ¶ÿÿ¹ÿÿ¼ÿÿÀÿÿÄÿÿÈÿÿÌÿÿÏÿÿÎÿÿÉÿÿÅÿÿÁÿÿ½ÿÿ¹ÿÿ¶ÿÿ¶ÿÿºÿÿ¿ÿÿÃÿÿÇÿÿËÿÿÏÿÿÐÿÿÍÿÿÉÿÿÅÿÿÁÿÿ½ÿÿºÿÿ¶ÿÿ·ÿÿºÿÿ¾ÿÿÂÿÿÆÿÿÊÿÿÏÿÿÒÿÿÕÿÿÓÿÿÏÿÿËÿÿÈÿÿÄÿÿÀÿÿ½ÿÿºÿÿ·ÿÿ·ÿÿºÿÿ¾ÿÿÁÿÿÅÿÿÈÿÿÌÿÿÑÿÿÕÿÿÙÿÿÜÿÿÝÿÿÛÿÿØÿÿÕÿÿÑÿÿÎÿÿËÿÿÈÿÿÅÿÿÂÿÿ¿ÿÿ¼ÿÿ¹ÿÿ·ÿÿ¸ÿÿ¼ÿÿ¿ÿÿÂÿÿÅÿÿÉÿÿÌÿÿÐÿÿÓÿÿ×ÿÿÛÿÿÞûÿâçÿåÍÿè®ÿëuÿê6ÿèÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÅ~ÿÈ×ÿÌÿÿÐÿÿÓÿÿÒÿÿÎÿÿÊÿÿÆÿÿÂÿÿ¿ÿÿ»ÿÿ¸ÿÿ¶ÿÿ¸ÿÿ¼ÿÿÀÿÿÃÿÿÇÿÿËÿÿÐÿÿÑÿÿÍÿÿÈÿÿÄÿÿÀÿÿ½ÿÿ¹ÿÿ¶ÿÿ·ÿÿ»ÿÿ¿ÿÿÃÿÿÇÿÿËÿÿÏÿÿÒÿÿÏÿÿËÿÿÇÿÿÃÿÿ¿ÿÿ»ÿÿ¸ÿÿ¶ÿÿ¸ÿÿ¼ÿÿÀÿÿÄÿÿÉÿÿÌÿÿÑÿÿÕÿÿÖÿÿÓÿÿÐÿÿÌÿÿÈÿÿÅÿÿÁÿÿ½ÿÿºÿÿ·ÿÿ·ÿÿ¹ÿÿ½ÿÿÀÿÿÄÿÿÈÿÿÍÿÿÑÿÿÕÿÿÙÿÿÜÿÿßÿÿÝÿÿÛÿÿ×ÿÿÕÿÿÑÿÿÎÿÿËÿÿÇÿÿÄÿÿÁÿÿ¾ÿÿ»ÿÿ¸ÿÿ·ÿÿ¹ÿÿ½ÿÿÀÿÿÃÿÿÇÿÿÊÿÿÎÿÿÒÿÿÕÿÿÙÿÿÝÿÿàÿÿä ÿÿçÿÿêýÿì"Ïÿì vÿêÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÂÿÅ€ÿÈëÿËÿÿÎÿÿÒÿÿÔÿÿÓÿÿÎÿÿÊÿÿÇÿÿÃÿÿ¿ÿÿ¼ÿÿ¸ÿÿ¶ÿÿ¸ÿÿ»ÿÿ¿ÿÿÃÿÿÆÿÿËÿÿÏÿÿÒÿÿÑÿÿÌÿÿÈÿÿÄÿÿÀÿÿ¼ÿÿ¹ÿÿ¶ÿÿ·ÿÿ»ÿÿÀÿÿÄÿÿÈÿÿÌÿÿÐÿÿÓÿÿÒÿÿÍÿÿÉÿÿÅÿÿÁÿÿ¾ÿÿºÿÿ·ÿÿ·ÿÿºÿÿ¾ÿÿÂÿÿÆÿÿÊÿÿÏÿÿÓÿÿ×ÿÿØÿÿÕÿÿÐÿÿÍÿÿÉÿÿÅÿÿÂÿÿ¾ÿÿ»ÿÿ¸ÿÿ¶ÿÿ¹ÿÿ½ÿÿÁÿÿÄÿÿÈÿÿÍÿÿÑÿÿÕÿÿÙÿÿÝÿÿàÿÿàÿÿÝÿÿÚÿÿ×ÿÿÔÿÿÑÿÿÍÿÿÊÿÿÇÿÿÄÿÿÀÿÿ½ÿÿºÿÿ¸ÿÿ¸ÿÿ»ÿÿ¾ÿÿÁÿÿÅÿÿÉÿÿÌÿÿÐÿÿÓÿÿ×ÿÿÛÿÿßÿÿâÿÿåÿÿéÿÿì!ÿÿî&ãÿí#sÿë ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÅ>ÿÈÑÿËÿÿÎÿÿÒÿÿÕÿÿÖÿÿÓÿÿÏÿÿËÿÿÇÿÿÃÿÿÀÿÿ¼ÿÿ¹ÿÿ¶ÿÿ·ÿÿ»ÿÿ¾ÿÿÂÿÿÆÿÿÊÿÿÎÿÿÒÿÿÔÿÿÑÿÿÌÿÿÇÿÿÄÿÿÀÿÿ¼ÿÿ¸ÿÿ¶ÿÿ¸ÿÿ¼ÿÿÀÿÿÄÿÿÈÿÿÌÿÿÑÿÿÕÿÿÔÿÿÐÿÿËÿÿÇÿÿÃÿÿ¿ÿÿ¼ÿÿ¸ÿÿ¶ÿÿ¹ÿÿ¼ÿÿÀÿÿÅÿÿÉÿÿÍÿÿÑÿÿÕÿÿÙÿÿÙÿÿÕÿÿÒÿÿÌÿÿÉÿÿÆÿÿÃÿÿ¾ÿÿ»ÿÿ¸ÿÿ¶ÿÿ¹ÿÿ½ÿÿÁÿÿÄÿÿÈÿÿÌÿÿÐÿÿÔÿÿØÿÿÝÿÿàÿÿâ ÿÿàÿÿÝÿÿÚÿÿ×ÿÿÓÿÿÐÿÿÍÿÿÉÿÿÆÿÿÃÿÿ¿ÿÿ¼ÿÿ¹ÿÿ·ÿÿ¹ÿÿ½ÿÿÀÿÿÃÿÿÇÿÿÊÿÿÎÿÿÒÿÿÖÿÿÙÿÿÝÿÿáÿÿä ÿÿèÿÿëÿÿî&ÿÿï*Åÿî&0ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÈcÿËõÿÎÿÿÑÿÿÕÿÿ×ÿÿ×ÿÿÓÿÿÏÿÿËÿÿÇÿÿÄÿÿÀÿÿ¼ÿÿ¹ÿÿ¶ÿÿ·ÿÿ»ÿÿ¾ÿÿÂÿÿÆÿÿÊÿÿÎÿÿÒÿÿÕÿÿÔÿÿÏÿÿËÿÿÇÿÿÃÿÿ¿ÿÿ»ÿÿ¸ÿÿ¶ÿÿ¹ÿÿ½ÿÿÁÿÿÅÿÿÉÿÿÍÿÿÒÿÿÖÿÿÕÿÿÑÿÿÍÿÿÉÿÿÅÿÿÁÿÿ½ÿÿºÿÿ¶ÿÿ·ÿÿ»ÿÿ¿ÿÿÃÿÿÇÿÿËÿÿÏÿÿÔÿÿØÿÿÛÿÿÙÿÿÖÿÿÐÿÿÍÿÿËÿÿÆÿÿÃÿÿ¿ÿÿ»ÿÿ¸ÿÿ¶ÿÿ¹ÿÿ½ÿÿÁÿÿÅÿÿÈÿÿÍÿÿÑÿÿÕÿÿÙÿÿÝÿÿáÿÿã ÿÿâ ÿÿßÿÿÜÿÿÙÿÿÕÿÿÒÿÿÏÿÿËÿÿÈÿÿÅÿÿÁÿÿ¾ÿÿ»ÿÿ¸ÿÿ¸ÿÿ»ÿÿ¾ÿÿÂÿÿÅÿÿÉÿÿÍÿÿÐÿÿÔÿÿØÿÿÜÿÿßÿÿãÿÿçÿÿêÿÿí#ÿþï+ìþð-VÿÿÿÿÿÿÿÿÿÿËqÿÎýÿÑÿÿÕÿÿØÿÿÙÿÿ×ÿÿÓÿÿÏÿÿËÿÿÈÿÿÄÿÿÀÿÿ½ÿÿ¹ÿÿ¶ÿÿ·ÿÿ»ÿÿ¾ÿÿÂÿÿÆÿÿÉÿÿÍÿÿÑÿÿÕÿÿÖÿÿÓÿÿÎÿÿÊÿÿÆÿÿÂÿÿ¾ÿÿ»ÿÿ·ÿÿ¶ÿÿºÿÿ¾ÿÿÂÿÿÆÿÿÊÿÿÎÿÿÓÿÿ×ÿÿ×ÿÿÓÿÿÎÿÿÊÿÿÇÿÿÃÿÿ¿ÿÿ»ÿÿ¸ÿÿ¶ÿÿ¹ÿÿ¾ÿÿÁÿÿÆÿÿÉÿÿÎÿÿÓÿÿÖÿÿÛÿÿÜÿÿÙÿÿÔÿÿÒÿÿÏÿÿÉÿÿÆÿÿÃÿÿ¿ÿÿ»ÿÿ¸ÿÿ·ÿÿºÿÿ½ÿÿÁÿÿÅÿÿÉÿÿÍÿÿÒÿÿÕÿÿÚÿÿÞÿÿáÿÿåÿÿäÿÿáÿÿÞÿÿÛÿÿ×ÿÿÔÿÿÑÿÿÍÿÿÊÿÿÇÿÿÃÿÿÀÿÿ½ÿÿ¹ÿÿ¸ÿÿ¹ÿÿ½ÿÿÀÿÿÄÿÿÇÿÿËÿÿÏÿÿÓÿÿ×ÿÿÛÿÿÞÿÿâÿÿå ÿÿéÿÿì ÿþï*úüñ1`ÿÿÿÿÏcÿÒýÿÕÿÿØÿÿÛÿÿÚÿÿ×ÿÿÓÿÿÏÿÿËÿÿÈÿÿÄÿÿÀÿÿ½ÿÿ¹ÿÿ¶ÿÿ·ÿÿ»ÿÿ¾ÿÿÂÿÿÇÿÿÉÿÿÌÿÿÒÿÿÖÿÿØÿÿÖÿÿÑÿÿÍÿÿÉÿÿÅÿÿÁÿÿ½ÿÿºÿÿ¶ÿÿ·ÿÿ»ÿÿ¿ÿÿÃÿÿÇÿÿËÿÿÐÿÿÔÿÿØÿÿÙÿÿÕÿÿÐÿÿÌÿÿÈÿÿÄÿÿÀÿÿ½ÿÿ¹ÿÿ¶ÿÿ¸ÿÿ¼ÿÿÀÿÿÄÿÿÈÿÿÌÿÿÑÿÿÕÿÿÚÿÿÝÿÿÝÿÿÙÿÿÕÿÿÒÿÿÎÿÿÊÿÿÆÿÿÃÿÿ¿ÿÿ»ÿÿ¸ÿÿ·ÿÿºÿÿ¾ÿÿÂÿÿÆÿÿÊÿÿÎÿÿÒÿÿÖÿÿÚÿÿÞÿÿâÿÿæÿÿæÿÿã ÿÿàÿÿÝÿÿÙÿÿÖÿÿÓÿÿÏÿÿÌÿÿÈÿÿÅÿÿÁÿÿ¾ÿÿ»ÿÿ¸ÿÿ¸ÿÿ»ÿÿ¿ÿÿÃÿÿÆÿÿÊÿÿÎÿÿÒÿÿÖÿÿÚÿÿÞÿÿáÿÿå ÿÿéÿÿìÿÿï'ùüñ1SÿÒ<ÿÕöÿÙÿÿÜÿÿÝÿÿÚÿÿÖÿÿÓÿÿÐÿÿÊÿÿÈÿÿÄÿÿÀÿÿ¼ÿÿ¹ÿÿ¶ÿÿ·ÿÿ¼ÿÿ¾ÿÿÁÿÿÇÿÿÊÿÿÎÿÿÑÿÿÕÿÿÙÿÿÙÿÿÕÿÿÐÿÿÌÿÿÈÿÿÄÿÿÀÿÿ¼ÿÿ¹ÿÿ¶ÿÿ¸ÿÿ¼ÿÿÁÿÿÅÿÿÈÿÿÌÿÿÑÿÿÕÿÿÚÿÿÛÿÿ×ÿÿÒÿÿÎÿÿÊÿÿÅÿÿÂÿÿ¾ÿÿºÿÿ·ÿÿ·ÿÿ»ÿÿ¿ÿÿÃÿÿÇÿÿËÿÿÐÿÿÔÿÿÙÿÿÝÿÿßÿÿÝÿÿÙÿÿÕÿÿÑÿÿÎÿÿÊÿÿÆÿÿÂÿÿ¾ÿÿ»ÿÿ¸ÿÿ·ÿÿ»ÿÿ¾ÿÿÃÿÿÇÿÿËÿÿÏÿÿÓÿÿ×ÿÿÛÿÿßÿÿã ÿÿçÿÿçÿÿåÿÿâÿÿßÿÿÛÿÿØÿÿÔÿÿÑÿÿÎÿÿÊÿÿÆÿÿÃÿÿÀÿÿ¼ÿÿ¹ÿÿ¸ÿÿºÿÿ¾ÿÿÂÿÿÅÿÿÉÿÿÍÿÿÑÿÿÕÿÿÙÿÿÝÿÿáÿÿåÿÿèÿÿëÿÿî%ëýñ/+ÿÖÿÙÔÿÜÿÿÞÿÿÝÿÿÙÿÿÖÿÿÒÿÿÎÿÿËÿÿÇÿÿÄÿÿÀÿÿ½ÿÿ¹ÿÿ·ÿÿ¸ÿÿ»ÿÿ¿ÿÿÂÿÿÅÿÿÊÿÿÏÿÿÒÿÿÕÿÿÚÿÿÛÿÿØÿÿÓÿÿÏÿÿËÿÿÇÿÿÃÿÿ¿ÿÿ»ÿÿ¸ÿÿ·ÿÿºÿÿ½ÿÿÂÿÿÆÿÿÊÿÿÎÿÿÒÿÿ×ÿÿÛÿÿÜÿÿØÿÿÓÿÿÏÿÿËÿÿÇÿÿÃÿÿ¿ÿÿ¼ÿÿ¸ÿÿ·ÿÿºÿÿ¾ÿÿÂÿÿÆÿÿÊÿÿÎÿÿÓÿÿ×ÿÿÜÿÿàÿÿàÿÿÝÿÿÙÿÿÕÿÿÑÿÿÍÿÿÉÿÿÆÿÿÂÿÿ¾ÿÿ»ÿÿ·ÿÿ¸ÿÿ»ÿÿ¿ÿÿÃÿÿÈÿÿÌÿÿÐÿÿÔÿÿØÿÿÜÿÿàÿÿä ÿÿçÿÿéÿÿçÿÿä ÿÿàÿÿÝÿÿÚÿÿÖÿÿÓÿÿÏÿÿËÿÿÈÿÿÄÿÿÁÿÿ½ÿÿºÿÿ¸ÿÿ¹ÿÿ½ÿÿÁÿÿÄÿÿÈÿÿÌÿÿÐÿÿÔÿÿØÿÿÜÿÿàÿÿãÿÿçÿÿëÿÿî#Áþô/ÿ݃ÿßÿÿßÿÿÝÿÿÙÿÿÕÿÿÑÿÿÎÿÿÊÿÿÆÿÿÃÿÿÀÿÿ¼ÿÿ¸ÿÿ·ÿÿ¸ÿÿ¼ÿÿ¿ÿÿÃÿÿÇÿÿËÿÿÎÿÿÒÿÿÖÿÿÛÿÿÝÿÿÚÿÿÖÿÿÒÿÿÎÿÿÉÿÿÆÿÿÂÿÿ¾ÿÿºÿÿ·ÿÿ·ÿÿ»ÿÿ¿ÿÿÃÿÿÇÿÿÌÿÿÐÿÿÔÿÿØÿÿÝÿÿÝÿÿÙÿÿÕÿÿÐÿÿÌÿÿÈÿÿÄÿÿÀÿÿ½ÿÿ¹ÿÿ¶ÿÿ¹ÿÿ½ÿÿÁÿÿÅÿÿÉÿÿÍÿÿÒÿÿÖÿÿÛÿÿßÿÿâ ÿÿàÿÿÜÿÿØÿÿÕÿÿÑÿÿÍÿÿÉÿÿÅÿÿÁÿÿ¾ÿÿºÿÿ·ÿÿ¹ÿÿ¼ÿÿÀÿÿÄÿÿÈÿÿÍÿÿÐÿÿÕÿÿÙÿÿÝÿÿáÿÿåÿÿéÿÿêÿÿèÿÿå ÿÿâÿÿßÿÿÛÿÿØÿÿÔÿÿÑÿÿÍÿÿÉÿÿÆÿÿÂÿÿ¾ÿÿ»ÿÿ¹ÿÿ¹ÿÿ¼ÿÿÀÿÿÄÿÿÇÿÿËÿÿÐÿÿÔÿÿØÿÿÛÿÿßÿÿäÿÿçÿÿêÿÿð"jÿá ÿáîÿßÿÿÜÿÿØÿÿÔÿÿÑÿÿÍÿÿÉÿÿÆÿÿÃÿÿ¿ÿÿ»ÿÿ¸ÿÿ·ÿÿ¹ÿÿ¼ÿÿÀÿÿÄÿÿÇÿÿËÿÿÏÿÿÓÿÿ×ÿÿÚÿÿÞÿÿÝÿÿØÿÿÔÿÿÐÿÿÌÿÿÈÿÿÄÿÿÀÿÿ½ÿÿ¹ÿÿ·ÿÿ¹ÿÿ½ÿÿÁÿÿÅÿÿÉÿÿÍÿÿÑÿÿÖÿÿÚÿÿÞÿÿÞÿÿÚÿÿÖÿÿÑÿÿÍÿÿÉÿÿÅÿÿÁÿÿ½ÿÿºÿÿ·ÿÿ¸ÿÿ¼ÿÿÁÿÿÅÿÿÉÿÿÍÿÿÑÿÿÖÿÿÚÿÿÞÿÿâ ÿÿã ÿÿàÿÿÜÿÿØÿÿÔÿÿÐÿÿÌÿÿÈÿÿÄÿÿÁÿÿ½ÿÿ¹ÿÿ·ÿÿºÿÿ¾ÿÿÁÿÿÅÿÿÉÿÿÎÿÿÒÿÿÖÿÿÚÿÿßÿÿãÿÿæÿÿêÿÿë ÿÿêÿÿçÿÿãÿÿàÿÿÜÿÿÙÿÿÕÿÿÒÿÿÎÿÿÊÿÿÇÿÿÃÿÿÀÿÿ¼ÿÿ¹ÿÿ¹ÿÿ»ÿÿ¿ÿÿÃÿÿÇÿÿËÿÿÏÿÿÓÿÿ×ÿÿÜÿÿàÿÿäÿÿæ ÿÿëáÿèÿá‚ÿÞÿÿÚÿÿ×ÿÿÓÿÿÐÿÿÌÿÿÉÿÿÅÿÿÁÿÿ¿ÿÿºÿÿ¸ÿÿ·ÿÿºÿÿ½ÿÿÁÿÿÅÿÿÈÿÿÌÿÿÐÿÿÔÿÿ×ÿÿÛÿÿßÿÿßÿÿÛÿÿ×ÿÿÒÿÿÏÿÿÊÿÿÆÿÿÂÿÿ¿ÿÿ»ÿÿ·ÿÿ·ÿÿ»ÿÿ¿ÿÿÃÿÿÆÿÿËÿÿÏÿÿÔÿÿØÿÿÜÿÿàÿÿßÿÿÛÿÿ×ÿÿÒÿÿÎÿÿÊÿÿÆÿÿÂÿÿ¾ÿÿ»ÿÿ·ÿÿ¸ÿÿ»ÿÿÀÿÿÄÿÿÈÿÿÌÿÿÐÿÿÕÿÿÙÿÿÞÿÿâÿÿåÿÿã ÿÿßÿÿÛÿÿ×ÿÿÓÿÿÏÿÿËÿÿÇÿÿÃÿÿÀÿÿ¼ÿÿ¸ÿÿ¸ÿÿ»ÿÿ¾ÿÿÃÿÿÇÿÿËÿÿÏÿÿÔÿÿØÿÿÜÿÿàÿÿä ÿÿçÿÿëÿÿí$ÿÿëÿÿèÿÿå ÿÿáÿÿÝÿÿÚÿÿ×ÿÿÓÿÿÏÿÿËÿÿÈÿÿÄÿÿÁÿÿ½ÿÿ¹ÿÿ¸ÿÿ»ÿÿ¿ÿÿÂÿÿÆÿÿÊÿÿÎÿÿÒÿÿÖÿÿÛÿÿßÿÿãÿÿæ ÿÿíiÿà ÿÝÚÿÙÿÿÖÿÿÒÿÿÏÿÿËÿÿÈÿÿÄÿÿÀÿÿ¾ÿÿºÿÿ·ÿÿ¸ÿÿ»ÿÿ¿ÿÿÂÿÿÆÿÿÉÿÿÍÿÿÑÿÿÕÿÿØÿÿÜÿÿàÿÿáÿÿÝÿÿÙÿÿÕÿÿÑÿÿÍÿÿÉÿÿÅÿÿÁÿÿ½ÿÿ¹ÿÿ·ÿÿ¹ÿÿ½ÿÿÁÿÿÅÿÿÉÿÿÍÿÿÑÿÿÕÿÿÚÿÿÞÿÿáÿÿàÿÿÛÿÿØÿÿÓÿÿÏÿÿËÿÿÇÿÿÃÿÿ¿ÿÿ»ÿÿ¸ÿÿ·ÿÿ»ÿÿÀÿÿÄÿÿÈÿÿËÿÿÐÿÿÕÿÿØÿÿÝÿÿâÿÿåÿÿåÿÿâÿÿÞÿÿÚÿÿÖÿÿÒÿÿÎÿÿÊÿÿÆÿÿÂÿÿ¾ÿÿ»ÿÿ¸ÿÿ¹ÿÿ¼ÿÿÀÿÿÄÿÿÈÿÿÌÿÿÑÿÿÕÿÿÙÿÿÞÿÿâÿÿåÿÿéÿÿì#ÿÿî&ÿÿìÿÿéÿÿæ ÿÿâÿÿßÿÿÛÿÿØÿÿÔÿÿÐÿÿÌÿÿÉÿÿÅÿÿÁÿÿ½ÿÿºÿÿ¸ÿÿºÿÿ¾ÿÿÁÿÿÇÿÿËÿÿÎÿÿÒÿÿÖÿÿÛÿÿßÿÿãÿÿé Çÿ›ÿÛ@ÿØþÿÔÿÿÑÿÿÍÿÿÊÿÿÆÿÿÃÿÿÀÿÿ¼ÿÿ¹ÿÿ·ÿÿ¹ÿÿ¼ÿÿÀÿÿÃÿÿÇÿÿÊÿÿÎÿÿÒÿÿÖÿÿÙÿÿÝÿÿáÿÿâ ÿÿßÿÿÛÿÿÖÿÿÓÿÿÏÿÿËÿÿÇÿÿÂÿÿ¿ÿÿ¼ÿÿ¸ÿÿ·ÿÿºÿÿ¿ÿÿÃÿÿÇÿÿËÿÿÏÿÿÓÿÿØÿÿÜÿÿàÿÿã ÿÿáÿÿÜÿÿØÿÿÔÿÿÐÿÿÌÿÿÈÿÿÄÿÿÀÿÿ¼ÿÿ¸ÿÿ·ÿÿ»ÿÿ¾ÿÿÂÿÿÇÿÿÌÿÿÏÿÿÔÿÿÙÿÿÝÿÿáÿÿåÿÿçÿÿä ÿÿáÿÿÝÿÿÙÿÿÕÿÿÑÿÿÍÿÿÉÿÿÅÿÿÁÿÿ½ÿÿºÿÿ·ÿÿºÿÿ¾ÿÿÂÿÿÆÿÿÊÿÿÎÿÿÒÿÿ×ÿÿÛÿÿàÿÿäÿÿçÿÿëÿÿî'ÿÿï)ÿÿì!ÿÿêÿÿçÿÿâÿÿßÿÿÜÿÿØÿÿÕÿÿÑÿÿÍÿÿÈÿÿÅÿÿÂÿÿ¾ÿÿºÿÿ¸ÿÿºÿÿ¾ÿÿÂÿÿÇÿÿËÿÿÏÿÿÒÿÿÖÿÿÛÿÿàÿÿçùÿ±+ÿ×�ÿÓÿÿÏÿÿÌÿÿÈÿÿÅÿÿÂÿÿ¾ÿÿ»ÿÿ¸ÿÿ¸ÿÿºÿÿ¾ÿÿÁÿÿÅÿÿÈÿÿÌÿÿÏÿÿÓÿÿ×ÿÿÛÿÿÞÿÿâ ÿÿä ÿÿáÿÿÝÿÿÙÿÿÔÿÿÑÿÿÍÿÿÉÿÿÅÿÿÁÿÿ½ÿÿ¹ÿÿ·ÿÿ¹ÿÿ½ÿÿÁÿÿÅÿÿÉÿÿÍÿÿÑÿÿÖÿÿÚÿÿÞÿÿâÿÿäÿÿáÿÿÝÿÿÙÿÿÕÿÿÐÿÿÌÿÿÈÿÿÄÿÿÀÿÿ¼ÿÿ¹ÿÿ·ÿÿºÿÿ¿ÿÿÃÿÿÆÿÿËÿÿÐÿÿÔÿÿØÿÿÝÿÿáÿÿåÿÿèÿÿçÿÿã ÿÿàÿÿÜÿÿØÿÿÔÿÿÐÿÿËÿÿÇÿÿÃÿÿÀÿÿ¼ÿÿ¹ÿÿ¸ÿÿ»ÿÿ¿ÿÿÄÿÿÈÿÿÌÿÿÐÿÿÔÿÿÙÿÿÝÿÿâÿÿæ ÿÿéÿÿí!ÿþð+ÿþï+ÿÿí"ÿÿêÿÿæÿÿãÿÿàÿÿÝÿÿÙÿÿÕÿÿÑÿÿÎÿÿÊÿÿÆÿÿÁÿÿ¿ÿÿºÿÿ¸ÿÿ»ÿÿ¾ÿÿÂÿÿÇÿÿËÿÿÏÿÿÑÿÿÖÿÿÜÿÿãÿÿ³fÿÒµÿÎÿÿÊÿÿÇÿÿÄÿÿÀÿÿ½ÿÿ¹ÿÿ·ÿÿ¹ÿÿ¼ÿÿ¿ÿÿÃÿÿÆÿÿÊÿÿÍÿÿÑÿÿÕÿÿØÿÿÜÿÿàÿÿã ÿÿåÿÿã ÿÿßÿÿÛÿÿ×ÿÿÓÿÿÏÿÿÊÿÿÆÿÿÃÿÿ¿ÿÿ»ÿÿ¸ÿÿ¸ÿÿ»ÿÿ¿ÿÿÃÿÿÇÿÿÌÿÿÏÿÿÔÿÿØÿÿÜÿÿàÿÿäÿÿåÿÿâÿÿÝÿÿÙÿÿÕÿÿÑÿÿÍÿÿÉÿÿÄÿÿÀÿÿ½ÿÿ¹ÿÿ·ÿÿºÿÿ¿ÿÿÃÿÿÆÿÿËÿÿÐÿÿÓÿÿØÿÿÝÿÿáÿÿå ÿÿéÿÿéÿÿæÿÿâÿÿÞÿÿÚÿÿÖÿÿÒÿÿÎÿÿÊÿÿÆÿÿÂÿÿ¿ÿÿ»ÿÿ¸ÿÿ¹ÿÿ½ÿÿÁÿÿÅÿÿÉÿÿÎÿÿÒÿÿÖÿÿÛÿÿàÿÿäÿÿçÿÿëÿÿî&ÿýñ0ÿýð-ÿÿí#ÿÿëÿÿèÿÿåÿÿáÿÿÜÿÿÙÿÿÖÿÿÒÿÿÎÿÿÉÿÿÅÿÿÂÿÿ¾ÿÿ»ÿÿ¹ÿÿºÿÿ¾ÿÿÂÿÿÆÿÿÊÿÿÎÿÿÓÿÿØÿÿßÿÿ´�ÿÌÕÿÉÿÿÅÿÿÂÿÿ¿ÿÿ»ÿÿ¸ÿÿ¸ÿÿºÿÿ¾ÿÿÁÿÿÄÿÿÈÿÿËÿÿÏÿÿÓÿÿÖÿÿÚÿÿÝÿÿáÿÿåÿÿæÿÿä ÿÿàÿÿÜÿÿØÿÿÔÿÿÐÿÿÌÿÿÈÿÿÄÿÿÀÿÿ½ÿÿ¹ÿÿ·ÿÿºÿÿ¾ÿÿÂÿÿÆÿÿÊÿÿÎÿÿÒÿÿ×ÿÿÛÿÿßÿÿã ÿÿæÿÿæÿÿâÿÿÝÿÿÙÿÿÕÿÿÑÿÿÍÿÿÉÿÿÅÿÿÁÿÿ½ÿÿ¹ÿÿ·ÿÿºÿÿ¿ÿÿÃÿÿÆÿÿËÿÿÐÿÿÓÿÿØÿÿÝÿÿáÿÿå ÿÿéÿÿëÿÿèÿÿä ÿÿáÿÿÝÿÿÙÿÿÕÿÿÑÿÿÌÿÿÈÿÿÄÿÿÁÿÿ½ÿÿ¹ÿÿ¸ÿÿ»ÿÿ¿ÿÿÃÿÿÇÿÿÌÿÿÐÿÿÔÿÿÙÿÿÝÿÿáÿÿæ ÿÿéÿÿí!ÿþð,ÿúò3ÿýñ.ÿÿî$ÿÿëÿÿèÿÿå ÿÿáÿÿÞÿÿÛÿÿÕÿÿÑÿÿÍÿÿÉÿÿÅÿÿÂÿÿ¿ÿÿ»ÿÿ¹ÿÿ»ÿÿ¿ÿÿÂÿÿÆÿÿËÿÿÏÿÿÓÿÿÚÿÿ´¾ÿÇéÿÃÿÿÀÿÿ½ÿÿºÿÿ·ÿÿ¹ÿÿ¼ÿÿ¿ÿÿÃÿÿÆÿÿÊÿÿÍÿÿÑÿÿÔÿÿØÿÿÜÿÿßÿÿã ÿÿæÿÿèÿÿåÿÿáÿÿÞÿÿÚÿÿÖÿÿÑÿÿÍÿÿÊÿÿÆÿÿÂÿÿ¾ÿÿºÿÿ·ÿÿ¸ÿÿ¼ÿÿÀÿÿÅÿÿÈÿÿÌÿÿÑÿÿÕÿÿÙÿÿÝÿÿáÿÿåÿÿèÿÿæÿÿáÿÿÝÿÿÙÿÿÕÿÿÑÿÿÍÿÿÉÿÿÅÿÿÁÿÿ½ÿÿ¹ÿÿ·ÿÿºÿÿ¿ÿÿÃÿÿÆÿÿËÿÿÐÿÿÔÿÿÙÿÿÝÿÿáÿÿå ÿÿéÿÿì!ÿÿêÿÿçÿÿãÿÿßÿÿÛÿÿ×ÿÿÓÿÿÏÿÿËÿÿÇÿÿÂÿÿ¿ÿÿ»ÿÿ¸ÿÿ¹ÿÿ½ÿÿÁÿÿÅÿÿÊÿÿÍÿÿÒÿÿ×ÿÿÛÿÿàÿÿäÿÿèÿÿëÿÿï&ÿüò2ÿøó6ÿýò/ÿÿî%ÿÿëÿÿéÿÿå ÿÿâÿÿßÿÿÙÿÿÕÿÿÑÿÿÍÿÿÉÿÿÆÿÿÂÿÿ¿ÿÿ»ÿÿ¹ÿÿ»ÿÿ¿ÿÿÃÿÿÇÿÿËÿÿÏÿÿ×ÿÿ´ÕÿÂëÿ¾ÿÿ»ÿÿ¸ÿÿ¸ÿÿ»ÿÿ¾ÿÿÁÿÿÅÿÿÈÿÿÌÿÿÏÿÿÓÿÿ×ÿÿÚÿÿÞÿÿáÿÿä ÿÿèÿÿéÿÿæÿÿãÿÿßÿÿÛÿÿ×ÿÿÓÿÿÏÿÿËÿÿÇÿÿÃÿÿ¿ÿÿ¼ÿÿ¸ÿÿ¸ÿÿ»ÿÿ¿ÿÿÃÿÿÇÿÿËÿÿÏÿÿÔÿÿØÿÿÜÿÿàÿÿä ÿÿèÿÿéÿÿæÿÿáÿÿÞÿÿÚÿÿÕÿÿÑÿÿÍÿÿÉÿÿÅÿÿÁÿÿ½ÿÿ¹ÿÿ¸ÿÿ»ÿÿ¾ÿÿÂÿÿÇÿÿÌÿÿÏÿÿÔÿÿÙÿÿÝÿÿâÿÿæÿÿéÿÿì#ÿÿì!ÿÿéÿÿæ ÿÿâÿÿÝÿÿÙÿÿÕÿÿÑÿÿÍÿÿÉÿÿÅÿÿÁÿÿ½ÿÿ¹ÿÿ¸ÿÿ»ÿÿÀÿÿÃÿÿÈÿÿÌÿÿÐÿÿÕÿÿÙÿÿÞÿÿâÿÿæ ÿÿêÿÿí"ÿþð-ÿøô8ÿøî5ÿýó/ÿÿô'ÿÿðÿÿêÿÿå ÿÿâÿÿÞÿÿÙÿÿÕÿÿÑÿÿÍÿÿÉÿÿÅÿÿÂÿÿ¾ÿÿºÿÿ¹ÿÿ»ÿÿÀÿÿÄÿÿÈÿÿÌÿÿÓÿÿ´âÿ¼êÿ¹ÿÿ¸ÿÿºÿÿ½ÿÿÀÿÿÄÿÿÇÿÿÊÿÿÎÿÿÑÿÿÖÿÿÙÿÿÜÿÿàÿÿãÿÿæÿÿéÿÿêÿÿçÿÿä ÿÿàÿÿÜÿÿØÿÿÔÿÿÐÿÿÌÿÿÈÿÿÄÿÿÁÿÿ½ÿÿ¹ÿÿ·ÿÿºÿÿ¾ÿÿÂÿÿÆÿÿÊÿÿÎÿÿÒÿÿ×ÿÿÛÿÿßÿÿãÿÿæÿÿêÿÿéÿÿæÿÿáÿÿÝÿÿÙÿÿÕÿÿÑÿÿÍÿÿÊÿÿÅÿÿÁÿÿ½ÿÿ¹ÿÿ¸ÿÿ»ÿÿÀÿÿÄÿÿÇÿÿËÿÿÐÿÿÕÿÿÙÿÿÞÿÿâÿÿæÿÿêÿÿí$ÿÿí&ÿÿêÿÿçÿÿãÿÿàÿÿÜÿÿØÿÿÓÿÿÐÿÿËÿÿÇÿÿÃÿÿ¿ÿÿ»ÿÿ¸ÿÿºÿÿ¾ÿÿÂÿÿÆÿÿÊÿÿÏÿÿÓÿÿØÿÿÜÿÿáÿÿå ÿÿéÿÿìÿÿñ)ÿüç.ÿý„ ÿþ� ÿÿ±ÿÿÏÿÿäÿÿìÿÿé ÿÿãÿÿÞÿÿÚÿÿÖÿÿÒÿÿÎÿÿÊÿÿÅÿÿÁÿÿ¾ÿÿºÿÿ¹ÿÿ¼ÿÿÀÿÿÄÿÿÈÿÿÏÿÿµïÿ¸õÿ¹ÿÿ¼ÿÿ¿ÿÿÃÿÿÆÿÿÉÿÿÍÿÿÐÿÿÔÿÿ×ÿÿÛÿÿßÿÿâÿÿå ÿÿèÿÿëÿÿëÿÿèÿÿä ÿÿáÿÿÝÿÿÙÿÿÕÿÿÑÿÿÍÿÿÉÿÿÅÿÿÂÿÿ¾ÿÿºÿÿ¸ÿÿ¹ÿÿ½ÿÿÁÿÿÅÿÿÉÿÿÍÿÿÑÿÿÖÿÿÚÿÿÞÿÿâÿÿæÿÿéÿÿì ÿÿéÿÿæÿÿâÿÿÝÿÿÙÿÿÕÿÿÒÿÿÍÿÿÉÿÿÄÿÿÀÿÿ¼ÿÿ¹ÿÿ¸ÿÿ»ÿÿÀÿÿÄÿÿÈÿÿÍÿÿÑÿÿÕÿÿÚÿÿÞÿÿâÿÿæÿÿêÿÿî%ÿÿï*ÿÿì ÿÿéÿÿå ÿÿâÿÿÞÿÿÙÿÿÕÿÿÑÿÿÍÿÿÈÿÿÄÿÿÀÿÿ½ÿÿ¹ÿÿ¸ÿÿ¼ÿÿÁÿÿÄÿÿÈÿÿÍÿÿÑÿÿÖÿÿÚÿÿßÿÿãÿÿçÿÿëÿÿó&ÿÿ¯ÿÿgÿÿgÿÿiÿÿqÿÿ„ÿÿžÿÿÀ ÿÿÙÿÿâÿÿâÿÿÛÿÿÖÿÿÑÿÿÍÿÿÉÿÿÅÿÿÁÿÿ¾ÿÿºÿÿ¹ÿÿ½ÿÿÁÿÿÅÿÿËÿÿ°ÿÿ»ÿÿ¿ÿÿÂÿÿÅÿÿÈÿÿÌÿÿÏÿÿÓÿÿÖÿÿÚÿÿÞÿÿáÿÿä ÿÿçÿÿêÿÿì#ÿÿì!ÿÿéÿÿåÿÿâÿÿÞÿÿÚÿÿÖÿÿÒÿÿÎÿÿÊÿÿÆÿÿÂÿÿ¿ÿÿ»ÿÿ¸ÿÿ¹ÿÿ¼ÿÿÀÿÿÄÿÿÈÿÿÌÿÿÐÿÿÕÿÿÙÿÿÝÿÿáÿÿå ÿÿèÿÿì!ÿÿì!ÿÿéÿÿå ÿÿâÿÿÝÿÿÙÿÿÕÿÿÑÿÿÌÿÿÈÿÿÄÿÿÀÿÿ¼ÿÿ¸ÿÿ¸ÿÿ¼ÿÿÁÿÿÄÿÿÉÿÿÍÿÿÒÿÿÖÿÿÚÿÿßÿÿãÿÿçÿÿëÿÿî'ÿþð-ÿÿî%ÿÿêÿÿçÿÿäÿÿßÿÿÛÿÿ×ÿÿÓÿÿÏÿÿËÿÿÆÿÿÂÿÿ¾ÿÿ»ÿÿ¸ÿÿºÿÿ¿ÿÿÃÿÿÇÿÿÌÿÿÐÿÿÔÿÿÙÿÿÞÿÿâÿÿæ ÿÿíÿÿÙÿÿwÿÿnÿÿjÿÿkÿÿoÿÿqÿÿtÿÿyÿÿ…ÿÿ™ÿÿ¸ÿÿÏÿÿÙÿÿ×ÿÿÒÿÿÍÿÿÈÿÿÄÿÿÀÿÿ½ÿÿ¹ÿÿºÿÿ¾ÿÿÂÿÿÇÿÿ«ÿÿÁÿÿÄÿÿÈÿÿËÿÿÏÿÿÒÿÿÖÿÿÙÿÿÝÿÿàÿÿãÿÿæÿÿéÿÿì"ÿÿî'ÿÿì"ÿÿéÿÿæÿÿâÿÿßÿÿÛÿÿ×ÿÿÓÿÿÏÿÿËÿÿÇÿÿÃÿÿÀÿÿ¼ÿÿ¸ÿÿ¸ÿÿ¼ÿÿ¿ÿÿÃÿÿÈÿÿÌÿÿÏÿÿÔÿÿØÿÿÜÿÿàÿÿä ÿÿèÿÿëÿÿî&ÿÿì ÿÿèÿÿå ÿÿàÿÿÜÿÿØÿÿÔÿÿÐÿÿÌÿÿÈÿÿÃÿÿ¿ÿÿ¼ÿÿ¸ÿÿ¹ÿÿ½ÿÿÁÿÿÅÿÿÉÿÿÎÿÿÒÿÿ×ÿÿÛÿÿàÿÿäÿÿèÿÿëÿÿï(ÿýñ0ÿÿï(ÿÿìÿÿéÿÿå ÿÿáÿÿÝÿÿÙÿÿÕÿÿÑÿÿÌÿÿÈÿÿÄÿÿÀÿÿ¼ÿÿ¹ÿÿ¹ÿÿ½ÿÿÂÿÿÆÿÿÊÿÿÎÿÿÓÿÿ×ÿÿÜÿÿáÿÿåÿÿíÿÿ¤ ÿÿqÿÿqÿÿlÿÿiÿÿkÿÿpÿÿtÿÿxÿÿ|ÿÿ~ÿÿ�ÿÿŒÿÿžÿÿ²ÿÿÉÿÿÐÿÿÎÿÿÈÿÿÃÿÿÀÿÿ¼ÿÿ¹ÿÿ»ÿÿ¿ÿÿÃÿÿ­ÿÿÇÿÿËÿÿÎÿÿÒÿÿÕÿÿÙÿÿÜÿÿàÿÿãÿÿæÿÿéÿÿìÿÿî'ÿÿï*ÿÿí#ÿÿêÿÿæÿÿãÿÿßÿÿÜÿÿØÿÿÔÿÿÏÿÿËÿÿÇÿÿÄÿÿÀÿÿ¼ÿÿ¹ÿÿ¸ÿÿ»ÿÿ¿ÿÿÃÿÿÇÿÿËÿÿÏÿÿÓÿÿ×ÿÿÜÿÿàÿÿäÿÿçÿÿêÿÿî&ÿÿî'ÿÿëÿÿèÿÿä ÿÿàÿÿÜÿÿØÿÿÔÿÿÐÿÿËÿÿÇÿÿÃÿÿ¿ÿÿ»ÿÿ¸ÿÿºÿÿ¾ÿÿÂÿÿÆÿÿËÿÿÏÿÿÓÿÿØÿÿÜÿÿáÿÿå ÿÿéÿÿìÿÿï*ÿûò3ÿþð-ÿÿí"ÿÿêÿÿçÿÿãÿÿßÿÿÛÿÿÖÿÿÒÿÿÎÿÿÊÿÿÅÿÿÁÿÿ½ÿÿ¹ÿÿ¹ÿÿ¼ÿÿÁÿÿÄÿÿÉÿÿÍÿÿÒÿÿÖÿÿÛÿÿßÿÿèÿÿÍ ÿÿ|ÿÿvÿÿrÿÿmÿÿhÿÿhÿÿlÿÿqÿÿuÿÿyÿÿ}ÿÿ‚ÿÿ†ÿÿˆÿÿŒÿÿ•ÿÿ¥ÿÿ·ÿÿÄÿÿÈÿÿÄÿÿ¿ÿÿ»ÿÿ¹ÿÿ½ÿÿ¿ÿÿ«ÿÿÎÿÿÑÿÿÕÿÿØÿÿÜÿÿßÿÿâÿÿæ ÿÿèÿÿëÿÿî%ÿþð-ÿþð,ÿÿí#ÿÿêÿÿçÿÿãÿÿàÿÿÜÿÿØÿÿÓÿÿÏÿÿÌÿÿÈÿÿÄÿÿÁÿÿ½ÿÿ¹ÿÿ¸ÿÿ»ÿÿ¿ÿÿÂÿÿÆÿÿÊÿÿÏÿÿÓÿÿØÿÿÜÿÿàÿÿãÿÿçÿÿêÿÿí$ÿÿð,ÿÿî%ÿÿëÿÿçÿÿäÿÿßÿÿÛÿÿ×ÿÿÓÿÿÏÿÿÊÿÿÆÿÿÂÿÿ¾ÿÿºÿÿ¸ÿÿ»ÿÿ¿ÿÿÃÿÿÇÿÿËÿÿÐÿÿÔÿÿÙÿÿÝÿÿâÿÿæ ÿÿêÿÿí"ÿþñ-ÿùó6ÿýñ0ÿÿî&ÿÿëÿÿèÿÿäÿÿàÿÿÜÿÿØÿÿÔÿÿÐÿÿËÿÿÇÿÿÃÿÿ¾ÿÿ»ÿÿ¸ÿÿ»ÿÿÀÿÿÃÿÿÈÿÿÌÿÿÑÿÿÕÿÿÚÿÿßÿÿáÿÿ—ÿÿzÿÿxÿÿsÿÿnÿÿiÿÿfÿÿiÿÿnÿÿrÿÿvÿÿzÿÿ~ÿÿƒÿÿ‡ÿÿŒÿÿ�ÿÿ“ÿÿ—ÿÿ ÿÿ®ÿÿºÿÿÀÿÿ¿ÿÿ»ÿÿ»ÿÿ»ÿÿ­ÿÿÕÿÿØÿÿÜÿÿßÿÿâÿÿå ÿÿèÿÿëÿÿî$ÿýð-ÿüñ1ÿþð,ÿÿí"ÿÿêÿÿçÿÿäÿÿàÿÿÜÿÿØÿÿÔÿÿÑÿÿÌÿÿÈÿÿÅÿÿÁÿÿ½ÿÿ¹ÿÿ¸ÿÿºÿÿ¾ÿÿÂÿÿÆÿÿÊÿÿÎÿÿÒÿÿ×ÿÿÜÿÿßÿÿãÿÿæÿÿêÿÿí#ÿþð-ÿþð-ÿÿí#ÿÿêÿÿæÿÿãÿÿÞÿÿÛÿÿÖÿÿÒÿÿÎÿÿÊÿÿÅÿÿÁÿÿ½ÿÿ¹ÿÿ¸ÿÿ¼ÿÿÀÿÿÄÿÿÈÿÿÌÿÿÑÿÿÖÿÿÚÿÿßÿÿãÿÿçÿÿëÿÿî$ÿýó0ÿ÷ù;ÿûö4ÿÿð(ÿÿìÿÿéÿÿæ ÿÿáÿÿÝÿÿÚÿÿÕÿÿÑÿÿÌÿÿÈÿÿÄÿÿÀÿÿ¼ÿÿ¹ÿÿºÿÿ¿ÿÿÂÿÿÇÿÿËÿÿÐÿÿÔÿÿÙÿÿáÿÿ´ÿÿÿÿ~ÿÿyÿÿtÿÿoÿÿkÿÿfÿÿfÿÿjÿÿoÿÿsÿÿwÿÿ{ÿÿ€ÿÿ„ÿÿˆÿÿ�ÿÿ’ÿÿ–ÿÿ›ÿÿžÿÿ¤ÿÿ¬ÿÿ´ÿÿºÿÿºÿÿ¸ÿÿ°ÿÿÛÿÿßÿÿâÿÿå ÿÿèÿÿëÿÿí#ÿþð+ÿûò3ÿûò4ÿþð+ÿÿí"ÿÿêÿÿçÿÿäÿÿàÿÿÜÿÿØÿÿÕÿÿÑÿÿÍÿÿÉÿÿÄÿÿÁÿÿ½ÿÿºÿÿ¸ÿÿºÿÿ¿ÿÿÂÿÿÆÿÿËÿÿÏÿÿÒÿÿÖÿÿÚÿÿßÿÿâÿÿæÿÿêÿÿí"ÿþð,ÿüò2ÿÿï*ÿÿì ÿÿéÿÿå ÿÿáÿÿÝÿÿÙÿÿÕÿÿÑÿÿÍÿÿÈÿÿÄÿÿÀÿÿ¼ÿÿ¹ÿÿ¹ÿÿ½ÿÿÁÿÿÅÿÿÉÿÿÎÿÿÓÿÿ×ÿÿÛÿÿàÿÿäÿÿèÿÿìÿÿó)ÿüê/ÿú®ÿüÍ&ÿÿò,ÿÿò"ÿÿêÿÿç ÿÿãÿÿßÿÿÚÿÿÖÿÿÒÿÿÎÿÿÉÿÿÅÿÿÁÿÿ½ÿÿ¹ÿÿ¹ÿÿ½ÿÿÂÿÿÆÿÿÊÿÿÏÿÿÓÿÿÚÿÿËÿÿ‹ÿÿƒÿÿÿÿzÿÿuÿÿqÿÿlÿÿgÿÿdÿÿgÿÿlÿÿpÿÿtÿÿxÿÿ|ÿÿ�ÿÿ…ÿÿŠÿÿŽÿÿ“ÿÿ˜ÿÿœÿÿ¡ÿÿ¦ÿÿªÿÿ°ÿÿ¶ÿÿ·ÿÿ³ÿÿâÿÿæ ÿÿêÿÿïÿÿó$ÿþõ-ÿúô4ÿ÷ô8ÿûò4ÿÿð*ÿÿí!ÿÿêÿÿçÿÿäÿÿàÿÿÜÿÿ×ÿÿÔÿÿÑÿÿÍÿÿÈÿÿÅÿÿÁÿÿ½ÿÿºÿÿ¸ÿÿ»ÿÿ¾ÿÿÂÿÿÆÿÿÊÿÿÎÿÿÒÿÿÖÿÿÛÿÿÞÿÿâÿÿæ ÿÿêÿÿí!ÿþð+ÿùò5ÿüñ1ÿÿï&ÿÿëÿÿèÿÿåÿÿàÿÿÜÿÿØÿÿÔÿÿÐÿÿËÿÿÇÿÿÃÿÿ¿ÿÿ»ÿÿ¸ÿÿºÿÿ¿ÿÿÃÿÿÇÿÿËÿÿÏÿÿÔÿÿÙÿÿÝÿÿâÿÿæ ÿÿêÿÿò"ÿÿÞ$ÿþ‹ ÿÿdÿÿmÿÿ” ÿÿÎÿÿíÿÿëÿÿäÿÿàÿÿÜÿÿØÿÿÓÿÿÏÿÿËÿÿÆÿÿÂÿÿ¾ÿÿºÿÿ¹ÿÿ¼ÿÿÁÿÿÅÿÿÉÿÿÎÿÿÓÿÿÖÿÿžÿÿ‡ÿÿ…ÿÿ€ÿÿ{ÿÿvÿÿqÿÿmÿÿhÿþcÿþdÿÿhÿÿmÿÿqÿÿuÿÿzÿÿ~ÿÿƒÿÿ‡ÿÿŒÿÿ�ÿÿ•ÿÿšÿÿžÿÿ£ÿÿ¨ÿÿ­ÿÿ²ÿÿ¶ÿÿ¶ÿÿîÿÿëÿÿâÿÿÑÿþ¹ÿýœÿû¨ÿüô3ÿÿð)ÿÿíÿÿêÿÿçÿÿãÿÿàÿÿÝÿÿ×ÿÿÓÿÿÏÿÿÌÿÿÉÿÿÅÿÿÀÿÿ½ÿÿºÿÿ¸ÿÿ»ÿÿ¿ÿÿÃÿÿÆÿÿÊÿÿÏÿÿÓÿÿ×ÿÿÛÿÿàÿÿâÿÿæ ÿÿêÿÿí!ÿþô,ÿùø7ÿøô7ÿþð,ÿÿî#ÿÿêÿÿçÿÿãÿÿßÿÿÛÿÿ×ÿÿÓÿÿÎÿÿÊÿÿÆÿÿÂÿÿ¾ÿÿºÿÿ¹ÿÿ¼ÿÿÀÿÿÄÿÿÈÿÿÍÿÿÑÿÿÖÿÿÚÿÿßÿÿãÿÿéÿÿïÿÿÆÿÿ|ÿÿjÿÿjÿÿmÿÿnÿÿuÿÿ™ÿÿÌ ÿÿæÿÿãÿÿÝÿÿØÿÿÔÿÿÐÿÿËÿÿÇÿÿÃÿÿ¾ÿÿºÿÿ¹ÿÿ¼ÿÿÁÿÿÄÿÿÉÿÿÎÿÿÕÿÿ´ÿÿ�ÿÿ‹ÿÿ†ÿÿ�ÿÿ|ÿÿwÿÿrÿÿmÿÿhÿþcÿübÿÿeÿÿjÿÿnÿÿrÿÿwÿÿ{ÿÿ€ÿÿ„ÿÿ‰ÿÿŽÿÿ’ÿÿ—ÿÿœÿÿ ÿÿ¥ÿÿªÿÿ¯ÿÿ´ÿÿ·ÿÿ«ÿÿ�ÿÿyÿÿlÿÿgÿÿhÿÿwÿÿâ"ÿÿîÿÿêÿÿæ ÿÿãÿÿßÿÿÛÿÿØÿÿÔÿÿÐÿÿÌÿÿÇÿÿÄÿÿÁÿÿ½ÿÿºÿÿ¹ÿÿ»ÿÿ¿ÿÿÂÿÿÇÿÿËÿÿÏÿÿÓÿÿ×ÿÿÜÿÿàÿÿäÿÿæ ÿÿëÿÿò#ÿþñ,ÿüÒ'ÿù½#ÿûñ2ÿÿñ)ÿÿìÿÿêÿÿå ÿÿâÿÿÞÿÿÚÿÿÖÿÿÑÿÿÍÿÿÈÿÿÄÿÿÀÿÿ¼ÿÿ¹ÿÿ¹ÿÿ½ÿÿÂÿÿÅÿÿÊÿÿÏÿÿÓÿÿ×ÿÿÜÿÿáÿÿèÿÿãÿÿª ÿÿuÿÿoÿÿlÿÿiÿÿlÿÿqÿÿuÿÿvÿÿ}ÿÿŸÿÿÒÿÿàÿÿÛÿÿÕÿÿÐÿÿÌÿÿÈÿÿÃÿÿ¿ÿÿ»ÿÿ¹ÿÿ»ÿÿÀÿÿÄÿÿÈÿÿÏÿÿÁÿÿ•ÿÿ�ÿÿ‹ÿÿ†ÿÿ�ÿÿ|ÿÿxÿÿsÿÿnÿÿiÿþdÿû`ÿþcÿÿgÿÿlÿÿpÿÿtÿÿyÿÿ}ÿÿ‚ÿÿ†ÿÿ‹ÿÿ�ÿÿ”ÿÿ™ÿÿžÿÿ£ÿÿ§ÿÿ¬ÿÿ±ÿÿ¶ÿÿkÿÿiÿÿiÿÿkÿÿoÿÿsÿÿsÿÿÇÿÿíÿÿæ ÿÿâÿÿÞÿÿÛÿÿ×ÿÿÓÿÿÏÿÿËÿÿÈÿÿÄÿÿÁÿÿ¼ÿÿ¹ÿÿ¹ÿÿ¼ÿÿÀÿÿÄÿÿÇÿÿÌÿÿÐÿÿÔÿÿØÿÿÜÿÿàÿÿãÿÿêÿÿïÿÿç ÿÿÃÿÿ‘ÿÿjÿÿgÿÿ¥ÿÿð%ÿÿìÿÿèÿÿäÿÿàÿÿÜÿÿØÿÿÔÿÿÏÿÿËÿÿÇÿÿÂÿÿ¿ÿÿ»ÿÿ¸ÿÿ»ÿÿÀÿÿÃÿÿÈÿÿÌÿÿÐÿÿÕÿÿÙÿÿÞÿÿæÿÿÑÿÿ’ÿÿsÿÿsÿÿoÿÿjÿÿhÿÿlÿÿqÿÿuÿÿzÿÿ~ÿÿÿÿŠÿÿ®ÿÿÔÿÿØÿÿÒÿÿÍÿÿÈÿÿÄÿÿÀÿÿ¼ÿÿ¹ÿÿ»ÿÿÀÿÿÃÿÿÉÿÿÈÿÿ ÿÿ•ÿÿ‘ÿÿŒÿÿ‡ÿÿ‚ÿÿ}ÿÿxÿÿsÿÿnÿÿiÿÿeÿú`ÿû`ÿÿeÿÿiÿÿmÿÿrÿÿvÿÿ{ÿÿÿÿ„ÿÿˆÿÿ�ÿÿ’ÿÿ–ÿÿ›ÿÿ ÿÿ¥ÿÿªÿÿ¯ÿÿ´ÿÿiÿÿiÿÿlÿÿpÿÿtÿÿxÿÿwÿÿ±ÿÿéÿÿáÿÿÞÿÿÚÿÿÖÿÿÓÿÿÎÿÿËÿÿÇÿÿÃÿÿÀÿÿ¼ÿÿ¹ÿÿ¹ÿÿ½ÿÿÁÿÿÄÿÿÈÿÿÍÿÿÑÿÿÕÿÿÙÿÿÜÿÿâÿÿéÿÿéÿÿÖÿÿ­ÿÿ�ÿÿkÿÿgÿÿkÿÿpÿÿpÿÿ§ ÿÿêÿÿç ÿÿâÿÿÞÿÿÛÿÿÖÿÿÒÿÿÎÿÿÉÿÿÅÿÿÁÿÿ½ÿÿ¹ÿÿ¹ÿÿ½ÿÿÁÿÿÅÿÿÊÿÿÎÿÿÓÿÿ×ÿÿÞÿÿáÿÿ¹ÿÿ‚ÿÿyÿÿwÿÿrÿÿmÿÿiÿÿgÿÿkÿÿpÿÿtÿÿyÿÿ~ÿÿ‚ÿÿ†ÿÿˆÿÿ˜ÿÿ¿ÿÿÓÿÿÏÿÿÉÿÿÄÿÿÀÿÿ¼ÿÿ¹ÿÿ»ÿÿÀÿÿÄÿÿÇÿÿªÿÿšÿÿ–ÿÿ‘ÿÿŒÿÿ‡ÿÿ‚ÿÿ}ÿÿxÿÿsÿÿnÿÿjÿÿeÿú`ÿø^ÿþbÿÿgÿÿkÿÿoÿÿtÿÿxÿÿ}ÿÿ�ÿÿ†ÿÿ‹ÿÿ�ÿÿ”ÿÿ™ÿÿžÿÿ£ÿÿ§ÿÿ­ÿÿ±ÿÿjÿÿnÿÿrÿÿvÿÿzÿÿ}ÿÿ~ÿÿŸÿÿãÿÿÝÿÿÙÿÿÕÿÿÑÿÿÎÿÿÊÿÿÆÿÿÃÿÿ¿ÿÿ»ÿÿ¹ÿÿºÿÿ½ÿÿÁÿÿÅÿÿÉÿÿÍÿÿÑÿÿÕÿÿÚÿÿàÿÿåÿÿÜÿÿÀ ÿÿ˜ÿÿyÿÿnÿÿmÿÿjÿÿjÿÿnÿÿrÿÿwÿÿvÿÿ´ÿÿêÿÿáÿÿÝÿÿÙÿÿÔÿÿÐÿÿÌÿÿÇÿÿÃÿÿ¿ÿÿ»ÿÿ¹ÿÿ»ÿÿ¿ÿÿÃÿÿÇÿÿÌÿÿÐÿÿÕÿÿÝÿÿÑÿÿ ÿÿ€ÿÿ}ÿÿyÿÿuÿÿpÿÿkÿÿfÿÿgÿÿlÿÿpÿÿtÿÿyÿÿ}ÿÿ‚ÿÿ‡ÿÿ‹ÿÿ�ÿÿ”ÿÿªÿÿÆÿÿËÿÿÅÿÿÀÿÿ¼ÿÿ¹ÿÿ»ÿÿÀÿÿÄÿÿ²ÿÿŸÿÿ›ÿÿ–ÿÿ‘ÿÿŒÿÿ‡ÿÿ‚ÿÿ}ÿÿxÿÿtÿÿoÿÿjÿÿeÿû`ÿ÷]ÿû`ÿÿdÿÿiÿÿmÿÿrÿÿvÿÿzÿÿÿÿ„ÿÿˆÿÿ�ÿÿ’ÿÿ—ÿÿ›ÿÿ ÿÿ¥ÿÿ«ÿÿ¯ÿÿoÿÿsÿÿwÿÿ{ÿÿÿÿƒÿÿ„ÿÿžÿÿÝÿÿØÿÿÔÿÿÐÿÿÌÿÿÉÿÿÅÿÿÂÿÿ¾ÿÿºÿÿ¹ÿÿ»ÿÿ¾ÿÿÂÿÿÆÿÿÊÿÿÎÿÿÒÿÿØÿÿÞÿÿÜÿÿÍÿÿ©ÿÿˆÿÿwÿÿsÿÿrÿÿnÿÿiÿÿhÿÿlÿÿpÿÿuÿÿyÿÿ}ÿÿ‚ÿÿ¾ÿÿâÿÿÛÿÿ×ÿÿÒÿÿÎÿÿÉÿÿÅÿÿÁÿÿ½ÿÿºÿÿ¹ÿÿ½ÿÿÁÿÿÅÿÿÊÿÿÎÿÿÕÿÿÖÿÿºÿÿ�ÿÿ‚ÿÿ€ÿÿ|ÿÿwÿÿrÿÿnÿÿiÿÿdÿÿfÿÿkÿÿoÿÿtÿÿyÿÿ}ÿÿ‚ÿÿ†ÿÿ‹ÿÿ�ÿÿ•ÿÿ—ÿÿ¡ÿÿ¹ÿÿÆÿÿÂÿÿ½ÿÿºÿÿ»ÿÿÁÿÿ¶ÿÿ¤ÿÿ ÿÿ›ÿÿ–ÿÿ‘ÿÿŒÿÿ‡ÿÿ‚ÿÿ}ÿÿxÿÿtÿÿoÿÿjÿÿeÿû`ÿõ\ÿø]ÿþbÿÿgÿÿjÿÿoÿÿtÿÿyÿÿ}ÿÿ�ÿÿ‡ÿÿ‹ÿÿ�ÿÿ•ÿÿšÿÿžÿÿ¤ÿÿ©ÿÿ­ÿÿuÿÿxÿÿ}ÿÿ€ÿÿ„ÿÿ‰ÿÿ‹ÿÿ—ÿÿÒÿÿÔÿÿÏÿÿÌÿÿÈÿÿÄÿÿÀÿÿ½ÿÿºÿÿºÿÿ¼ÿÿÀÿÿÃÿÿÇÿÿËÿÿÑÿÿ×ÿÿØÿÿÎÿÿ´ÿÿ”ÿÿƒÿÿ{ÿÿyÿÿvÿÿqÿÿmÿÿiÿÿgÿÿjÿÿoÿÿsÿÿwÿÿ|ÿÿ€ÿÿ„ÿÿˆÿÿÆÿÿÛÿÿÔÿÿÐÿÿÌÿÿÇÿÿÃÿÿ¿ÿÿ»ÿÿ¹ÿÿ»ÿÿ¿ÿÿÄÿÿÈÿÿÍÿÿÓÿÿÇÿÿ ÿÿŠÿÿ‡ÿÿƒÿÿ~ÿÿyÿÿuÿÿpÿÿkÿÿfÿÿcÿÿfÿÿkÿÿoÿÿtÿÿyÿÿ}ÿÿ‚ÿÿ†ÿÿ‹ÿÿ�ÿÿ•ÿÿšÿÿ�ÿÿ¢ÿÿ²ÿÿÀÿÿ¾ÿÿºÿÿ¼ÿÿ¹ÿÿªÿÿ¥ÿÿ ÿÿ›ÿÿ–ÿÿ‘ÿÿŒÿÿ‡ÿÿ‚ÿÿ}ÿÿxÿÿsÿÿoÿÿjÿÿeÿû`ÿõ[ÿõ[ÿû`ÿÿeÿÿhÿÿmÿÿrÿÿwÿÿ{ÿÿÿÿ…ÿÿ‰ÿÿŽÿÿ’ÿÿ—ÿÿœÿÿ¡ÿÿ§ÿÿ«ÿÿzÿÿ~ÿÿ‚ÿÿ†ÿÿŠÿÿŽÿÿ’ÿÿ›ÿÿÍÿÿÎÿÿÊÿÿÆÿÿÃÿÿ¿ÿÿ¼ÿÿ¹ÿÿºÿÿ¾ÿÿÁÿÿÅÿÿÊÿÿÏÿÿÓÿÿÊÿÿ·ÿÿŸÿÿŒÿÿƒÿÿÿÿ}ÿÿyÿÿtÿÿpÿÿlÿÿhÿÿeÿÿhÿÿmÿÿqÿÿuÿÿzÿÿ~ÿÿƒÿÿ‡ÿÿŠÿÿ—ÿÿÏÿÿÓÿÿÍÿÿÉÿÿÅÿÿÁÿÿ½ÿÿºÿÿºÿÿ¾ÿÿÂÿÿÆÿÿÌÿÿËÿÿ´ÿÿ•ÿÿ�ÿÿŠÿÿ…ÿÿ€ÿÿ|ÿÿwÿÿrÿÿmÿÿiÿþdÿýbÿÿfÿÿkÿÿoÿÿtÿÿyÿÿ}ÿÿ‚ÿÿ‡ÿÿ‹ÿÿ�ÿÿ•ÿÿšÿÿŸÿÿ£ÿÿ¨ÿÿ°ÿÿºÿÿ»ÿÿ¸ÿÿ°ÿÿªÿÿ¥ÿÿ ÿÿ›ÿÿ–ÿÿ‘ÿÿŒÿÿ‡ÿÿ‚ÿÿ}ÿÿxÿÿsÿÿnÿÿiÿÿeÿû`ÿô[ÿóZÿù^ÿþcÿÿgÿÿkÿÿpÿÿtÿÿyÿÿ~ÿÿ‚ÿÿ‡ÿÿŒÿÿ‘ÿÿ–ÿÿ›ÿÿŸÿÿ¤ÿÿ©ÿÿ€ÿÿ„ÿÿˆÿÿŒÿÿ‘ÿÿ”ÿÿ—ÿÿ ÿÿÈÿÿÉÿÿÅÿÿÁÿÿ¾ÿÿºÿÿ¹ÿÿ¼ÿÿ¿ÿÿÄÿÿÈÿÿÌÿÿÉÿÿ»ÿÿ¨ÿÿ”ÿÿŠÿÿ†ÿÿ„ÿÿ€ÿÿ|ÿÿwÿÿsÿÿoÿÿkÿÿgÿÿdÿÿgÿÿkÿÿpÿÿtÿÿxÿÿ}ÿÿ�ÿÿ†ÿÿŠÿÿ�ÿÿ‘ÿÿ¨ÿÿÐÿÿËÿÿÇÿÿÃÿÿ¿ÿÿ»ÿÿ¹ÿÿ¼ÿÿÀÿÿÅÿÿÉÿÿ½ÿÿ¢ÿÿ“ÿÿ�ÿÿŒÿÿ‡ÿÿ‚ÿÿ~ÿÿyÿÿtÿÿoÿÿkÿÿfÿüaÿýbÿÿgÿÿlÿÿpÿÿtÿÿyÿÿ}ÿÿ‚ÿÿ‡ÿÿ‹ÿÿ�ÿÿ•ÿÿšÿÿŸÿÿ¤ÿÿ©ÿÿ­ÿÿ³ÿÿ¸ÿÿ´ÿÿ¯ÿÿªÿÿ¥ÿÿ ÿÿ›ÿÿ–ÿÿ‘ÿÿŒÿÿ‡ÿÿ‚ÿÿ}ÿÿxÿÿsÿÿnÿÿiÿÿdÿû_ÿôZÿòYÿ÷\ÿüaÿÿeÿÿjÿÿnÿÿsÿÿwÿÿ|ÿÿ�ÿÿ…ÿÿŠÿÿ�ÿÿ”ÿÿ™ÿÿžÿÿ£ÿÿ¨ÿÿ†ÿÿŠÿÿŽÿÿ’ÿÿ–ÿÿšÿÿ�ÿÿ¥ÿÿÄÿÿÄÿÿÀÿÿ¼ÿÿºÿÿºÿÿ¾ÿÿÂÿÿÅÿÿÄÿÿºÿÿ«ÿÿœÿÿ’ÿÿŽÿÿ‹ÿÿ‡ÿÿƒÿÿÿÿzÿÿvÿÿrÿÿnÿÿjÿÿeÿþcÿÿeÿÿjÿÿnÿÿsÿÿwÿÿ{ÿÿÿÿ„ÿÿ‰ÿÿ�ÿÿ’ÿÿ–ÿÿ™ÿÿ¹ÿÿÊÿÿÄÿÿÀÿÿ¼ÿÿ¹ÿÿ»ÿÿ¿ÿÿÄÿÿÁÿÿ­ÿÿœÿÿ–ÿÿ“ÿÿŽÿÿ‰ÿÿ„ÿÿ€ÿÿ{ÿÿvÿÿqÿÿmÿÿhÿþcÿú`ÿþbÿÿgÿÿlÿÿpÿÿuÿÿyÿÿ~ÿÿ‚ÿÿ‡ÿÿŒÿÿ‘ÿÿ–ÿÿšÿÿŸÿÿ¤ÿÿ©ÿÿ®ÿÿ³ÿÿ·ÿÿ´ÿÿ¯ÿÿªÿÿ¥ÿÿ ÿÿ›ÿÿ–ÿÿ�ÿÿ‹ÿÿ‡ÿÿ�ÿÿ|ÿÿwÿÿsÿÿnÿÿiÿÿdÿú_ÿôZÿðWÿõ[ÿú_ÿÿdÿÿhÿÿmÿÿqÿÿvÿÿzÿÿÿÿ„ÿÿ‰ÿÿŽÿÿ’ÿÿ—ÿÿœÿÿ¡ÿÿ¦ÿÿŒÿÿ�ÿÿ•ÿÿ™ÿÿ�ÿÿ¡ÿÿ¤ÿÿ®ÿÿÂÿÿ¾ÿÿ»ÿÿºÿÿ½ÿÿÀÿÿ¾ÿÿ¶ÿÿ«ÿÿ¡ÿÿ™ÿÿ”ÿÿ‘ÿÿŽÿÿŠÿÿ†ÿÿ�ÿÿ}ÿÿyÿÿuÿÿqÿÿlÿÿhÿþdÿýaÿÿdÿÿiÿÿmÿÿqÿÿuÿÿzÿÿ~ÿÿƒÿÿ‡ÿÿŒÿÿ�ÿÿ•ÿÿ™ÿÿžÿÿ¥ÿÿÁÿÿÂÿÿ¾ÿÿºÿÿºÿÿ¾ÿÿÀÿÿµÿÿ¤ÿÿ�ÿÿ™ÿÿ”ÿÿ�ÿÿ‹ÿÿ†ÿÿ�ÿÿ}ÿÿxÿÿsÿÿnÿÿjÿÿeÿû`ÿú_ÿþcÿÿhÿÿlÿÿqÿÿuÿÿzÿÿ~ÿÿƒÿÿˆÿÿŒÿÿ‘ÿÿ–ÿÿ›ÿÿ ÿÿ¥ÿÿªÿÿ¯ÿÿ´ÿÿ¸ÿÿ´ÿÿ®ÿÿ©ÿÿ¤ÿÿŸÿÿšÿÿ•ÿÿ�ÿÿ‹ÿÿ†ÿÿ�ÿÿ|ÿÿwÿÿrÿÿmÿÿhÿþcÿù^ÿóYÿïVÿóYÿø^ÿþbÿÿgÿÿkÿÿpÿÿtÿÿyÿÿ}ÿÿ‚ÿÿ‡ÿÿŒÿÿ‘ÿÿ–ÿÿ›ÿÿ ÿÿ¥ÿÿ“ÿÿ—ÿÿ›ÿÿŸÿÿ£ÿÿ§ÿÿªÿÿ³ÿÿ½ÿÿºÿÿºÿÿºÿÿµÿÿ®ÿÿ¦ÿÿ ÿÿœÿÿ˜ÿÿ”ÿÿ�ÿÿŒÿÿˆÿÿƒÿÿÿÿ{ÿÿwÿÿrÿÿoÿÿkÿÿfÿýbÿû`ÿþcÿÿhÿÿlÿÿpÿÿtÿÿyÿÿ}ÿÿ‚ÿÿ†ÿÿŠÿÿ�ÿÿ”ÿÿ˜ÿÿ�ÿÿ¢ÿÿ¥ÿÿ³ÿÿÀÿÿ»ÿÿºÿÿ¼ÿÿ¹ÿÿ¬ÿÿ£ÿÿŸÿÿ›ÿÿ–ÿÿ‘ÿÿŒÿÿˆÿÿƒÿÿ~ÿÿyÿÿuÿÿpÿÿkÿÿgÿýbÿø^ÿú_ÿÿdÿÿhÿÿmÿÿqÿÿvÿÿzÿÿÿÿ„ÿÿˆÿÿ�ÿÿ’ÿÿ—ÿÿœÿÿ¡ÿÿ¥ÿÿ«ÿÿ¯ÿÿµÿÿ¸ÿÿ³ÿÿ®ÿÿ©ÿÿ¤ÿÿžÿÿ™ÿÿ•ÿÿ�ÿÿŠÿÿ…ÿÿ€ÿÿ{ÿÿvÿÿqÿÿlÿÿgÿþbÿù^ÿòYÿîUÿñXÿ÷\ÿüaÿÿeÿÿjÿÿnÿÿsÿÿwÿÿ|ÿÿ�ÿÿ†ÿÿ‹ÿÿ�ÿÿ•ÿÿ™ÿÿžÿÿ£ÿÿ™ÿÿ�ÿÿ¢ÿÿ¦ÿÿªÿÿ®ÿÿ²ÿÿ·ÿÿ¹ÿÿµÿÿ±ÿÿ«ÿÿ¦ÿÿ¢ÿÿžÿÿšÿÿ–ÿÿ’ÿÿŽÿÿŠÿÿ†ÿÿ�ÿÿ}ÿÿyÿÿvÿÿqÿÿmÿÿiÿÿdÿü`ÿú_ÿýbÿÿgÿÿkÿÿoÿÿsÿÿxÿÿ|ÿÿ€ÿÿ…ÿÿ‰ÿÿŽÿÿ’ÿÿ—ÿÿ›ÿÿ ÿÿ¥ÿÿ©ÿÿ®ÿÿ¹ÿÿºÿÿ¸ÿÿ²ÿÿªÿÿ¦ÿÿ¡ÿÿœÿÿ—ÿÿ“ÿÿŽÿÿ‰ÿÿ„ÿÿ€ÿÿ{ÿÿvÿÿqÿÿmÿÿhÿÿdÿú_ÿö\ÿû`ÿÿeÿÿiÿÿmÿÿrÿÿvÿÿ{ÿÿ€ÿÿ„ÿÿ‰ÿÿŽÿÿ“ÿÿ˜ÿÿœÿÿ¢ÿÿ§ÿÿ¬ÿÿ±ÿÿ¶ÿÿ·ÿÿ²ÿÿ­ÿÿ¨ÿÿ£ÿÿžÿÿ™ÿÿ”ÿÿŽÿÿ‰ÿÿ…ÿÿÿÿzÿÿuÿÿpÿÿlÿÿfÿýbÿ÷]ÿñXÿìTÿïVÿõ[ÿû`ÿÿdÿÿhÿÿmÿÿrÿÿvÿÿ{ÿÿ€ÿÿ…ÿÿ‰ÿÿŽÿÿ“ÿÿ˜ÿÿ�ÿÿ¢ÿÿ ÿÿ¤ÿÿ©ÿÿ­ÿÿ±ÿÿµÿÿ·ÿÿµÿÿ±ÿÿ¬ÿÿ¨ÿÿ¤ÿÿ ÿÿœÿÿ˜ÿÿ”ÿÿ�ÿÿ‹ÿÿˆÿÿƒÿÿÿÿ{ÿÿwÿÿsÿÿoÿÿkÿÿgÿþbÿú_ÿù^ÿýbÿÿfÿÿjÿÿnÿÿsÿÿwÿÿ{ÿÿ€ÿÿ„ÿÿˆÿÿ�ÿÿ‘ÿÿ–ÿÿšÿÿŸÿÿ¤ÿÿ¨ÿÿ­ÿÿ²ÿÿ·ÿÿ¶ÿÿ±ÿÿ¬ÿÿ§ÿÿ£ÿÿžÿÿ™ÿÿ”ÿÿ�ÿÿ‹ÿÿ†ÿÿ�ÿÿ|ÿÿwÿÿsÿÿnÿÿjÿÿeÿü`ÿõ\ÿö\ÿüaÿÿfÿÿjÿÿnÿÿsÿÿwÿÿ|ÿÿ�ÿÿ…ÿÿŠÿÿ�ÿÿ”ÿÿ™ÿÿžÿÿ£ÿÿ¨ÿÿ­ÿÿ²ÿÿ·ÿÿ·ÿÿ±ÿÿ¬ÿÿ§ÿÿ¢ÿÿœÿÿ˜ÿÿ’ÿÿ�ÿÿˆÿÿƒÿÿ~ÿÿyÿÿtÿÿoÿÿjÿÿeÿü`ÿö\ÿðWÿêSÿîUÿôZÿù^ÿþcÿÿgÿÿlÿÿqÿÿuÿÿzÿÿÿÿ„ÿÿˆÿÿ�ÿÿ’ÿÿ—ÿÿœÿÿ¡ÿÿ§ÿÿ«ÿÿ°ÿÿ´ÿÿ·ÿÿ·ÿÿ²ÿÿ®ÿÿªÿÿ¦ÿÿ¢ÿÿ�ÿÿ™ÿÿ•ÿÿ’ÿÿ�ÿÿ‰ÿÿ…ÿÿ�ÿÿ}ÿÿyÿÿuÿÿqÿÿlÿÿhÿÿdÿü`ÿ÷]ÿø]ÿýaÿÿfÿÿjÿÿnÿÿrÿÿvÿÿ{ÿÿÿÿƒÿÿˆÿÿŒÿÿ�ÿÿ•ÿÿšÿÿžÿÿ£ÿÿ§ÿÿ¬ÿÿ²ÿÿ¶ÿÿ¶ÿÿ±ÿÿ­ÿÿ©ÿÿ¤ÿÿŸÿÿšÿÿ•ÿÿ‘ÿÿŒÿÿ‡ÿÿ‚ÿÿ~ÿÿxÿÿtÿÿoÿÿkÿÿfÿýbÿ÷\ÿóZÿø]ÿýbÿÿfÿÿkÿÿoÿÿtÿÿyÿÿ}ÿÿ‚ÿÿ‡ÿÿ‹ÿÿ�ÿÿ•ÿÿšÿÿŸÿÿ¤ÿÿ©ÿÿ®ÿÿ³ÿÿ¸ÿÿµÿÿ°ÿÿ«ÿÿ¦ÿÿ¡ÿÿœÿÿ—ÿÿ‘ÿÿŒÿÿ‡ÿÿ‚ÿÿ}ÿÿxÿÿsÿÿnÿÿiÿÿdÿû_ÿõZÿîUÿéRÿíTÿóYÿø]ÿýbÿÿfÿÿkÿÿoÿÿtÿÿyÿÿ~ÿÿ‚ÿÿ‡ÿÿ�ÿÿ‘ÿÿ—ÿÿœÿÿ ÿÿ®ÿÿ³ÿÿ·ÿÿ·ÿÿ³ÿÿ¯ÿÿ«ÿÿ§ÿÿ£ÿÿŸÿÿ›ÿÿ—ÿÿ“ÿÿŽÿÿ‹ÿÿ†ÿÿ‚ÿÿ~ÿÿzÿÿvÿÿrÿÿnÿÿjÿÿfÿþbÿù^ÿõ[ÿ÷\ÿüaÿÿeÿÿiÿÿmÿÿrÿÿwÿÿyÿÿ~ÿÿ„ÿÿ‡ÿÿ‹ÿÿ�ÿÿ”ÿÿ™ÿÿ�ÿÿ¢ÿÿ§ÿÿ«ÿÿ°ÿÿ¶ÿÿ·ÿÿ³ÿÿ®ÿÿªÿÿ¥ÿÿ ÿÿ›ÿÿ—ÿÿ’ÿÿ�ÿÿˆÿÿƒÿÿÿÿzÿÿuÿÿqÿÿkÿÿgÿþcÿù]ÿóYÿóZÿù_ÿþcÿÿhÿÿlÿÿpÿÿuÿÿzÿÿ~ÿÿƒÿÿˆÿÿŒÿÿ‘ÿÿ–ÿÿ›ÿÿ ÿÿ¥ÿÿªÿÿ¯ÿÿ´ÿÿ¸ÿÿ´ÿÿ®ÿÿªÿÿ¥ÿÿŸÿÿšÿÿ•ÿÿ�ÿÿ‹ÿÿ†ÿÿ�ÿÿ|ÿÿwÿÿrÿÿmÿÿhÿÿcÿù^ÿóYÿíTÿèPÿìSÿòXÿ÷\ÿýaÿÿfÿÿjÿÿoÿÿsÿÿxÿÿ}ÿÿ‚ÿÿ†ÿÿŒÿÿ�ÿÿ–ÿÿšÿÿ ÿÿ¶ÿÿ¸ÿÿµÿÿ°ÿÿ¬ÿÿ¨ÿÿ¤ÿÿ ÿÿœÿÿ˜ÿÿ”ÿÿ�ÿÿŒÿÿˆÿÿ„ÿÿ€ÿÿ{ÿÿwÿÿtÿÿpÿÿlÿÿhÿÿdÿû`ÿö\ÿóZÿö\ÿüaÿÿfÿÿiÿÿnÿÿpÿÿuÿÿ{ÿÿ}ÿÿ‚ÿÿˆÿÿ‹ÿÿ�ÿÿ”ÿÿ˜ÿÿ�ÿÿ¢ÿÿ¦ÿÿ«ÿÿ°ÿÿµÿÿ·ÿÿ´ÿÿ¯ÿÿªÿÿ¦ÿÿ¡ÿÿœÿÿ—ÿÿ“ÿÿŽÿÿ‰ÿÿ„ÿÿ€ÿÿ{ÿÿvÿÿrÿÿmÿÿhÿþdÿú_ÿôZÿñXÿõ[ÿû`ÿÿdÿÿhÿÿmÿÿrÿÿvÿÿ{ÿÿ€ÿÿ„ÿÿ‰ÿÿŽÿÿ“ÿÿ˜ÿÿ�ÿÿ¢ÿÿ§ÿÿ¬ÿÿ±ÿÿ¶ÿÿ¸ÿÿ³ÿÿ­ÿÿ¨ÿÿ£ÿÿžÿÿ™ÿÿ”ÿÿ�ÿÿŠÿÿ…ÿÿÿÿzÿÿuÿÿpÿÿkÿÿfÿþbÿø]ÿñXÿëSÿçOÿëRÿðWÿö[ÿü`ÿÿeÿÿiÿÿnÿÿsÿÿwÿÿ|ÿÿ�ÿÿ†ÿÿ‹ÿÿ�ÿÿ•ÿÿšÿÿŸÿÿµÿÿ±ÿÿ¬ÿÿ©ÿÿ¥ÿÿ¡ÿÿ�ÿÿ˜ÿÿ”ÿÿ‘ÿÿ�ÿÿ‰ÿÿ…ÿÿ�ÿÿ}ÿÿyÿÿuÿÿqÿÿmÿÿiÿÿfÿýaÿø]ÿóZÿòYÿ÷]ÿüaÿÿfÿÿiÿÿnÿÿqÿÿuÿÿzÿÿ~ÿÿ‚ÿÿ‡ÿÿ‹ÿÿ�ÿÿ”ÿÿ˜ÿÿ�ÿÿ¡ÿÿ¦ÿÿ«ÿÿ¯ÿÿµÿÿ¸ÿÿµÿÿ°ÿÿ«ÿÿ¥ÿÿ¡ÿÿ�ÿÿ˜ÿÿ“ÿÿ�ÿÿŠÿÿ…ÿÿ€ÿÿ|ÿÿwÿÿrÿÿnÿÿiÿÿeÿû`ÿõZÿðWÿòXÿ÷]ÿýaÿÿfÿÿjÿÿoÿÿsÿÿxÿÿ}ÿÿ�ÿÿ†ÿÿ‹ÿÿ�ÿÿ”ÿÿ™ÿÿžÿÿ£ÿÿ¨ÿÿ­ÿÿ²ÿÿ¸ÿÿ¶ÿÿ±ÿÿ¬ÿÿ§ÿÿ¢ÿÿœÿÿ—ÿÿ’ÿÿ�ÿÿˆÿÿƒÿÿ~ÿÿyÿÿtÿÿoÿÿjÿÿeÿü`ÿö[ÿðVÿéQÿåNÿêRÿðVÿö[ÿû_ÿÿdÿÿiÿÿmÿÿrÿÿwÿÿ|ÿÿ�ÿÿ…ÿÿŠÿÿ�ÿÿ”ÿÿ™ÿÿŸÿÿ®ÿÿªÿÿ¥ÿÿ¡ÿÿ�ÿÿ™ÿÿ•ÿÿ‘ÿÿŽÿÿŠÿÿ…ÿÿ�ÿÿ~ÿÿzÿÿvÿÿrÿÿnÿÿjÿÿfÿþcÿú_ÿõ[ÿñXÿòYÿ÷]ÿübÿÿfÿÿjÿÿmÿÿqÿÿuÿÿzÿÿ~ÿÿ‚ÿÿ‡ÿÿ‹ÿÿ�ÿÿ”ÿÿ˜ÿÿ�ÿÿ¢ÿÿ¦ÿÿ«ÿÿ°ÿÿ´ÿÿ¸ÿÿµÿÿ°ÿÿ«ÿÿ§ÿÿ¢ÿÿ�ÿÿ˜ÿÿ”ÿÿ�ÿÿŠÿÿ†ÿÿ�ÿÿ|ÿÿxÿÿsÿÿnÿÿjÿÿeÿüaÿö\ÿðWÿîVÿôZÿù^ÿþcÿÿgÿÿlÿÿpÿÿuÿÿyÿÿ~ÿÿƒÿÿˆÿÿŒÿÿ‘ÿÿ–ÿÿ›ÿÿ ÿÿ¥ÿÿªÿÿ¯ÿÿµÿÿ¸ÿÿµÿÿ¯ÿÿªÿÿ¥ÿÿ ÿÿ›ÿÿ–ÿÿ‘ÿÿ‹ÿÿ†ÿÿ�ÿÿ|ÿÿwÿÿrÿÿmÿÿhÿÿcÿú^ÿôZÿîUÿçPÿäNÿéQÿïVÿõZÿû_ÿÿdÿÿhÿÿmÿÿrÿÿvÿÿ{ÿÿ€ÿÿ…ÿÿŠÿÿ�ÿÿ”ÿÿ™ÿÿžÿÿ¦ÿÿ¢ÿÿžÿÿšÿÿ–ÿÿ’ÿÿŽÿÿŠÿÿ†ÿÿ‚ÿÿ~ÿÿ{ÿÿwÿÿsÿÿoÿÿkÿÿgÿþcÿû`ÿö\ÿñXÿïVÿòYÿø]ÿýbÿÿeÿÿiÿÿmÿÿqÿÿuÿÿzÿÿ~ÿÿ‚ÿÿ‡ÿÿ‹ÿÿ�ÿÿ”ÿÿ™ÿÿ�ÿÿ¢ÿÿ¦ÿÿ«ÿÿ¯ÿÿ´ÿÿ¸ÿÿµÿÿ°ÿÿ«ÿÿ§ÿÿ¢ÿÿ�ÿÿ™ÿÿ”ÿÿ�ÿÿ‹ÿÿ†ÿÿ�ÿÿ}ÿÿxÿÿsÿÿoÿÿjÿÿfÿüaÿ÷\ÿñWÿìTÿðWÿö\ÿü`ÿÿdÿÿiÿÿmÿÿrÿÿvÿÿ{ÿÿ€ÿÿ„ÿÿ‰ÿÿ�ÿÿ“ÿÿ˜ÿÿ�ÿÿ¢ÿÿ§ÿÿ¬ÿÿ±ÿÿ¶ÿÿ¸ÿÿ³ÿÿ®ÿÿ¨ÿÿ£ÿÿžÿÿ™ÿÿ”ÿÿ�ÿÿŠÿÿ…ÿÿ€ÿÿ{ÿÿuÿÿpÿÿkÿÿgÿþbÿø]ÿòXÿëSÿåNÿãMÿéQÿïUÿõZÿú_ÿÿcÿÿhÿÿlÿÿqÿÿvÿÿ{ÿÿ€ÿÿ…ÿÿŠÿÿ�ÿÿ”ÿÿ™ÿÿžÿÿŸÿÿ›ÿÿ–ÿÿ’ÿÿŽÿÿŠÿÿ‡ÿÿƒÿÿÿÿ{ÿÿwÿÿsÿÿpÿÿlÿÿhÿÿdÿüaÿ÷]ÿóYÿîUÿîVÿóYÿø]ÿýaÿÿfÿÿiÿÿnÿÿrÿÿvÿÿzÿÿ~ÿÿƒÿÿ‡ÿÿ‹ÿÿ�ÿÿ”ÿÿ™ÿÿ�ÿÿ¢ÿÿ¦ÿÿ«ÿÿ°ÿÿ´ÿÿ¸ÿÿµÿÿ°ÿÿ«ÿÿ§ÿÿ¢ÿÿ�ÿÿ™ÿÿ”ÿÿ�ÿÿŠÿÿ†ÿÿ�ÿÿ}ÿÿxÿÿtÿÿnÿÿjÿÿfÿýaÿ÷]ÿñWÿëTÿíTÿóYÿø]ÿýbÿÿfÿÿkÿÿoÿÿtÿÿxÿÿ}ÿÿ‚ÿÿ†ÿÿ‹ÿÿ�ÿÿ•ÿÿšÿÿŸÿÿ¤ÿÿ©ÿÿ®ÿÿ³ÿÿ¸ÿÿ¶ÿÿ±ÿÿ¬ÿÿ§ÿÿ¡ÿÿ�ÿÿ—ÿÿ’ÿÿ�ÿÿˆÿÿƒÿÿ~ÿÿyÿÿtÿÿoÿÿjÿÿeÿü`ÿö[ÿïVÿéQÿãLÿãLÿéQÿïVÿôZÿú^ÿÿcÿÿhÿÿlÿÿqÿÿvÿÿ{ÿÿÿÿ…ÿÿŠÿÿŽÿÿ”ÿÿ™ÿÿžÿÿ—ÿÿ“ÿÿŽÿÿŠÿÿ‡ÿÿƒÿÿÿÿ{ÿÿwÿÿtÿÿpÿÿlÿÿhÿÿeÿýaÿø]ÿóYÿîVÿìSÿïUÿôZÿù^ÿþbÿÿfÿÿjÿÿnÿÿrÿÿvÿÿ{ÿÿÿÿƒÿÿ‡ÿÿŒÿÿ�ÿÿ•ÿÿ™ÿÿžÿÿ¢ÿÿ§ÿÿ«ÿÿ°ÿÿµÿÿ¸ÿÿµÿÿ°ÿÿ«ÿÿ§ÿÿ¢ÿÿ�ÿÿ™ÿÿ”ÿÿ�ÿÿ‹ÿÿ†ÿÿ�ÿÿ}ÿÿxÿÿsÿÿoÿÿjÿÿfÿýaÿ÷]ÿòXÿìSÿêRÿðVÿõ[ÿû_ÿÿdÿÿhÿÿlÿÿqÿÿvÿÿzÿÿÿÿ„ÿÿ‰ÿÿ�ÿÿ’ÿÿ—ÿÿœÿÿ¡ÿÿ¦ÿÿ«ÿÿ°ÿÿ¶ÿÿ¸ÿÿ´ÿÿ¯ÿÿ©ÿÿ¤ÿÿŸÿÿšÿÿ•ÿÿ�ÿÿ‹ÿÿ†ÿÿ�ÿÿ{ÿÿvÿÿqÿÿlÿÿgÿþcÿù^ÿóYÿíTÿæOÿàKÿãLÿéPÿîUÿôYÿú^ÿÿcÿÿgÿÿlÿÿqÿÿvÿÿzÿÿ€ÿÿ…ÿÿŠÿÿŽÿÿ”ÿÿ™ÿÿžÿÿ�ÿÿŠÿÿ‡ÿÿ„ÿÿÿÿ{ÿÿwÿÿtÿÿpÿÿlÿÿiÿÿeÿýaÿù]ÿôZÿïVÿëSÿëSÿðWÿõ[ÿú_ÿþcÿÿgÿÿkÿÿoÿÿsÿÿwÿÿ{ÿÿ€ÿÿƒÿÿˆÿÿŒÿÿ‘ÿÿ•ÿÿšÿÿžÿÿ£ÿÿ§ÿÿ¬ÿÿ°ÿÿµÿÿ¸ÿÿµÿÿ°ÿÿ«ÿÿ§ÿÿ¢ÿÿ�ÿÿ™ÿÿ”ÿÿ�ÿÿŠÿÿ†ÿÿ�ÿÿ}ÿÿxÿÿsÿÿoÿÿjÿÿfÿýaÿø]ÿòXÿìSÿèQÿìTÿòYÿø\ÿýaÿÿfÿÿjÿÿoÿÿsÿÿxÿÿ}ÿÿ�ÿÿ†ÿÿ‹ÿÿ�ÿÿ•ÿÿšÿÿŸÿÿ¤ÿÿ©ÿÿ®ÿÿ³ÿÿ¸ÿÿ·ÿÿ±ÿÿ¬ÿÿ§ÿÿ¢ÿÿ�ÿÿ˜ÿÿ“ÿÿŽÿÿˆÿÿƒÿÿ~ÿÿyÿÿtÿÿoÿÿjÿÿeÿý`ÿ÷[ÿðWÿêRÿäMÿßIÿãLÿéPÿîUÿôZÿú^ÿÿcÿÿgÿÿlÿÿqÿÿvÿÿzÿÿ€ÿÿ…ÿÿŠÿÿ�ÿÿ”ÿÿ™ÿÿžÿÿ‡ÿÿƒÿÿÿÿ|ÿÿwÿÿtÿÿqÿÿmÿÿhÿÿeÿýaÿù^ÿôZÿïVÿêSÿéQÿìSÿñXÿö\ÿû`ÿþdÿÿhÿÿlÿÿpÿÿtÿÿxÿÿ|ÿÿ€ÿÿ„ÿÿ‰ÿÿ�ÿÿ’ÿÿ–ÿÿšÿÿŸÿÿ£ÿÿ¨ÿÿ¬ÿÿ±ÿÿ¶ÿÿ¸ÿÿ´ÿÿ°ÿÿ«ÿÿ¦ÿÿ¢ÿÿ�ÿÿ˜ÿÿ”ÿÿ�ÿÿŠÿÿ†ÿÿ�ÿÿ|ÿÿxÿÿsÿÿoÿÿjÿÿfÿýaÿø\ÿòXÿìSÿçPÿêRÿïVÿõ[ÿû_ÿÿcÿÿhÿÿlÿÿqÿÿvÿÿzÿÿÿÿ„ÿÿˆÿÿ�ÿÿ’ÿÿ—ÿÿœÿÿ¡ÿÿ¦ÿÿ«ÿÿ°ÿÿµÿÿ¹ÿÿ´ÿÿ¯ÿÿªÿÿ¥ÿÿ ÿÿ›ÿÿ–ÿÿ�ÿÿ‹ÿÿ†ÿÿ�ÿÿ|ÿÿwÿÿrÿÿmÿÿhÿÿcÿú^ÿôYÿíTÿçPÿáKÿÞHÿãLÿéPÿîUÿôZÿú^ÿÿcÿÿgÿÿlÿÿqÿÿvÿÿ{ÿÿ€ÿÿ…ÿÿŠÿÿ�ÿÿ”ÿÿ™ÿÿžÿÿ~ÿÿ{ÿÿxÿÿsÿÿpÿÿlÿÿhÿÿeÿýaÿù]ÿôZÿïWÿêRÿçPÿéQÿíUÿòYÿ÷]ÿüaÿÿdÿÿiÿÿlÿÿqÿÿuÿÿyÿÿ}ÿÿ�ÿÿ…ÿÿŠÿÿŽÿÿ’ÿÿ—ÿÿ›ÿÿŸÿÿ¤ÿÿ©ÿÿ­ÿÿ²ÿÿ·ÿÿ¸ÿÿ´ÿÿ¯ÿÿªÿÿ¦ÿÿ¡ÿÿœÿÿ˜ÿÿ“ÿÿ�ÿÿŠÿÿ…ÿÿ�ÿÿ|ÿÿxÿÿsÿÿnÿÿjÿÿeÿýaÿ÷\ÿòXÿìSÿæOÿçPÿíTÿòYÿø]ÿýaÿÿfÿÿjÿÿoÿÿsÿÿxÿÿ}ÿÿ�ÿÿ†ÿÿ‹ÿÿ�ÿÿ•ÿÿšÿÿžÿÿ£ÿÿ¨ÿÿ®ÿÿ³ÿÿ¸ÿÿ·ÿÿ²ÿÿ­ÿÿ¨ÿÿ¢ÿÿ�ÿÿ˜ÿÿ“ÿÿŽÿÿ‰ÿÿ„ÿÿÿÿyÿÿtÿÿoÿÿjÿÿeÿýaÿ÷\ÿñWÿêRÿäMÿÞIÿÝHÿãLÿéQÿïUÿõZÿû^ÿÿcÿÿhÿÿlÿÿqÿÿvÿÿ{ÿÿ€ÿÿ…ÿÿŠÿÿ�ÿÿ”ÿÿšÿÿŸÿÿvÿÿsÿÿpÿÿkÿÿhÿÿeÿý`ÿù]ÿôYÿïVÿêRÿæOÿæOÿêRÿïVÿôZÿù^ÿýbÿÿfÿÿjÿÿnÿÿrÿÿvÿÿzÿÿ~ÿÿ‚ÿÿ†ÿÿ‹ÿÿ�ÿÿ“ÿÿ˜ÿÿœÿÿ¡ÿÿ¥ÿÿªÿÿ®ÿÿ³ÿÿ·ÿÿ¸ÿÿ³ÿÿ®ÿÿªÿÿ¥ÿÿ ÿÿœÿÿ—ÿÿ“ÿÿŽÿÿ‰ÿÿ…ÿÿ€ÿÿ|ÿÿwÿÿrÿÿnÿÿiÿÿeÿü`ÿ÷\ÿñWÿìSÿæOÿåNÿêRÿðWÿö[ÿû_ÿÿdÿÿhÿÿmÿÿqÿÿvÿÿ{ÿÿÿÿ„ÿÿ‰ÿÿŽÿÿ’ÿÿ—ÿÿœÿÿ¡ÿÿ¦ÿÿ«ÿÿ°ÿÿ¶ÿÿ¹ÿÿ´ÿÿ¯ÿÿªÿÿ¥ÿÿ ÿÿ›ÿÿ•ÿÿ�ÿÿ‹ÿÿ†ÿÿ�ÿÿ|ÿÿwÿÿrÿÿmÿÿhÿÿcÿú^ÿôYÿîTÿçPÿáKÿÛFÿÞHÿäLÿéQÿïUÿõZÿû_ÿÿcÿÿhÿÿmÿÿrÿÿvÿÿ{ÿÿ�ÿÿ†ÿÿ‹ÿÿ�ÿÿ•ÿÿšÿÿŸÿÿnÿÿkÿÿhÿÿdÿü`ÿø\ÿóYÿïVÿêRÿåNÿäMÿçOÿìSÿñWÿö[ÿû_ÿþcÿÿgÿÿkÿÿoÿÿsÿÿwÿÿ{ÿÿ€ÿÿƒÿÿˆÿÿŒÿÿ�ÿÿ•ÿÿ™ÿÿ�ÿÿ¢ÿÿ¦ÿÿ«ÿÿ¯ÿÿ´ÿÿ¸ÿÿ·ÿÿ²ÿÿ­ÿÿ©ÿÿ¤ÿÿ ÿÿ›ÿÿ–ÿÿ’ÿÿ�ÿÿ‰ÿÿ„ÿÿÿÿ{ÿÿvÿÿrÿÿmÿÿiÿÿdÿü`ÿö[ÿðWÿëRÿåNÿãMÿèQÿîUÿóYÿù^ÿþbÿÿfÿÿkÿÿoÿÿtÿÿyÿÿ}ÿÿ‚ÿÿ‡ÿÿŒÿÿ�ÿÿ•ÿÿšÿÿŸÿÿ¤ÿÿ©ÿÿ®ÿÿ³ÿÿ¸ÿÿ·ÿÿ±ÿÿ¬ÿÿ§ÿÿ¢ÿÿ�ÿÿ˜ÿÿ“ÿÿŽÿÿ‰ÿÿ„ÿÿ~ÿÿyÿÿtÿÿoÿÿjÿÿeÿý`ÿ÷[ÿðWÿêRÿäMÿÝHÿÙEÿÞHÿäMÿêQÿðVÿö[ÿü_ÿÿdÿÿiÿÿmÿÿrÿÿwÿÿ|ÿÿ�ÿÿ†ÿÿ‹ÿÿ�ÿÿ–ÿÿ›ÿÿ ÿÿfÿþcÿû`ÿ÷\ÿòXÿîUÿéQÿäNÿâLÿäMÿéQÿîUÿóYÿø]ÿýaÿÿeÿÿhÿÿmÿÿpÿÿuÿÿyÿÿ}ÿÿ�ÿÿ…ÿÿ‰ÿÿ�ÿÿ’ÿÿ–ÿÿšÿÿŸÿÿ£ÿÿ¨ÿÿ¬ÿÿ±ÿÿ¶ÿÿ¸ÿÿ¶ÿÿ±ÿÿ¬ÿÿ¨ÿÿ£ÿÿŸÿÿšÿÿ•ÿÿ‘ÿÿŒÿÿˆÿÿƒÿÿÿÿzÿÿuÿÿqÿÿmÿÿhÿÿcÿû_ÿõ[ÿðVÿêRÿäMÿâKÿæOÿìTÿñWÿ÷\ÿü`ÿÿdÿÿiÿÿnÿÿrÿÿwÿÿ{ÿÿ€ÿÿ…ÿÿŠÿÿ�ÿÿ“ÿÿ˜ÿÿ�ÿÿ¢ÿÿ§ÿÿ¬ÿÿ±ÿÿ·ÿÿ¹ÿÿ´ÿÿ®ÿÿªÿÿ¤ÿÿŸÿÿšÿÿ•ÿÿ�ÿÿŠÿÿ†ÿÿ�ÿÿ{ÿÿvÿÿqÿÿlÿÿgÿÿbÿú]ÿóYÿíTÿçOÿáJÿÚEÿÙEÿßIÿåNÿëRÿðWÿö[ÿý`ÿÿdÿÿiÿÿnÿÿsÿÿxÿÿ}ÿÿ‚ÿÿ‡ÿÿŒÿÿ‘ÿÿ—ÿÿœÿÿ‹ÿú_ÿö[ÿòWÿíTÿèPÿãMÿàJÿâLÿçOÿìSÿðWÿõ[ÿú_ÿþbÿÿfÿÿjÿÿnÿÿrÿÿvÿÿzÿÿ~ÿÿƒÿÿ†ÿÿ‹ÿÿ�ÿÿ“ÿÿ˜ÿÿœÿÿ ÿÿ¥ÿÿªÿÿ®ÿÿ³ÿÿ·ÿÿ¸ÿÿµÿÿ°ÿÿ«ÿÿ§ÿÿ¢ÿÿ�ÿÿ™ÿÿ”ÿÿ�ÿÿ‹ÿÿ‡ÿÿ‚ÿÿ}ÿÿyÿÿtÿÿpÿÿkÿÿgÿþcÿú^ÿõZÿïVÿéQÿãLÿàJÿäMÿêRÿïVÿõZÿû^ÿÿcÿÿhÿÿlÿÿpÿÿuÿÿzÿÿ~ÿÿƒÿÿˆÿÿ�ÿÿ’ÿÿ—ÿÿ›ÿÿ¡ÿÿ¦ÿÿ«ÿÿ°ÿÿµÿÿ¹ÿÿ¶ÿÿ±ÿÿ«ÿÿ¦ÿÿ¡ÿÿœÿÿ—ÿÿ’ÿÿ�ÿÿˆÿÿƒÿÿ}ÿÿxÿÿsÿÿnÿÿiÿÿdÿü`ÿö[ÿðVÿéQÿãLÿÝGÿ×CÿÚEÿàJÿæNÿìSÿòWÿø\ÿý`ÿÿeÿÿjÿÿoÿÿtÿÿyÿÿ}ÿÿƒÿÿˆÿÿ�ÿÿ’ÿÿ™ÿÿ„ÿÿ{ÿðVÿëSÿçOÿâLÿßIÿàJÿäMÿéQÿîUÿóYÿø\ÿü`ÿÿdÿÿhÿÿlÿÿpÿÿtÿÿxÿÿ}ÿÿ€ÿÿ„ÿÿˆÿÿ�ÿÿ‘ÿÿ•ÿÿ™ÿÿžÿÿ¢ÿÿ¦ÿÿ«ÿÿ¯ÿÿ´ÿÿ¸ÿÿ·ÿÿ³ÿÿ®ÿÿªÿÿ¥ÿÿ¡ÿÿœÿÿ˜ÿÿ“ÿÿ�ÿÿŠÿÿ…ÿÿ�ÿÿ|ÿÿwÿÿsÿÿoÿÿjÿÿfÿþbÿù]ÿóYÿîTÿèPÿâLÿßIÿâLÿèPÿíUÿóYÿø]ÿþaÿÿfÿÿjÿÿoÿÿtÿÿxÿÿ}ÿÿ‚ÿÿ†ÿÿ‹ÿÿ�ÿÿ•ÿÿšÿÿŸÿÿ¤ÿÿ©ÿÿ®ÿÿ³ÿÿ¸ÿÿ¸ÿÿ²ÿÿ­ÿÿ¨ÿÿ£ÿÿžÿÿ™ÿÿ”ÿÿ�ÿÿ‰ÿÿ…ÿÿÿÿzÿÿuÿÿpÿÿkÿÿfÿþaÿù\ÿòXÿìSÿæNÿàIÿØDÿÖBÿÛFÿáJÿçOÿíSÿóXÿù]ÿþbÿÿfÿÿkÿÿpÿÿtÿÿzÿÿÿÿƒÿÿ‰ÿÿŽÿÿ•ÿÿ…ÿÿrÿÿÿåNÿáKÿÝHÿÞIÿãLÿçOÿìSÿñWÿö[ÿú^ÿþbÿÿfÿÿkÿÿnÿÿqÿÿvÿÿzÿÿ~ÿÿ‚ÿÿ†ÿÿ‹ÿÿŽÿÿ“ÿÿ—ÿÿ›ÿÿ ÿÿ¤ÿÿ¨ÿÿ­ÿÿ±ÿÿ¶ÿÿ¹ÿÿ¶ÿÿ±ÿÿ¬ÿÿ¨ÿÿ¤ÿÿŸÿÿ›ÿÿ–ÿÿ’ÿÿ�ÿÿ‰ÿÿ„ÿÿ€ÿÿ{ÿÿwÿÿrÿÿnÿÿiÿÿeÿý`ÿ÷\ÿòXÿìSÿçOÿáJÿÝHÿáKÿæOÿìTÿñWÿ÷\ÿý`ÿÿeÿÿiÿÿnÿÿrÿÿwÿÿ|ÿÿ€ÿÿ…ÿÿŠÿÿŽÿÿ“ÿÿ˜ÿÿ�ÿÿ¢ÿÿ§ÿÿ¬ÿÿ²ÿÿ·ÿÿ¹ÿÿ´ÿÿ¯ÿÿªÿÿ¥ÿÿ ÿÿ›ÿÿ•ÿÿ�ÿÿ‹ÿÿ†ÿÿ�ÿÿ|ÿÿwÿÿrÿÿmÿÿhÿÿcÿû^ÿõYÿîTÿèPÿâKÿÛFÿÕBÿÖBÿÜGÿâKÿèPÿîTÿôYÿú^ÿÿbÿÿgÿÿlÿÿqÿÿvÿÿ{ÿÿ€ÿÿ…ÿÿŠÿÿ’ÿÿ~ÿÿgÿÿuÿÿƒÿÛGÿÜGÿáJÿæNÿêRÿïUÿôYÿø]ÿý`ÿÿeÿÿhÿÿlÿÿpÿÿtÿÿxÿÿ|ÿÿ�ÿÿ„ÿÿˆÿÿ�ÿÿ‘ÿÿ•ÿÿ™ÿÿ�ÿÿ¢ÿÿ¦ÿÿªÿÿ¯ÿÿ³ÿÿ¸ÿÿ¸ÿÿ´ÿÿ¯ÿÿ«ÿÿ¦ÿÿ¢ÿÿ�ÿÿ™ÿÿ”ÿÿ�ÿÿ‹ÿÿ‡ÿÿƒÿÿ~ÿÿyÿÿvÿÿqÿÿlÿÿhÿÿcÿû_ÿö[ÿðVÿêRÿåNÿßIÿÜGÿßIÿæNÿêRÿðVÿõ[ÿü_ÿÿcÿÿhÿÿmÿÿqÿÿuÿÿzÿÿÿÿ„ÿÿˆÿÿŽÿÿ’ÿÿ—ÿÿœÿÿ¡ÿÿ¦ÿÿ«ÿÿ°ÿÿ³ÿÿ·ÿÿ³ÿÿ±ÿÿ¬ÿÿ§ÿÿ¡ÿÿ�ÿÿ—ÿÿ’ÿÿ�ÿÿˆÿÿƒÿÿ~ÿÿyÿÿtÿÿnÿÿjÿÿeÿý`ÿ÷[ÿðVÿêQÿäLÿÞHÿÖCÿÓ@ÿØCÿÞHÿäMÿêQÿïUÿöZÿü_ÿÿcÿÿhÿÿmÿÿrÿÿwÿÿ|ÿÿ�ÿÿ†ÿÿŽÿÿwÿÿ]ÿÿjÿÿyÿÿ†ÿßIÿäMÿéPÿíUÿòXÿ÷[ÿû_ÿþcÿÿgÿÿkÿÿoÿÿsÿÿwÿÿ{ÿÿÿÿƒÿÿ‡ÿÿ‹ÿÿ�ÿÿ“ÿÿ—ÿÿœÿÿ ÿÿ¤ÿÿ¨ÿÿ­ÿÿ±ÿÿ¶ÿÿ¹ÿÿ·ÿÿ²ÿÿ­ÿÿ©ÿÿ¥ÿÿ ÿÿœÿÿ—ÿÿ“ÿÿŽÿÿŠÿÿ…ÿÿ�ÿÿ|ÿÿwÿÿsÿÿoÿÿkÿÿfÿþaÿù^ÿôYÿîUÿéQÿäLÿÞHÿÚFÿÞHÿäMÿéQÿïUÿôZÿú^ÿÿbÿÿgÿÿlÿÿpÿÿtÿÿyÿÿ~ÿÿ‚ÿÿ‡ÿÿŒÿÿ‘ÿÿ–ÿÿšÿÿŸÿÿ¥ÿÿªÿÿ¬ÿÿ®ÿÿ¶ÿÿ³ÿÿ§ÿÿ«ÿÿ¨ÿÿ£ÿÿžÿÿ˜ÿÿ”ÿÿ�ÿÿŠÿÿ„ÿÿÿÿzÿÿuÿÿpÿÿkÿÿfÿþaÿù\ÿòWÿìSÿæNÿßIÿÙDÿÓ@ÿÓ@ÿÙDÿßIÿåMÿëRÿñWÿ÷[ÿý`ÿÿeÿÿiÿÿnÿÿsÿÿxÿÿ}ÿÿƒÿÿŠÿÿqÿÿSÿÿaÿÿnÿÿ|ÿÿ‰ÿçOÿìSÿñWÿõZÿú^ÿþbÿÿeÿÿiÿÿmÿÿqÿÿuÿÿyÿÿ}ÿÿ�ÿÿ…ÿÿ‰ÿÿ�ÿÿ‘ÿÿ–ÿÿ™ÿÿžÿÿ¢ÿÿ¦ÿÿ«ÿÿ¯ÿÿ³ÿÿ¸ÿÿ¸ÿÿµÿÿ°ÿÿ«ÿÿ§ÿÿ¢ÿÿžÿÿšÿÿ•ÿÿ‘ÿÿŒÿÿˆÿÿƒÿÿÿÿzÿÿvÿÿrÿÿmÿÿhÿÿeÿý`ÿ÷\ÿòXÿìSÿçOÿáKÿÜFÿÙEÿÝHÿãLÿèPÿîUÿôYÿù]ÿþbÿÿfÿÿjÿÿoÿÿsÿÿxÿÿ}ÿÿ�ÿÿ†ÿÿ‹ÿÿ�ÿÿ”ÿÿ™ÿÿŸÿÿ¥ÿÿ§ÿÿ¥ÿÿ¨ÿÿ³ÿÿµÿÿªÿÿœÿÿ ÿÿ¥ÿÿŸÿÿšÿÿ•ÿÿ�ÿÿ‹ÿÿ†ÿÿ�ÿÿ|ÿÿwÿÿrÿÿmÿÿhÿÿcÿú]ÿôYÿîTÿèOÿáJÿÛFÿÔAÿÐ>ÿÕAÿÛFÿáJÿçOÿíSÿóXÿù\ÿþaÿÿfÿÿkÿÿpÿÿuÿÿzÿÿ€ÿÿˆÿÿkÿÿIÿÿWÿÿfÿÿrÿÿ€ÿÿ�ÿïVÿôYÿù]ÿý`ÿÿdÿÿhÿÿlÿÿpÿÿtÿÿxÿÿ|ÿÿ€ÿÿ„ÿÿˆÿÿŒÿÿ�ÿÿ”ÿÿ˜ÿÿœÿÿ¡ÿÿ¥ÿÿ©ÿÿ¬ÿÿ¯ÿÿ´ÿÿ¶ÿÿ²ÿÿ²ÿÿ®ÿÿ©ÿÿ¤ÿÿ¡ÿÿœÿÿ—ÿÿ“ÿÿ�ÿÿŠÿÿ†ÿÿ�ÿÿ}ÿÿyÿÿtÿÿpÿÿkÿÿgÿþcÿû^ÿõZÿðVÿêRÿåMÿßIÿÚEÿØDÿÝGÿâLÿèPÿíTÿóXÿø\ÿþaÿÿeÿÿjÿÿnÿÿrÿÿwÿÿ|ÿÿ€ÿÿ…ÿÿŠÿÿ�ÿÿ“ÿÿ˜ÿÿŸÿÿ¢ÿÿžÿÿ›ÿÿ£ÿÿ²ÿÿ·ÿÿ¬ÿÿ ÿÿ’ÿÿ�ÿÿ¡ÿÿœÿÿ–ÿÿ‘ÿÿŒÿÿ‡ÿÿ‚ÿÿ}ÿÿxÿÿsÿÿnÿÿiÿÿdÿü^ÿöZÿïUÿéQÿãLÿÜGÿÖBÿÐ>ÿÑ>ÿ×CÿÝGÿãLÿéPÿïUÿõYÿû^ÿÿcÿÿhÿÿlÿÿqÿÿvÿÿ|ÿÿ�ÿÿ]ÿÿ@ÿÿNÿÿ\ÿÿiÿÿwÿÿ…ÿÿ’ÿø\ÿý`ÿÿdÿÿgÿÿkÿÿoÿÿsÿÿwÿÿ{ÿÿÿÿƒÿÿ†ÿÿ‹ÿÿ�ÿÿ“ÿÿ—ÿÿ›ÿÿ ÿÿ¤ÿÿ¦ÿÿ¦ÿÿ¨ÿÿ­ÿÿ´ÿÿ´ÿÿªÿÿ¦ÿÿ¬ÿÿ§ÿÿ¢ÿÿžÿÿšÿÿ•ÿÿ‘ÿÿŒÿÿˆÿÿ„ÿÿÿÿzÿÿvÿÿrÿÿnÿÿiÿÿeÿýaÿø\ÿóXÿíTÿèPÿâKÿÝGÿ×Cÿ×CÿÜGÿâKÿçOÿìSÿòXÿ÷\ÿý_ÿÿdÿÿiÿÿmÿÿrÿÿvÿÿ{ÿÿ€ÿÿ„ÿÿ‰ÿÿŽÿÿ“ÿÿ™ÿÿžÿÿ™ÿÿ’ÿÿ•ÿÿ¢ÿÿ¯ÿÿ¸ÿÿ¯ÿÿ¢ÿÿ•ÿÿˆÿÿ~ÿÿ—ÿÿ˜ÿÿ’ÿÿ�ÿÿˆÿÿƒÿÿ~ÿÿyÿÿtÿÿoÿÿjÿÿeÿý`ÿ÷[ÿñWÿêRÿäMÿÞHÿØDÿÑ>ÿÎ<ÿÓ@ÿÙDÿÞIÿåMÿëRÿñVÿ÷[ÿý`ÿÿdÿÿiÿÿnÿÿsÿÿzÿÿ~ÿÿNÿÿ3ÿÿEÿÿSÿÿaÿÿnÿÿ|ÿÿ‰ÿÿ—ÿÿcÿÿfÿÿjÿÿnÿÿrÿÿvÿÿzÿÿ~ÿÿ‚ÿÿ†ÿÿŠÿÿŽÿÿ’ÿÿ—ÿÿ›ÿÿžÿÿŸÿÿœÿÿ›ÿÿŸÿÿ¨ÿÿ²ÿÿ¶ÿÿ¯ÿÿ¤ÿÿ˜ÿÿŸÿÿ¥ÿÿ ÿÿ›ÿÿ—ÿÿ’ÿÿŽÿÿŠÿÿ…ÿÿ�ÿÿ}ÿÿxÿÿtÿÿpÿÿkÿÿgÿÿcÿû_ÿöZÿðVÿëRÿåNÿàIÿÚEÿÕAÿÖBÿÜFÿáKÿæOÿìTÿñVÿ÷[ÿý`ÿÿcÿÿhÿÿnÿÿqÿÿvÿÿzÿÿÿÿ„ÿÿ‰ÿÿ�ÿÿ“ÿÿ™ÿÿ•ÿÿ‹ÿÿˆÿÿ“ÿÿ¡ÿÿ­ÿÿ·ÿÿ±ÿÿ¤ÿÿ—ÿÿ‹ÿÿ~ÿÿoÿÿˆÿÿ•ÿÿŽÿÿ‰ÿÿ„ÿÿÿÿzÿÿuÿÿpÿÿkÿÿfÿþaÿø\ÿòXÿìSÿåNÿßHÿÙDÿÒ?ÿÍ;ÿÏ=ÿÕAÿÛFÿáJÿçOÿíSÿóXÿù]ÿþaÿÿfÿÿkÿÿpÿÿwÿÿuÿÿEÿÿ+ÿÿ<ÿÿJÿÿXÿÿfÿÿsÿÿ�ÿÿŽÿÿœÿÿjÿÿmÿÿqÿÿuÿÿyÿÿ}ÿÿ�ÿÿ…ÿÿ‰ÿÿŽÿÿ“ÿÿ—ÿÿ˜ÿÿ–ÿÿ‘ÿÿŽÿÿ’ÿÿ™ÿÿ¤ÿÿ°ÿÿ¶ÿÿ²ÿÿ§ÿÿœÿÿ‘ÿÿ‰ÿÿžÿÿ�ÿÿ˜ÿÿ”ÿÿ�ÿÿŒÿÿ‡ÿÿƒÿÿÿÿzÿÿvÿÿrÿÿmÿÿiÿÿeÿý`ÿø\ÿóXÿíTÿèPÿãKÿÝGÿ×CÿÓ@ÿÖAÿÛFÿáJÿæNÿìSÿñXÿ÷Zÿü_ÿÿdÿÿhÿÿlÿÿqÿÿvÿÿzÿÿÿÿ„ÿÿˆÿÿŽÿÿ”ÿÿ“ÿÿ‚ÿÿ{ÿÿ…ÿÿ“ÿÿŸÿÿ¬ÿÿ·ÿÿ³ÿÿ¥ÿÿ™ÿÿŒÿÿÿÿsÿÿcÿÿvÿÿ‘ÿÿŠÿÿ…ÿÿ€ÿÿ{ÿÿvÿÿqÿÿlÿÿgÿþbÿù]ÿóXÿíTÿæOÿàJÿÚEÿÔAÿÍ;ÿÌ;ÿÒ?ÿ×CÿÞGÿäLÿêPÿïUÿöZÿü^ÿÿcÿÿhÿÿmÿÿvÿÿoÿÿ/ÿÿ"ÿÿ4ÿÿBÿÿPÿÿ]ÿÿkÿÿyÿÿ†ÿÿ”ÿÿ¡ÿÿqÿÿtÿÿyÿÿ}ÿÿ�ÿÿ…ÿÿŠÿÿ�ÿÿ‘ÿÿ�ÿÿŠÿÿ„ÿÿ€ÿÿ„ÿÿŒÿÿ—ÿÿ¢ÿÿ®ÿÿµÿÿ´ÿÿ«ÿÿŸÿÿ•ÿÿŠÿÿ}ÿÿ†ÿÿœÿÿ–ÿÿ‘ÿÿ�ÿÿ‰ÿÿ„ÿÿ€ÿÿ|ÿÿxÿÿsÿÿoÿÿkÿÿgÿþbÿú^ÿõYÿðUÿêQÿåMÿàIÿÚEÿÔAÿÒ?ÿÖAÿÛFÿáKÿæNÿìRÿñWÿ÷[ÿü_ÿÿcÿÿhÿÿlÿÿqÿÿuÿÿzÿÿÿÿƒÿÿ‰ÿÿ�ÿÿ�ÿÿ|ÿÿqÿÿwÿÿ…ÿÿ’ÿÿžÿÿ«ÿÿ·ÿÿ´ÿÿ§ÿÿšÿÿŽÿÿ�ÿÿtÿÿgÿÿWÿÿaÿÿŒÿÿ…ÿÿ€ÿÿ{ÿÿvÿÿqÿÿlÿÿgÿÿcÿú^ÿôYÿîTÿèOÿáKÿÛFÿÕAÿÎ<ÿÉ9ÿÎ<ÿÔAÿÚDÿàIÿæNÿìRÿòWÿø[ÿþ`ÿÿeÿÿjÿÿtÿÿ`ÿÿ%ÿÿÿÿ,ÿÿ:ÿÿHÿÿUÿÿcÿÿqÿÿ~ÿÿŒÿÿ™ÿÿ§ÿÿxÿÿ|ÿÿ�ÿÿ†ÿÿŠÿÿŠÿÿ…ÿÿ{ÿÿsÿÿpÿÿvÿÿÿÿ‹ÿÿ–ÿÿ¡ÿÿ¬ÿÿ´ÿÿ¶ÿÿ­ÿÿ¢ÿÿ—ÿÿ�ÿÿ‚ÿÿwÿÿkÿÿŒÿÿ”ÿÿŽÿÿŠÿÿ†ÿÿ�ÿÿ}ÿÿyÿÿuÿÿpÿÿlÿÿhÿÿdÿü_ÿ÷[ÿòWÿíSÿçNÿâJÿÝGÿ×BÿÒ?ÿÑ>ÿÖBÿÛFÿáJÿæNÿìRÿñWÿ÷[ÿü_ÿÿdÿÿhÿÿlÿÿqÿÿvÿÿzÿÿÿÿ…ÿÿ‹ÿÿ‡ÿÿsÿÿdÿÿjÿÿxÿÿ†ÿÿ‘ÿÿžÿÿ«ÿÿ¶ÿÿµÿÿ¨ÿÿ›ÿÿ�ÿÿ‚ÿÿvÿÿhÿÿ[ÿÿLÿÿMÿÿƒÿÿ�ÿÿ|ÿÿwÿÿrÿÿmÿÿgÿÿcÿû^ÿõYÿîUÿèPÿâJÿÜGÿÕBÿÏ=ÿÉ9ÿË9ÿÑ>ÿ×BÿÝFÿãKÿéPÿïTÿõYÿû^ÿÿbÿÿhÿÿpÿÿRÿÿÿÿÿÿ%ÿÿ2ÿÿ@ÿÿNÿÿ\ÿÿiÿÿwÿÿ„ÿÿ’ÿÿŸÿÿ¬ÿÿƒÿÿƒÿÿÿÿvÿÿlÿÿbÿÿbÿÿiÿÿuÿÿ€ÿÿ‹ÿÿ•ÿÿ ÿÿªÿÿ´ÿÿ¶ÿÿ¯ÿÿ¤ÿÿ™ÿÿ�ÿÿ„ÿÿzÿÿoÿÿaÿÿiÿÿ�ÿÿŒÿÿ‡ÿÿ‚ÿÿ~ÿÿzÿÿvÿÿqÿÿmÿÿiÿÿeÿþ`ÿù]ÿôXÿïTÿéPÿäLÿßHÿÙDÿÓ@ÿÏ=ÿÐ>ÿÖAÿÜFÿáJÿæNÿìRÿñWÿ÷[ÿü_ÿÿdÿÿhÿÿlÿÿqÿÿvÿÿzÿÿ€ÿÿ‡ÿÿ�ÿÿkÿÿYÿÿ\ÿÿkÿÿyÿÿ…ÿÿ‘ÿÿ�ÿÿªÿÿ¶ÿÿµÿÿ©ÿÿœÿÿ�ÿÿƒÿÿvÿÿiÿÿ\ÿÿOÿÿAÿÿ:ÿÿzÿÿ}ÿÿwÿÿrÿÿmÿÿhÿÿcÿü_ÿõZÿïUÿéPÿãKÿÜGÿÖBÿÐ>ÿÉ8ÿÈ7ÿÍ;ÿÔ@ÿÚDÿàHÿåMÿìRÿòWÿø[ÿþ`ÿÿfÿÿkÿý=ÿþÿÿ ÿÿÿÿ+ÿÿ9ÿÿFÿÿTÿÿbÿÿoÿÿ}ÿÿ‹ÿÿ˜ÿÿ¦ÿÿ³ÿÿ`ÿÿUÿÿPÿÿUÿÿ^ÿÿjÿÿvÿÿ€ÿÿŠÿÿ”ÿÿŸÿÿ©ÿÿ³ÿÿ¶ÿÿ°ÿÿ¦ÿÿ›ÿÿ�ÿÿ†ÿÿ|ÿÿqÿÿfÿÿZÿÿNÿÿzÿÿŠÿÿƒÿÿÿÿ{ÿÿwÿÿsÿÿnÿÿjÿÿfÿþbÿû^ÿöZÿðUÿëQÿæMÿàIÿÛEÿÕAÿÐ=ÿÍ<ÿÑ?ÿÖCÿÜGÿáKÿçOÿìSÿòWÿ÷[ÿü_ÿÿdÿÿhÿÿmÿÿqÿÿvÿÿ|ÿÿ‚ÿÿ|ÿÿbÿÿMÿÿPÿÿ_ÿÿlÿÿyÿÿ…ÿÿ‘ÿÿ�ÿÿªÿÿ¶ÿÿµÿÿ¨ÿÿœÿÿ�ÿÿƒÿÿvÿÿiÿÿ\ÿÿOÿÿBÿÿ3ÿÿ.ÿÿuÿÿxÿÿrÿÿmÿÿhÿÿdÿü_ÿöZÿïUÿéPÿãLÿÝGÿ×CÿÐ>ÿÊ9ÿÆ6ÿÊ9ÿÐ=ÿÖBÿÜFÿâKÿéPÿïTÿõYÿû]ÿÿfÿþcÿù)ÿûÿÿÿÿÿÿ$ÿÿ2ÿÿ?ÿÿMÿÿ[ÿÿhÿÿvÿÿ„ÿÿ’ÿÿŸÿÿ¬ÿÿ¸ÿÿJÿÿUÿÿaÿÿlÿÿvÿÿ€ÿÿ‹ÿÿ”ÿÿŸÿÿ©ÿÿ³ÿÿ·ÿÿ±ÿÿ§ÿÿœÿÿ’ÿÿ‡ÿÿ}ÿÿrÿÿgÿÿ\ÿÿQÿÿCÿÿRÿÿ…ÿÿ€ÿÿ|ÿÿxÿÿsÿÿoÿÿkÿÿgÿÿcÿü_ÿ÷[ÿòVÿìRÿçNÿâJÿÜFÿ×CÿÒ>ÿÍ;ÿÍ;ÿÒ?ÿØCÿÝGÿâKÿçOÿíSÿòWÿø\ÿý`ÿÿdÿÿiÿÿmÿÿrÿÿxÿÿ~ÿÿwÿÿZÿÿBÿÿDÿÿSÿÿ`ÿÿmÿÿyÿÿ…ÿÿ’ÿÿžÿÿ«ÿÿ¶ÿÿµÿÿ©ÿÿœÿÿ�ÿÿƒÿÿvÿÿiÿÿ\ÿÿOÿÿBÿÿ4ÿÿ'ÿÿÿÿaÿÿuÿÿmÿÿhÿÿdÿü_ÿöZÿðUÿêPÿãLÿÝGÿ×CÿÑ>ÿÊ9ÿÅ5ÿÇ7ÿÎ<ÿÔ@ÿÚDÿàIÿåMÿìRÿòVÿø[ÿÿeÿûQÿòÿ÷ÿÿÿÿÿÿÿÿ+ÿÿ9ÿÿGÿÿTÿÿbÿÿpÿÿ}ÿÿ‹ÿÿ˜ÿÿ¦ÿÿ´ÿÿ·ÿÿbÿÿmÿÿwÿÿ�ÿÿ‹ÿÿ•ÿÿŸÿÿ©ÿÿ³ÿÿ¶ÿÿ±ÿÿ¦ÿÿœÿÿ’ÿÿˆÿÿ}ÿÿrÿÿhÿÿ]ÿÿRÿÿGÿÿ;ÿÿ3ÿÿqÿÿÿÿxÿÿtÿÿpÿÿlÿÿgÿÿcÿý_ÿø[ÿóWÿîSÿèOÿãKÿÞGÿÙCÿÓ@ÿÍ<ÿÊ9ÿÍ;ÿÓ@ÿØDÿÝHÿãLÿèPÿîTÿóXÿù\ÿþaÿÿeÿÿiÿÿnÿÿuÿÿzÿÿlÿÿRÿÿ8ÿÿ9ÿÿGÿÿUÿÿaÿÿnÿÿzÿÿ‡ÿÿ“ÿÿŸÿÿ¬ÿÿ¶ÿÿ´ÿÿ¨ÿÿ›ÿÿ�ÿÿ‚ÿÿuÿÿiÿÿ\ÿÿOÿÿAÿÿ4ÿÿ'ÿÿÿÿ ÿÿTÿÿqÿÿiÿÿdÿü_ÿöZÿðUÿêPÿãLÿÝGÿ×BÿÑ>ÿÊ9ÿÄ5ÿÅ5ÿË:ÿÑ>ÿ×BÿÝGÿãKÿéPÿïTÿõZÿübÿöAÿí ÿóÿýÿÿ ÿÿÿÿ%ÿÿ2ÿÿ@ÿÿNÿÿ\ÿÿiÿÿwÿÿ…ÿÿ’ÿÿ ÿÿ­ÿÿ¸ÿÿ±ÿÿxÿÿ‚ÿÿŒÿÿ–ÿÿ ÿÿªÿÿ³ÿÿ¶ÿÿ±ÿÿ§ÿÿœÿÿ’ÿÿ‡ÿÿ}ÿÿsÿÿhÿÿ]ÿÿSÿÿHÿÿ=ÿÿ2ÿÿ"ÿÿLÿÿ|ÿÿtÿÿpÿÿlÿÿhÿÿdÿý`ÿù\ÿôXÿîTÿéPÿäLÿßHÿÚDÿÔ@ÿÏ<ÿÊ9ÿÊ9ÿÎ<ÿÔ@ÿÙEÿÞIÿäMÿéQÿïUÿôYÿú]ÿþaÿÿeÿÿjÿÿrÿÿtÿÿeÿÿ?ÿÿ(ÿÿ-ÿÿ=ÿÿKÿÿWÿÿcÿÿoÿÿ|ÿÿˆÿÿ”ÿÿ¡ÿÿ­ÿÿ·ÿÿ³ÿÿ§ÿÿšÿÿŽÿÿ�ÿÿuÿÿhÿÿ[ÿÿNÿÿAÿÿ3ÿÿ&ÿÿÿÿ ÿýÿþZÿÿkÿÿcÿü_ÿöZÿðUÿêPÿãLÿÝGÿ×BÿÑ>ÿÊ9ÿÄ4ÿÂ4ÿÈ8ÿÏ<ÿÔ@ÿÚEÿàIÿæNÿìRÿôZÿ÷Wÿì)ÿçÿðÿùÿÿÿÿÿÿÿÿ,ÿÿ:ÿÿHÿÿVÿÿcÿÿqÿÿÿÿŒÿÿšÿÿ§ÿÿµÿÿ¶ÿÿ©ÿÿ�ÿÿ˜ÿÿ¢ÿÿ¬ÿÿ´ÿÿ¶ÿÿ°ÿÿ¦ÿÿ›ÿÿ‘ÿÿ‡ÿÿ}ÿÿrÿÿhÿÿ]ÿÿSÿÿHÿÿ=ÿÿ2ÿÿ'ÿÿÿÿ&ÿÿoÿÿrÿÿlÿÿhÿÿdÿþ`ÿú\ÿôXÿïTÿêPÿåMÿàIÿÚEÿÕAÿÐ=ÿÊ9ÿÇ7ÿÊ9ÿÐ=ÿÕAÿÚEÿàJÿåMÿêQÿðVÿõYÿû^ÿÿbÿÿgÿÿoÿÿmÿÿVÿÿ,ÿÿÿÿ#ÿÿ3ÿÿ@ÿÿLÿÿXÿÿeÿÿrÿÿ}ÿÿŠÿÿ–ÿÿ£ÿÿ¯ÿÿ¸ÿÿ²ÿÿ¥ÿÿ™ÿÿŒÿÿ€ÿÿsÿÿfÿÿYÿÿMÿÿ?ÿÿ2ÿÿ%ÿÿÿÿ ÿüÿöÿþaÿÿdÿü^ÿöZÿïUÿéPÿãKÿÝGÿÖBÿÐ>ÿÊ9ÿÃ4ÿÁ2ÿÅ6ÿÌ:ÿÒ?ÿØCÿÞHÿäLÿêQÿòYÿïHÿáÿâÿíÿõÿþÿÿ ÿÿÿÿ'ÿÿ5ÿÿBÿÿPÿÿ^ÿÿlÿÿyÿÿ‡ÿÿ”ÿÿ¢ÿÿ°ÿÿ¹ÿÿ¯ÿÿ¡ÿÿ¤ÿÿ®ÿÿµÿÿ¶ÿÿ®ÿÿ¤ÿÿšÿÿ�ÿÿ†ÿÿ{ÿÿqÿÿgÿÿ\ÿÿRÿÿGÿÿ<ÿÿ1ÿÿ'ÿÿÿÿÿÿÿÿYÿÿpÿÿhÿÿdÿþ`ÿú\ÿõYÿðUÿëQÿåMÿàIÿÛEÿÖAÿÐ>ÿË9ÿÆ7ÿÇ7ÿË;ÿÑ>ÿÖBÿÜFÿáJÿæNÿìRÿñWÿ÷Zÿü_ÿÿeÿÿlÿÿeÿþEÿÿÿÿÿÿÿÿ)ÿÿ6ÿÿBÿÿNÿÿ[ÿÿgÿÿtÿÿ€ÿÿŒÿÿ˜ÿÿ¥ÿÿ±ÿÿ¸ÿÿ°ÿÿ£ÿÿ—ÿÿ‹ÿÿ~ÿÿqÿÿeÿÿXÿÿKÿÿ>ÿÿ1ÿÿ#ÿÿÿÿÿüÿôÿìÿý[ÿü_ÿõYÿïTÿéPÿãKÿÝFÿÖBÿÐ=ÿÊ9ÿÃ4ÿ¿1ÿÃ4ÿÉ9ÿÏ=ÿÕAÿÛFÿáJÿèPÿîTÿä3ÿÙÿßÿéÿòÿûÿÿÿÿÿÿ!ÿÿ/ÿÿ=ÿÿKÿÿYÿÿfÿÿtÿÿ‚ÿÿ�ÿÿ�ÿÿªÿÿ·ÿÿ´ÿÿ§ÿÿ™ÿÿ¶ÿÿ´ÿÿ¬ÿÿ¢ÿÿ˜ÿÿŽÿÿ„ÿÿzÿÿpÿÿeÿÿ[ÿÿQÿÿFÿÿ;ÿÿ1ÿÿ&ÿÿÿÿÿÿÿûÿü;ÿÿmÿÿdÿþ`ÿú\ÿõYÿðVÿëQÿæMÿàIÿÛEÿÖBÿÑ>ÿË:ÿÆ6ÿÄ5ÿÈ7ÿÍ<ÿÓ@ÿØDÿÝGÿãLÿèOÿíTÿóWÿù\ÿþcÿÿgÿýYÿû6ÿý ÿÿÿÿÿÿ ÿÿ,ÿÿ9ÿÿEÿÿQÿÿ^ÿÿjÿÿvÿÿƒÿÿ�ÿÿ›ÿÿ§ÿÿ³ÿÿ·ÿÿ®ÿÿ¡ÿÿ•ÿÿ‰ÿÿ|ÿÿpÿÿcÿÿVÿÿIÿÿ<ÿÿ/ÿÿ!ÿÿÿÿÿûÿóÿéÿæÿú[ÿõYÿîTÿèOÿâJÿÜFÿÕAÿÏ=ÿÉ8ÿÂ3ÿ¾0ÿÁ3ÿÇ8ÿÍ;ÿÓ@ÿÙDÿàIÿçPÿçIÿÖÿÓÿÝÿæÿïÿøÿÿÿÿÿÿÿÿ*ÿÿ8ÿÿFÿÿTÿÿaÿÿoÿÿ}ÿÿŠÿÿ˜ÿÿ¥ÿÿ³ÿÿ¸ÿÿ¬ÿÿžÿÿ�ÿÿªÿÿŸÿÿ•ÿÿŒÿÿ‚ÿÿwÿÿmÿÿcÿÿYÿÿOÿÿDÿÿ:ÿÿ/ÿÿ$ÿÿÿÿÿþÿûÿóÿõ"ÿÿfÿþaÿú\ÿõXÿðUÿëQÿåNÿàIÿÛEÿÖBÿÑ>ÿÌ:ÿÆ6ÿÃ4ÿÅ5ÿÊ9ÿÏ=ÿÔAÿÚEÿßIÿäMÿêQÿïUÿõZÿûaÿý`ÿúJÿõ ÿ÷ÿýÿÿ ÿÿÿÿ$ÿÿ/ÿÿ<ÿÿHÿÿUÿÿaÿÿmÿÿyÿÿ†ÿÿ’ÿÿžÿÿªÿÿµÿÿ¶ÿÿ«ÿÿŸÿÿ“ÿÿ†ÿÿzÿÿmÿÿ`ÿÿSÿÿFÿÿ9ÿÿ,ÿÿÿÿÿÿÿúÿòÿéÿßÿáÿôZÿíSÿçNÿáJÿÛEÿÕ@ÿÏ<ÿÈ8ÿÂ3ÿ½/ÿ¿1ÿÅ6ÿË:ÿÑ>ÿ×CÿÞHÿäMÿÜ4ÿÌ ÿÐÿÚÿãÿìÿõÿþÿÿ ÿÿÿÿ&ÿÿ3ÿÿAÿÿOÿÿ]ÿÿkÿÿxÿÿ†ÿÿ“ÿÿ¡ÿÿ®ÿÿ¹ÿÿ±ÿÿ£ÿÿ•ÿÿˆÿÿ’ÿÿ‰ÿÿÿÿuÿÿkÿÿ`ÿÿVÿÿLÿÿBÿÿ7ÿÿ-ÿÿ"ÿÿÿÿ ÿþÿúÿóÿëÿìÿûYÿú_ÿôXÿïTÿêPÿåMÿàJÿÛEÿÖAÿÑ>ÿÌ:ÿÆ6ÿÂ3ÿÂ4ÿÇ6ÿÌ;ÿÑ>ÿÖBÿÜFÿáJÿæNÿìSÿòYÿ÷]ÿøTÿó6ÿïÿñÿùÿþÿÿÿÿÿÿ(ÿÿ4ÿÿ@ÿÿKÿÿXÿÿeÿÿqÿÿ}ÿÿ‰ÿÿ•ÿÿ¡ÿÿ­ÿÿ·ÿÿ´ÿÿ¨ÿÿ›ÿÿ�ÿÿƒÿÿwÿÿjÿÿ]ÿÿQÿÿCÿÿ6ÿÿ*ÿÿÿÿÿþÿùÿðÿçÿÞÿÔÿß)ÿîVÿæNÿàIÿÚDÿÓ@ÿÍ;ÿÇ7ÿÁ2ÿ»/ÿ½0ÿÄ5ÿÊ9ÿÐ=ÿÖAÿÞIÿÝCÿÌÿÅÿÎÿØÿàÿéÿòÿûÿÿÿÿÿÿ!ÿÿ/ÿÿ=ÿÿKÿÿYÿÿfÿÿtÿÿ‚ÿÿ�ÿÿœÿÿªÿÿ·ÿÿµÿÿ§ÿÿšÿÿŒÿÿ~ÿÿ{ÿÿrÿÿhÿÿ]ÿÿSÿÿIÿÿ>ÿÿ4ÿÿ*ÿÿÿÿÿÿ ÿýÿùÿòÿëÿãÿßÿôNÿõ[ÿîTÿéQÿäLÿßHÿÚEÿÕBÿÑ=ÿË:ÿÆ6ÿÁ3ÿÀ2ÿÄ4ÿÉ8ÿÎ<ÿÓ@ÿÙDÿÞHÿãLÿêRÿïWÿòVÿðCÿé#ÿçÿìÿôÿüÿÿÿÿÿÿ ÿÿ,ÿÿ8ÿÿDÿÿPÿÿ\ÿÿiÿÿuÿÿ�ÿÿ�ÿÿ™ÿÿ¥ÿÿ±ÿÿ¸ÿÿ±ÿÿ¥ÿÿ˜ÿÿ�ÿÿ€ÿÿsÿÿgÿÿZÿÿMÿÿ@ÿÿ3ÿÿ&ÿÿÿÿ ÿþÿ÷ÿîÿåÿÜÿÔÿÉÿÞ6ÿæPÿßHÿÙCÿÒ?ÿÌ:ÿÆ6ÿÀ1ÿº.ÿ¼/ÿÂ3ÿÈ8ÿÎ<ÿÖBÿÛFÿÐ/ÿ¿ ÿÂÿÌÿÕÿÞÿçÿðÿùÿÿÿÿÿÿÿÿ+ÿÿ:ÿÿGÿÿUÿÿbÿÿpÿÿ~ÿÿ‹ÿÿ™ÿÿ¦ÿÿ´ÿÿ¸ÿÿ«ÿÿžÿÿ�ÿÿ‚ÿÿtÿÿdÿÿZÿÿOÿÿEÿÿ;ÿÿ1ÿÿ&ÿÿÿÿÿÿÿýÿ÷ÿðÿéÿâÿÚÿ×ÿëDÿïVÿèOÿäKÿßHÿÚEÿÕ@ÿÐ=ÿÊ9ÿÅ6ÿÀ2ÿ¾0ÿÁ3ÿÆ6ÿË:ÿÑ>ÿÖAÿÛFÿàJÿçQÿìTÿêHÿä-ÿÞÿàÿçÿðÿøÿþÿÿ ÿÿÿÿ$ÿÿ0ÿÿ<ÿÿIÿÿUÿÿaÿÿmÿÿyÿÿ…ÿÿ‘ÿÿ�ÿÿ©ÿÿ´ÿÿ·ÿÿ­ÿÿ ÿÿ”ÿÿ‰ÿÿ|ÿÿpÿÿcÿÿVÿÿJÿÿ=ÿÿ0ÿÿ#ÿÿÿÿÿýÿõÿìÿãÿÚÿÑÿÈÿÂÿÞBÿÞHÿ×BÿÑ>ÿË9ÿÅ5ÿ¾0ÿ¹-ÿº.ÿÁ2ÿÇ7ÿÍ;ÿÕBÿÑ9ÿ½ÿ¸ÿÁÿÊÿÓÿÜÿåÿîÿ÷ÿþÿÿ ÿÿÿÿ(ÿÿ6ÿÿCÿÿQÿÿ_ÿÿmÿÿzÿÿˆÿÿ•ÿÿ¢ÿÿ°ÿÿ¹ÿÿ¯ÿÿ¡ÿÿ”ÿÿ†ÿÿxÿÿjÿÿKÿÿAÿÿ7ÿÿ-ÿÿ"ÿÿÿÿ ÿþÿûÿõÿîÿçÿàÿÙÿÑÿÎÿä@ÿéRÿâKÿÞHÿÙCÿÔ@ÿÏ=ÿÊ9ÿÅ5ÿ¿1ÿ¼/ÿ¿1ÿÄ4ÿÉ8ÿÎ<ÿÓ@ÿØDÿßJÿäNÿæJÿß5ÿÙÿÖÿÛÿãÿìÿôÿûÿÿÿÿÿÿÿÿ)ÿÿ5ÿÿAÿÿNÿÿZÿÿfÿÿrÿÿ~ÿÿŠÿÿ•ÿÿ¡ÿÿ®ÿÿ·ÿÿµÿÿ©ÿÿœÿÿ�ÿÿ„ÿÿxÿÿlÿÿ_ÿÿRÿÿFÿÿ9ÿÿ,ÿÿÿÿÿÿÿúÿòÿéÿáÿØÿÏÿÆÿ¼ÿ¿ÿÜFÿÖBÿÏ=ÿÊ8ÿÃ4ÿ½/ÿ·,ÿ¹-ÿ¿1ÿÅ6ÿÍ<ÿÐ=ÿÀ"ÿ±ÿµÿ¿ÿÈÿÑÿÚÿãÿìÿõÿýÿÿ ÿÿÿÿ%ÿÿ3ÿÿ@ÿÿNÿÿ\ÿÿiÿÿwÿÿ…ÿÿ’ÿÿŸÿÿ­ÿÿ¸ÿÿ³ÿÿ¥ÿÿ—ÿÿŠÿÿ|ÿÿnÿÿ_ÿÿ2ÿÿ(ÿÿÿÿÿÿ ÿýÿùÿòÿëÿäÿÝÿÖÿÐÿÈÿÅÿÝ<ÿãMÿÜFÿ×BÿÒ?ÿÎ;ÿÈ8ÿÃ4ÿ¾1ÿ».ÿ¼/ÿÁ3ÿÇ7ÿÌ:ÿÑ>ÿ×DÿÝIÿßHÿÚ8ÿÑÿÎ ÿÏÿ×ÿàÿèÿðÿøÿþÿÿ ÿÿÿÿ#ÿÿ/ÿÿ;ÿÿGÿÿSÿÿ_ÿÿkÿÿwÿÿƒÿÿŽÿÿšÿÿ¦ÿÿ²ÿÿ¸ÿÿ±ÿÿ¤ÿÿ™ÿÿŒÿÿ€ÿÿtÿÿgÿÿ[ÿÿNÿÿAÿÿ4ÿÿ'ÿÿÿÿ ÿþÿøÿïÿçÿÞÿÕÿÌÿÄÿ»ÿ°ÿÄ$ÿÖCÿÎ<ÿÈ7ÿÁ3ÿ».ÿ¶+ÿ¸,ÿ¾1ÿÅ6ÿÌ;ÿÃ-ÿ¯ÿªÿ´ÿ¾ÿÆÿÏÿØÿáÿêÿóÿüÿÿÿÿÿÿ"ÿÿ0ÿÿ>ÿÿKÿÿYÿÿgÿÿtÿÿ‚ÿÿ�ÿÿ�ÿÿªÿÿ·ÿÿ¶ÿÿ¨ÿÿšÿÿ�ÿÿÿÿqÿÿcÿÿTÿÿÿÿÿÿÿûÿöÿïÿèÿáÿÛÿÔÿÍÿÆÿ½ÿ»ÿÖ8ÿÜHÿÖAÿÑ>ÿÌ:ÿÇ7ÿÂ3ÿ½0ÿ¹-ÿº.ÿ¿1ÿÄ5ÿÊ9ÿÐ=ÿÖCÿÙDÿÔ7ÿÌ#ÿÅ ÿÅÿÌÿÕÿÜÿäÿíÿôÿûÿÿÿÿÿÿÿÿ)ÿÿ5ÿÿAÿÿMÿÿXÿÿeÿÿqÿÿ|ÿÿˆÿÿ”ÿÿŸÿÿ«ÿÿ¶ÿÿ¶ÿÿ¬ÿÿŸÿÿ“ÿÿ‡ÿÿ{ÿÿoÿÿbÿÿVÿÿIÿÿ<ÿÿ/ÿÿ#ÿÿÿÿÿýÿõÿíÿäÿÛÿÒÿÊÿÁÿ¸ÿ¯ÿ§ÿÊ4ÿÍ<ÿÆ6ÿ¿2ÿ¹-ÿµ*ÿ·+ÿ¾1ÿÆ6ÿÃ2ÿ¯ÿ¢ÿ©ÿ´ÿ¼ÿÅÿÎÿ×ÿàÿéÿòÿûÿÿÿÿÿÿÿÿ-ÿÿ;ÿÿIÿÿWÿÿdÿÿrÿÿÿÿ�ÿÿšÿÿ¨ÿÿµÿÿ·ÿÿ«ÿÿ�ÿÿ�ÿÿ‚ÿÿtÿÿfÿÿXÿÿIÿýÿùÿóÿìÿåÿÞÿØÿÑÿÊÿÃÿ¼ÿ´ÿ²ÿÏ4ÿÖCÿÏ<ÿÊ9ÿÆ6ÿÀ2ÿ»/ÿ¸,ÿ¹-ÿ½0ÿÃ4ÿÉ8ÿÏ=ÿÒ?ÿÏ7ÿÇ&ÿ¾ÿ»ÿÁÿÊÿÒÿÙÿáÿéÿñÿùÿþÿÿ ÿÿÿÿ#ÿÿ/ÿÿ;ÿÿGÿÿSÿÿ_ÿÿjÿÿvÿÿ‚ÿÿ�ÿÿ™ÿÿ¥ÿÿ±ÿÿ¸ÿÿ²ÿÿ¦ÿÿšÿÿŽÿÿ‚ÿÿvÿÿiÿÿ]ÿÿPÿÿDÿÿ7ÿÿ*ÿÿÿÿÿÿÿúÿòÿéÿáÿØÿÏÿÇÿ¾ÿµÿ­ÿ¢ÿ©ÿÊ9ÿÄ4ÿ½0ÿ·+ÿ³(ÿ·+ÿ¾1ÿÁ2ÿ± ÿ�ÿŸÿ©ÿ²ÿ»ÿÄÿÌÿÖÿßÿçÿðÿùÿÿÿÿÿÿÿÿ+ÿÿ9ÿÿFÿÿTÿÿbÿÿoÿÿ}ÿÿ‹ÿÿ˜ÿÿ¥ÿÿ³ÿÿ¸ÿÿ­ÿÿŸÿÿ’ÿÿ„ÿÿvÿÿhÿÿZÿÿLÿÿ=ÿïÿèÿáÿÚÿÔÿÍÿÆÿ¿ÿ¸ÿ²ÿ©ÿªÿÇ1ÿÏ>ÿÈ7ÿÄ4ÿ¾1ÿ¹-ÿ¶+ÿ·,ÿ¼/ÿÂ4ÿÈ9ÿË:ÿÈ3ÿ¾#ÿµÿ²ÿ·ÿ¿ÿÇÿÏÿ×ÿÞÿæÿîÿöÿüÿÿÿÿÿÿÿÿ*ÿÿ6ÿÿBÿÿMÿÿYÿÿeÿÿqÿÿ|ÿÿˆÿÿ”ÿÿŸÿÿ¬ÿÿ¶ÿÿ·ÿÿ¬ÿÿ ÿÿ”ÿÿˆÿÿ|ÿÿpÿÿdÿÿWÿÿJÿÿ>ÿÿ1ÿÿ$ÿÿÿÿ ÿþÿ÷ÿîÿæÿÝÿÔÿÌÿÃÿºÿ²ÿ©ÿ ÿ–ÿ´#ÿÄ5ÿ».ÿµ*ÿ²(ÿ·,ÿ½0ÿ±$ÿš ÿ–ÿŸÿ©ÿ±ÿºÿÃÿÌÿÔÿÞÿæÿïÿøÿÿÿÿ ÿÿÿÿ)ÿÿ7ÿÿEÿÿRÿÿ`ÿÿnÿÿ{ÿÿ‰ÿÿ–ÿÿ£ÿÿ²ÿÿ¹ÿÿ¯ÿÿ¢ÿÿ”ÿÿ‡ÿÿyÿÿkÿÿ]ÿÿNÿÿ@ÿÿ1ÿÝÿÖÿÏÿÉÿÂÿ¼ÿµÿ®ÿ§ÿžÿ¦ ÿÆ3ÿÇ8ÿÁ2ÿ¼/ÿ·,ÿ´*ÿ¶+ÿ¼/ÿÂ4ÿÅ5ÿÁ/ÿ·!ÿ­ÿ©ÿ­ÿµÿ½ÿÅÿÍÿÔÿÜÿãÿëÿóÿúÿÿÿÿ ÿÿÿÿ%ÿÿ1ÿÿ=ÿÿIÿÿTÿÿ`ÿÿlÿÿxÿÿƒÿÿ�ÿÿšÿÿ¦ÿÿ²ÿÿ¸ÿÿ²ÿÿ¦ÿÿšÿÿŽÿÿ‚ÿÿvÿÿjÿÿ^ÿÿQÿÿDÿÿ8ÿÿ+ÿÿÿÿÿÿÿûÿóÿëÿâÿÙÿÐÿÈÿ¿ÿ¶ÿ­ÿ¦ÿ�ÿ“ÿ– ÿ½0ÿ¹,ÿ³&ÿ²$ÿ·,ÿ±'ÿ˜ÿŽÿ–ÿ ÿ¨ÿ±ÿ¹ÿÂÿËÿÔÿÝÿæÿïÿøÿþÿÿ ÿÿÿÿ(ÿÿ6ÿÿCÿÿQÿÿ_ÿÿlÿÿzÿÿ‡ÿÿ”ÿÿ¢ÿÿ°ÿÿ¹ÿÿ±ÿÿ£ÿÿ–ÿÿˆÿÿzÿÿlÿÿ^ÿÿPÿÿBÿÿ3ÿÿ$ÿËÿÅÿ¾ÿ·ÿ°ÿªÿ¤ÿ�ÿ”ÿ¤ÿ¿0ÿÀ2ÿ¹-ÿµ*ÿ´)ÿ·+ÿ¼/ÿ½0ÿ¸)ÿ°ÿ¥ ÿ ÿ¤ÿ«ÿ´ÿ¼ÿÃÿËÿÒÿÚÿáÿéÿðÿøÿþÿÿ ÿÿÿÿ!ÿÿ-ÿÿ8ÿÿDÿÿPÿÿ\ÿÿhÿÿsÿÿÿÿŠÿÿ–ÿÿ¡ÿÿ­ÿÿ·ÿÿ¶ÿÿ«ÿÿŸÿÿ“ÿÿ‡ÿÿ{ÿÿoÿÿcÿÿWÿÿJÿÿ>ÿÿ1ÿÿ%ÿÿÿÿ ÿþÿøÿïÿæÿÞÿÕÿÌÿÄÿ»ÿ²ÿªÿ¢ÿ™ÿ�ÿ‡ÿ¨ÿº)ÿ°(ÿ«7ÿ§Aÿ–ÿˆÿ�ÿ—ÿŸÿ¨ÿ°ÿ¹ÿÂÿÊÿÓÿÜÿåÿîÿ÷ÿþÿÿ ÿÿÿÿ'ÿÿ5ÿÿCÿÿPÿÿ^ÿÿkÿÿyÿÿ†ÿÿ”ÿÿ¡ÿÿ¯ÿÿ¹ÿÿ²ÿÿ¥ÿÿ—ÿÿŠÿÿ|ÿÿnÿÿ`ÿÿRÿÿCÿÿ5ÿÿ&ÿÿÿºÿ²ÿ¬ÿ¦ÿŸÿ™ÿ’ÿ�ÿ¢ÿ½-ÿ¸)ÿ´$ÿ³)ÿ¶+ÿµ*ÿ¯#ÿ¤ÿ™ ÿ–ÿ›ÿ£ÿ«ÿ³ÿºÿÁÿÉÿÐÿØÿßÿçÿîÿöÿýÿÿÿÿÿÿÿÿ(ÿÿ6ÿÿ@ÿÿKÿÿXÿÿdÿÿoÿÿ{ÿÿ†ÿÿ’ÿÿ�ÿÿ©ÿÿ´ÿÿ¸ÿÿ°ÿÿ¤ÿÿ˜ÿÿŒÿÿ€ÿÿuÿÿhÿÿ\ÿÿPÿÿCÿÿ7ÿÿ*ÿÿÿÿÿÿÿûÿóÿêÿâÿÙÿÑÿÈÿ¿ÿ·ÿ®ÿ¦ÿ�ÿ•ÿ�ÿ„,%ÿ|€nÿ€´šÿ{­›ÿz¸£ÿyÚ¾ÿ}̬ÿ„ÿŽÿ—ÿŸÿ§ÿ°ÿ¸ÿÁÿÊÿÓÿÜÿåÿîÿ÷ÿþÿÿ ÿÿÿÿ&ÿÿ4ÿÿBÿÿOÿÿ]ÿÿkÿÿxÿÿ†ÿÿ“ÿÿ ÿÿ®ÿÿ¹ÿÿ³ÿÿ¦ÿÿ˜ÿÿŠÿÿ}ÿÿoÿÿaÿÿSÿÿDÿÿ6ÿÿ'ÿÿÿÿ ÿ¨ÿ¡ÿ›ÿ”ÿŽÿ‡ÿ�:1ÿ’M6ÿ¥X3ÿª7ÿª9ÿ¤J&ÿ¥ÿ˜ÿŽÿ�ÿ“ÿ›ÿ£ÿªÿ²ÿ¹ÿÀÿÈÿÏÿÖÿÞÿåÿíÿõÿûÿÿÿÿÿÿÿÿ&ÿÿ2ÿÿ=ÿÿIÿÿTÿÿ`ÿÿlÿÿwÿÿƒÿÿŽÿÿ™ÿÿ¥ÿÿ±ÿÿ¸ÿÿ´ÿÿ¨ÿÿœÿÿ‘ÿÿ…ÿÿyÿÿmÿÿbÿÿUÿÿHÿÿ<ÿÿ0ÿÿ#ÿÿÿÿ ÿýÿ÷ÿîÿæÿÝÿÕÿÌÿÄÿ»ÿ²ÿªÿ¡ÿ™ÿ‘ ÿˆWGÿ¬‘ÿuâÆÿkê×ÿdâÙÿhåÖÿrêÐÿ|ìÇÿ…óÃÿŽ?1ÿ—ÿŸÿ§ÿ°ÿ¸ÿÂÿÊÿÓÿÜÿåÿîÿ÷ÿþÿÿ ÿÿÿÿ&ÿÿ4ÿÿAÿÿOÿÿ]ÿÿjÿÿxÿÿ…ÿÿ“ÿÿ ÿÿ­ÿÿ¹ÿÿ´ÿÿ¦ÿÿ™ÿÿ‹ÿÿ~ÿÿpÿÿbÿÿTÿÿEÿÿ7ÿÿ(ÿÿÿÿ ÿþÿ–ÿ�3(ÿˆ[Jÿ�†pÿz·žÿsÔ½ÿlãÑÿiãÕÿiáÓÿuÕ¾ÿ|ãÁÿ•}ÿ†ÿŒÿ”ÿœÿ£ÿ©ÿ±ÿ¸ÿ¿ÿÆÿÎÿÕÿÝÿäÿìÿóÿúÿÿÿÿ ÿÿÿÿ$ÿÿ/ÿÿ;ÿÿFÿÿRÿÿ]ÿÿiÿÿuÿÿÿÿ‹ÿÿ–ÿÿ¢ÿÿ®ÿÿ·ÿÿ¶ÿÿ¬ÿÿ ÿÿ”ÿÿ‰ÿÿ}ÿÿqÿÿeÿÿYÿÿMÿÿ@ÿÿ4ÿÿ'ÿÿÿÿÿÿÿúÿòÿéÿáÿØÿÐÿÇÿ¿ÿ¶ÿ­ÿ¥ÿ�ÿ”.#ÿŒ„hÿƒÒ¬ÿzïÌÿpêÒÿgÞÓÿdÛÔÿkßÐÿtåÊÿ}êÅÿ…î¾ÿŽý¿ÿ—{YÿŸÿ¨ÿ°ÿ¹ÿÂÿÊÿÓÿÜÿåÿîÿ÷ÿþÿÿ ÿÿÿÿ&ÿÿ4ÿÿAÿÿOÿÿ]ÿÿjÿÿxÿÿ…ÿÿ“ÿÿ ÿÿ­ÿÿ¹ÿÿ´ÿÿ¦ÿÿ™ÿÿŒÿÿ~ÿÿpÿÿbÿÿTÿÿFÿÿ7ÿÿ)ÿÿÿÿ ÿþÿ÷ÿƒÚ²ÿ|èÄÿtíÑÿmêÖÿgã×ÿeÞÕÿiÞÑÿpâÍÿwçÈÿ~íÆÿ…óÂÿ�@2ÿ•ÿ›ÿ¢ÿ©ÿ°ÿ·ÿ¾ÿÆÿÍÿÕÿÜÿãÿëÿòÿùÿþÿÿ ÿÿÿÿ"ÿÿ-ÿÿ9ÿÿDÿÿPÿÿ[ÿÿgÿÿrÿÿ}ÿÿˆÿÿ“ÿÿ ÿÿ«ÿÿµÿÿ·ÿÿ¯ÿÿ£ÿÿ˜ÿÿŒÿÿ€ÿÿuÿÿiÿÿ]ÿÿQÿÿEÿÿ8ÿÿ,ÿÿÿÿÿÿÿüÿõÿíÿäÿÜÿÓÿËÿÂÿ¹ÿ±ÿ©ÿ ÿ˜cHÿ�½�ÿ†êºÿ}ôÌÿtéÍÿkàÐÿcÚÔÿcÛÔÿlàÐÿtåÊÿ}êÄÿ†ï¾ÿ�ó·ÿ˜ÿµÿ¡´yÿ¨ÿ°ÿ¹ÿÂÿËÿÔÿÝÿæÿîÿøÿþÿÿ ÿÿÿÿ'ÿÿ4ÿÿBÿÿPÿÿ]ÿÿkÿÿxÿÿ…ÿÿ“ÿÿ ÿÿ®ÿÿ¹ÿÿ´ÿÿ¦ÿÿ™ÿÿŒÿÿ~ÿÿpÿÿbÿÿTÿÿFÿÿ7ÿÿ)ÿÿÿÿ ÿþÿ÷ÿìÿnåÐÿgÞÒÿcÛÔÿdÛÔÿiÞÑÿpãÍÿxèÈÿëÃÿ†ï¾ÿ�ú¾ÿ•³„ÿ›ÿ¢ÿ©ÿ°ÿ·ÿ¾ÿÆÿÍÿÔÿÛÿãÿêÿòÿùÿþÿÿ ÿÿÿÿ ÿÿ,ÿÿ7ÿÿCÿÿNÿÿYÿÿeÿÿpÿÿ{ÿÿ‡ÿÿ’ÿÿ�ÿÿ©ÿÿ´ÿÿ¸ÿÿ²ÿÿ¦ÿÿ›ÿÿ�ÿÿ„ÿÿxÿÿlÿÿ`ÿÿTÿÿHÿÿ<ÿÿ/ÿÿ#ÿÿÿÿ ÿþÿøÿïÿçÿÞÿÖÿÎÿÅÿ¼ÿ´ÿ¬ ÿ¤M5ÿ›Ÿpÿ“æªÿŠùÁÿ�óÇÿxèÉÿoâÎÿfÜÓÿ_ØÖÿdÛÔÿlàÏÿuæÊÿ~ëÄÿ‡ï¾ÿ�ô·ÿ™ø¯ÿ¢ÿ¬ÿªÉ~ÿ²ÿºÿÃÿÌÿÕÿÝÿæÿïÿùÿþÿÿ ÿÿÿÿ(ÿÿ5ÿÿCÿÿPÿÿ^ÿÿlÿÿyÿÿ†ÿÿ“ÿÿ¡ÿÿ®ÿÿ¹ÿÿ´ÿÿ¦ÿÿ™ÿÿ‹ÿÿ~ÿÿpÿÿbÿÿTÿÿEÿÿ7ÿÿ)ÿÿÿÿ ÿþÿ÷ÿí ÿå|/ÿ`ØÖÿcÛÔÿjßÐÿqäÌÿxèÈÿìÃÿ†ï¾ÿŽó¸ÿ•÷³ÿ�û®ÿ£B-ÿ©ÿ±ÿ·ÿ¿ÿÆÿÍÿÔÿÛÿãÿêÿòÿùÿþÿÿ ÿÿÿÿÿÿ+ÿÿ6ÿÿAÿÿMÿÿXÿÿdÿÿoÿÿzÿÿ…ÿÿ�ÿÿ›ÿÿ§ÿÿ²ÿÿ¸ÿÿ³ÿÿ¨ÿÿ�ÿÿ’ÿÿ†ÿÿzÿÿoÿÿcÿÿVÿÿKÿÿ?ÿÿ2ÿÿ&ÿÿÿÿ ÿÿÿúÿòÿéÿáÿÙÿÐÿÈÿ¿ÿ·ÿ¯;%ÿ§‰ZÿŸÓ‘ÿ–ü¶ÿ�ü¿ÿ„ñÁÿ{éÆÿräÌÿiÞÑÿ`ÙÖÿ^××ÿeÜÓÿnâÎÿvæÉÿëÃÿˆð½ÿ‘ô¶ÿšø¯ÿ£û§ÿ¬ÿ ÿµìŠÿ» ÿÄÿÍÿÕÿÞÿçÿðÿúÿÿÿÿ ÿÿÿÿ)ÿÿ6ÿÿDÿÿRÿÿ_ÿÿmÿÿzÿÿ‡ÿÿ•ÿÿ¢ÿÿ¯ÿÿ¹ÿÿ³ÿÿ¥ÿÿ˜ÿÿŠÿÿ}ÿÿoÿÿaÿÿSÿÿEÿÿ7ÿÿ(ÿÿÿÿ ÿþÿöÿîZÿçÑNÿÝÿmÿkßÐÿräÌÿyéÇÿ€ìÂÿˆð½ÿ�ó¸ÿ–ö²ÿ�ù«ÿ¥ÿªÿ«ºuÿ±ÿ¸ÿ¿ÿÆÿÍÿÕÿÜÿãÿêÿòÿùÿþÿÿ ÿÿÿÿÿÿ+ÿÿ6ÿÿAÿÿLÿÿWÿÿcÿÿnÿÿyÿÿ„ÿÿ�ÿÿšÿÿ¦ÿÿ±ÿÿ·ÿÿµÿÿªÿÿŸÿÿ“ÿÿˆÿÿ}ÿÿqÿÿeÿÿYÿÿMÿÿAÿÿ5ÿÿ)ÿÿÿÿÿÿÿüÿôÿìÿãÿÛÿÒÿÊÿÂÿº+ÿ²tHÿªÃ}ÿ¢û¨ÿ™ÿ¶ÿ�ùºÿ‡ï¾ÿ~ëÄÿuæÊÿlàÏÿcÛÔÿ\ÖØÿ^××ÿfÝÓÿoâÎÿwçÈÿ€ìÂÿ‰ñ¼ÿ’õµÿ›ù®ÿ¤ü¥ÿ®þ�ÿ·ÿ•ÿÀë€ÿÅ ÿÎÿ×ÿàÿéÿòÿûÿÿÿÿÿÿÿÿ+ÿÿ8ÿÿFÿÿSÿÿaÿÿnÿÿ{ÿÿ‰ÿÿ–ÿÿ£ÿÿ±ÿÿ¹ÿÿ²ÿÿ¤ÿÿ—ÿÿŠÿÿ|ÿÿnÿÿ`ÿÿRÿÿDÿÿ6ÿÿ'ÿÿÿÿÿþÿ÷Dÿï¹=ÿçÿ^ÿÝÿlÿÒÿvÿ{éÆÿ‚íÁÿ‰ñ½ÿ�ô·ÿ—÷±ÿŸú«ÿ¦ü¤ÿ­þžÿµû–ÿºB&ÿÀÿÇÿÎÿÕÿÝÿäÿëÿòÿúÿþÿÿ ÿÿÿÿ ÿÿ+ÿÿ6ÿÿAÿÿLÿÿWÿÿcÿÿnÿÿyÿÿ„ÿÿ�ÿÿšÿÿ¥ÿÿ°ÿÿ·ÿÿµÿÿ¬ÿÿ ÿÿ•ÿÿ‰ÿÿ~ÿÿrÿÿgÿÿ[ÿÿOÿÿCÿÿ7ÿÿ+ÿÿÿÿÿÿÿýÿöÿîÿåÿÝÿÔÿÌÿÄÿ¼a7ÿµ¹oÿ­÷šÿ¤ÿ¬ÿ›ÿ²ÿ’õ¶ÿ‰ñ¼ÿ€ìÃÿwçÈÿoâÎÿfÜÓÿ]Ö×ÿYÔÚÿ_ØÖÿhÞÒÿqãÍÿyèÇÿ‚íÁÿ‹ò»ÿ”ö´ÿ�ú¬ÿ¦ý¤ÿ¯ÿœÿ¸ÿ’ÿÂÿŠÿÊëuÿÐ ÿØÿáÿêÿóÿüÿÿÿÿÿÿÿÿ-ÿÿ:ÿÿHÿÿUÿÿcÿÿpÿÿ}ÿÿ‹ÿÿ˜ÿÿ¥ÿÿ²ÿÿ¹ÿÿ°ÿÿ£ÿÿ–ÿÿˆÿÿzÿÿmÿÿ_ÿÿQÿÿBÿÿ4ÿÿ&ÿÿÿÿÿþ. ÿø�,ÿðûQÿæÿaÿÜÿkÿÒÿwÿÇÿƒÿ‹ñ»ÿ’õ¶ÿ™ø°ÿ û©ÿ§ý£ÿ¯þœÿ¶ÿ”ÿ¾ÿ’ÿÓNÿÈÿÏÿ×ÿÞÿåÿìÿôÿúÿþÿÿ ÿÿÿÿ ÿÿ,ÿÿ6ÿÿBÿÿMÿÿXÿÿcÿÿnÿÿyÿÿ„ÿÿ�ÿÿšÿÿ¥ÿÿ°ÿÿ·ÿÿ¶ÿÿ¬ÿÿ¡ÿÿ–ÿÿŠÿÿÿÿtÿÿhÿÿ\ÿÿPÿÿDÿÿ8ÿÿ,ÿÿ ÿÿÿÿÿýÿ÷ÿïÿçÿÞÿÖÿÎÿÇa3ÿ¿±bÿ¸îŠÿ¯ÿ ÿ¦ÿ¨ÿ�û­ÿ”õ³ÿ‹ò»ÿ‚íÁÿzèÇÿqäÍÿhÞÒÿ_ØÖÿXÓÚÿYÔÙÿaÚÖÿjßÑÿsäËÿ{êÆÿ„îÀÿ�ó¹ÿ–÷²ÿŸúªÿ¨ý£ÿ±ÿšÿºÿ‘ÿÃÿ‡ÿÍÿ~ÿÕëjÿÚÿãÿìÿõÿýÿÿÿÿÿÿ!ÿÿ/ÿÿ=ÿÿJÿÿXÿÿeÿÿrÿÿ€ÿÿ�ÿÿšÿÿ§ÿÿ´ÿÿ¹ÿÿ®ÿÿ¡ÿÿ”ÿÿ†ÿÿyÿÿkÿÿ]ÿÿOÿÿAÿÿ2ÿÿ!ÿÿ ÿÿ"ÿÿ�%ÿùôDÿïÿUÿåÿ`ÿÛÿlÿÑÿyÿÇÿ„ÿ¼ÿ�ÿ›ù®ÿ¢û¨ÿ©þ¡ÿ±ÿšÿ¸ÿ“ÿ¿ÿ‹ÿÇÿ†ÿÍ×iÿÑÿØÿßÿæÿîÿõÿûÿÿÿÿ ÿÿÿÿ"ÿÿ-ÿÿ8ÿÿCÿÿNÿÿYÿÿdÿÿoÿÿzÿÿ…ÿÿ�ÿÿšÿÿ¥ÿÿ°ÿÿ·ÿÿ¶ÿÿ¬ÿÿ¡ÿÿ–ÿÿŠÿÿÿÿtÿÿiÿÿ]ÿÿQÿÿEÿÿ9ÿÿ-ÿÿ!ÿÿÿÿ ÿþÿøÿðÿèÿßÿØ ÿÑa/ÿʱ[ÿÂî€ÿ¹ÿ–ÿ°ÿžÿ§ÿ¤ÿŸú«ÿ–ö²ÿ�óºÿ„îÀÿ{êÆÿsåËÿjßÑÿaÚÕÿYÓÚÿUÑÜÿ[ÕÙÿdÛÔÿláÏÿuæÊÿ}ëÅÿ†ð¾ÿ�ô¸ÿ˜ø°ÿ¡û©ÿªþ¡ÿ³ÿ˜ÿ¼ÿ�ÿÆÿ…ÿÏÿzÿØÿqÿàë]ÿåÿîÿ÷ÿþÿÿ ÿÿÿÿ$ÿÿ2ÿÿ?ÿÿMÿÿZÿÿhÿÿuÿÿ‚ÿÿ�ÿÿœÿÿ©ÿÿ¶ÿÿ¸ÿÿ¬ÿÿŸÿÿ’ÿÿ„ÿÿwÿÿiÿÿ[ÿÿMÿÿ?ÿÿ-ÿÿÿÿ)ÿÿ‚ÿþæ6ÿøÿJÿîÿUÿäÿaÿÚÿnÿÐÿzÿÆÿ†ÿ»ÿ‘ÿ±ÿ›ÿ¬þŸÿ³ÿ˜ÿºÿ‘ÿÂÿ‰ÿÉÿ�ÿÐÿyÿ×úpÿÛGÿáÿèÿïÿöÿüÿÿÿÿ ÿÿÿÿ$ÿÿ/ÿÿ:ÿÿEÿÿPÿÿZÿÿeÿÿpÿÿ{ÿÿ†ÿÿ�ÿÿ›ÿÿ¦ÿÿ±ÿÿ¸ÿÿµÿÿ¬ÿÿ ÿÿ•ÿÿŠÿÿÿÿtÿÿiÿÿ]ÿÿRÿÿEÿÿ:ÿÿ.ÿÿ"ÿÿÿÿ ÿþÿùÿñÿéÿá ÿÚa+ÿÓ±SÿÌîvÿÃÿ‹ÿºÿ”ÿ²ÿšÿ©ý¢ÿ ûªÿ—÷±ÿŽó¸ÿ†ï¿ÿ}êÅÿtåËÿlàÐÿcÛÕÿZÔÙÿTÐÜÿUÑÛÿ]רÿfÝÓÿoâÎÿwçÉÿ€ìÃÿˆñ½ÿ’õ¶ÿšù¯ÿ£ü§ÿ¬þžÿµÿ–ÿ¿ÿŒÿÈÿ‚ÿÑÿxÿÚÿmÿãÿcÿììPÿñÿùÿÿÿÿ ÿÿÿÿ'ÿÿ5ÿÿBÿÿPÿÿ]ÿÿkÿÿxÿÿ…ÿÿ’ÿÿŸÿÿ¬ÿÿ¸ÿÿ¶ÿÿ©ÿÿœÿÿ�ÿÿ‚ÿÿtÿÿfÿÿXÿÿKÿÿ9ÿÿ$ÿÿ3ÿÿˆÿÿæ,ÿþÿ?ÿ÷ÿKÿìÿWÿâÿdÿØÿpÿÏÿ|ÿÄÿ‡ÿºÿ’ÿ¯ÿ�ÿ¥ý§ÿ½ÿŽÿÄÿ†ÿËÿ~ÿÓÿvÿÙÿnÿáÿhÿæ/ÿêÿòÿøÿýÿÿÿÿÿÿÿÿ&ÿÿ1ÿÿ<ÿÿGÿÿRÿÿ]ÿÿgÿÿrÿÿ}ÿÿ‡ÿÿ’ÿÿ�ÿÿ¨ÿÿ³ÿÿ¸ÿÿµÿÿ«ÿÿ ÿÿ•ÿÿŠÿÿÿÿsÿÿhÿÿ]ÿÿQÿÿFÿÿ9ÿÿ-ÿÿ"ÿÿÿÿ ÿþÿùÿñÿê+ÿãt.ÿܼPÿÕîlÿÌÿ€ÿÄÿŠÿ»ÿ‘ÿ³ÿ™ÿªþ¡ÿ¡û©ÿ˜÷°ÿ�ô¸ÿ‡ð¾ÿ~ëÅÿuæÊÿmáÏÿdÜÔÿ\ÖØÿSÐÜÿQÎÝÿXÓÚÿ`ÙÖÿißÒÿqäÍÿzéÇÿ‚îÁÿ‹ò»ÿ”ö´ÿ�ú¬ÿ¦ý¤ÿ¯ÿœÿ¸ÿ“ÿÁÿ‰ÿÊÿÿÓÿuÿÜÿjÿæÿ_ÿïÿUÿ÷Ë:ÿûÿÿÿÿÿÿÿÿ+ÿÿ9ÿÿFÿÿSÿÿaÿÿnÿÿ{ÿÿˆÿÿ•ÿÿ¢ÿÿ°ÿÿ¹ÿÿ´ÿÿ¦ÿÿ™ÿÿŒÿÿÿÿqÿÿdÿÿVÿÿDÿÿ0ÿÿ=ÿÿ�ÿÿæ#ÿÿÿ4ÿýÿ@ÿõÿLÿëÿYÿáÿfÿ×ÿrÿÍÿ~ÿÂÿ‰ÿ¸ÿ”ÿ®ÿŸÿ£ü¨ÿ˜ø±ÿÎÿ{ÿÕÿsÿÝÿjÿäÿaÿëÿ[ÿð©6ÿôÿûÿþÿÿ ÿÿÿÿÿÿ*ÿÿ4ÿÿ?ÿÿJÿÿUÿÿ_ÿÿjÿÿuÿÿÿÿŠÿÿ”ÿÿŸÿÿªÿÿ´ÿÿ¸ÿÿ³ÿÿ©ÿÿžÿÿ“ÿÿ‰ÿÿ~ÿÿrÿÿgÿÿ\ÿÿPÿÿDÿÿ9ÿÿ.ÿÿ!ÿÿÿÿÿþÿùÿò;ÿë-ÿåÄKÿÝøgÿÕÿwÿÍÿ€ÿÄÿ‡ÿ»ÿ�ÿ³ÿ˜ÿªþ¡ÿ¡û©ÿ™ø°ÿ�ô·ÿ‡ï¾ÿ~ìÄÿvçÊÿnâÏÿeÜÔÿ]ÖØÿSÐÜÿOÍÞÿSÏÝÿ[ÕÙÿcÛÔÿláÐÿtæËÿ|ëÅÿ…ï¿ÿŽô¹ÿ—÷²ÿ ûªÿ©þ¡ÿ²ÿ™ÿ»ÿ�ÿÄÿ†ÿÍÿ|ÿÖÿqÿßÿfÿèÿ[ÿòÿOÿúÿFÿÿ­(ÿÿÿÿÿÿ"ÿÿ/ÿÿ<ÿÿJÿÿWÿÿdÿÿrÿÿÿÿŒÿÿ™ÿÿ¦ÿÿ³ÿÿ¹ÿÿ±ÿÿ£ÿÿ–ÿÿ‰ÿÿ|ÿÿnÿÿ`ÿÿPÿÿ<ÿÿGÿÿ‘ ÿÿæÿÿÿ)ÿÿÿ5ÿüÿBÿóÿOÿéÿ\ÿßÿiÿÕÿuÿÊÿ€ÿÀÿŒÿµÿ–ÿ«ÿ¡ÿ¡üªÿ–÷³ÿŒó»ÿßÿfÿçÿ^ÿîÿTÿõÿMÿûÆ6ÿýÿÿÿÿ ÿÿÿÿ#ÿÿ-ÿÿ8ÿÿBÿÿMÿÿXÿÿbÿÿmÿÿxÿÿ‚ÿÿ�ÿÿ—ÿÿ¡ÿÿ­ÿÿµÿÿ¸ÿÿ²ÿÿ§ÿÿœÿÿ’ÿÿ‡ÿÿ|ÿÿqÿÿfÿÿZÿÿOÿÿDÿÿ8ÿÿ,ÿÿÿÿ ÿÿÿþÿúNÿôž1ÿíÔIÿåþ_ÿÝÿmÿÕÿvÿÍÿ~ÿÄÿ†ÿ»ÿ�ÿ³ÿ˜ÿªþ¡ÿ¢û©ÿ™ø°ÿ�õ·ÿˆð¾ÿìÄÿvçÉÿnâÏÿfÝÔÿ]רÿTÑÜÿNÌßÿNÌÞÿVÒÛÿ^Ø×ÿfÝÓÿoãÎÿwçÉÿ€ìÃÿ‰ñ½ÿ’õ¶ÿ›ù¯ÿ¤ü§ÿ­þŸÿ¶ÿ–ÿ¿ÿŒÿÈÿƒÿÑÿxÿÚÿnÿãÿcÿëÿWÿõÿKÿýÿ@ÿÿÿ6ÿÿ€ÿÿÿÿ&ÿÿ3ÿÿAÿÿNÿÿ[ÿÿiÿÿvÿÿƒÿÿ�ÿÿ�ÿÿªÿÿ¶ÿÿ¸ÿÿ­ÿÿ ÿÿ“ÿÿ…ÿÿxÿÿjÿÿZÿÿGÿÿPÿÿ•ÿÿäÿÿÿÿÿÿ+ÿÿÿ9ÿùÿEÿðÿRÿæÿ_ÿÜÿlÿÒÿxÿÈÿƒÿ¾ÿŽÿ³ÿ™ÿ©þ£ÿŸû¬ÿ”÷µÿ‰ñ½ÿìÄÿñÿQÿøÿGÿýÿ?ÿÿÙ.ÿÿÿÿ ÿÿÿÿ'ÿÿ2ÿÿ<ÿÿGÿÿQÿÿ\ÿÿfÿÿqÿÿ{ÿÿ†ÿÿ�ÿÿšÿÿ¥ÿÿ°ÿÿ·ÿÿ·ÿÿ¯ÿÿ¥ÿÿšÿÿ�ÿÿ„ÿÿzÿÿoÿÿdÿÿXÿÿMÿÿAÿÿ3ÿÿ#ÿÿÿÿÿÿ2 ÿÿaÿû°0ÿõéFÿíÿWÿåÿcÿÝÿlÿÔÿuÿÌÿ}ÿÃÿ‡ÿ»ÿ�ÿ²ÿ™ÿªþ¡ÿ¡û©ÿ™ø±ÿ�ô·ÿˆð¾ÿìÄÿvçÊÿnâÏÿeÝÔÿ]רÿUÑÜÿMËßÿKÊàÿQÎÝÿYÔÚÿaÚÕÿjàÑÿråÌÿ{éÇÿ„ïÁÿ�óºÿ•÷³ÿžú¬ÿ§ý¤ÿ°ÿœÿ¹ÿ’ÿÃÿ‰ÿÌÿÿÕÿtÿÞÿjÿæÿ^ÿðÿSÿøÿHÿþÿ;ÿÿþ/ÿÿý$ÿÿYÿÿ$ÿÿ8ÿÿEÿÿSÿÿ`ÿÿmÿÿzÿÿ‡ÿÿ”ÿÿ¡ÿÿ®ÿÿ¹ÿÿ¶ÿÿ©ÿÿœÿÿ�ÿÿ�ÿÿtÿÿcÿÿRÿÿYÿÿ˜ÿÿâÿÿÿÿÿþ"ÿÿþ/ÿþÿ<ÿøÿIÿîÿVÿäÿbÿÚÿoÿÐÿ{ÿÆÿ†ÿ»ÿ‘ÿ±ÿ›ÿ¦þ¦ÿœú®ÿ’õ·ÿ‡ð¿ÿ}ëÆÿråÍÿþÿ9ÿÿÿ0ÿÿè$ÿÿIÿÿÿÿ,ÿÿ6ÿÿAÿÿKÿÿVÿÿ`ÿÿkÿÿuÿÿÿÿŠÿÿ”ÿÿžÿÿ©ÿÿ³ÿÿ¸ÿÿµÿÿ¬ÿÿ¡ÿÿ—ÿÿŒÿÿ‚ÿÿwÿÿlÿÿaÿÿVÿÿIÿÿ:ÿÿ*ÿÿ#ÿÿ0ÿÿP ÿÿŽÿÿÉ.ÿû÷AÿôÿOÿìÿYÿäÿbÿÜÿlÿÓÿuÿËÿÿÃÿˆÿºÿ‘ÿ²ÿšÿ©þ¢ÿ¡ûªÿ˜ø±ÿ�ô¸ÿ‡ð¾ÿìÅÿvçÊÿnâÏÿeÝÔÿ]רÿUÑÜÿMËßÿIÈáÿMËßÿUÑÜÿ]רÿeÝÔÿnâÏÿvçÊÿìÄÿˆñ¾ÿ�õ¸ÿ™ø°ÿ¢ü¨ÿ«þ ÿ´ÿ—ÿ½ÿŽÿÆÿ…ÿÏÿ{ÿØÿpÿáÿeÿêÿZÿóÿNÿûÿCÿÿÿ7ÿÿý+ÿÿüÿÿæÿÿAÿÿ;ÿÿJÿÿXÿÿeÿÿrÿÿÿÿŒÿÿ™ÿÿ¦ÿÿ³ÿÿ¹ÿÿ²ÿÿ¤ÿÿ—ÿÿŠÿÿ}ÿÿlÿÿ\ÿÿoÿÿ¬ÿÿàÿÿû ÿÿûÿÿü&ÿÿÿ3ÿýÿ@ÿõÿMÿëÿYÿáÿfÿ×ÿsÿÍÿ~ÿÃÿ‰ÿ¸ÿ”ÿ®ÿžÿ£ý¨ÿ™ù±ÿ�ô¹ÿ„ïÁÿzêÈÿpãÎÿfÝÔÿÿÿ"ÿÿçÿÿVÿÿ(ÿÿ<ÿÿFÿÿQÿÿ[ÿÿeÿÿoÿÿzÿÿ„ÿÿŽÿÿ˜ÿÿ£ÿÿ­ÿÿµÿÿ¸ÿÿ²ÿÿ¨ÿÿžÿÿ“ÿÿ‰ÿÿ~ÿÿtÿÿiÿÿ]ÿÿOÿÿ?ÿÿ4ÿÿ5ÿÿJÿÿ~ÿÿ·ÿÿê-ÿþÿ:ÿùÿFÿóÿPÿêÿZÿâÿdÿÚÿmÿÒÿwÿÊÿ�ÿÂÿŠÿ¹ÿ’ÿ±ÿ›ÿ¨ý£ÿ û«ÿ—ø²ÿ�ô¹ÿ†ð¿ÿ~ëÅÿuçÊÿmáÐÿeÜÔÿ\רÿTÑÜÿLÊàÿGÆáÿIÈáÿQÎÝÿYÔÚÿaÚÖÿjßÑÿråÍÿzéÇÿƒîÁÿŒó»ÿ•÷´ÿ�ú­ÿ§ý¥ÿ°ÿ�ÿ¹ÿ“ÿÂÿŠÿËÿ€ÿÔÿvÿÜÿkÿåÿ`ÿîÿUÿ÷ÿIÿþÿ>ÿÿÿ2ÿÿü&ÿÿùÿÿúÿÿºÿÿ>ÿÿPÿÿ]ÿÿjÿÿwÿÿ„ÿÿ‘ÿÿžÿÿ«ÿÿ·ÿÿ¸ÿÿ­ÿÿŸÿÿ“ÿÿ…ÿÿtÿÿiÿÿwÿÿ°ÿÿçÿÿøÿÿøÿÿúÿÿþ*ÿÿÿ7ÿûÿDÿòÿQÿèÿ^ÿÞÿjÿÔÿvÿÊÿ‚ÿ¿ÿ�ÿµÿ˜ÿ«ÿ¡ÿ ü«ÿ–ø³ÿŒó¼ÿ�îÃÿwèÊÿmâÐÿcÛÕÿYÔÚÿÿå ÿÿaÿÿ9ÿÿMÿÿVÿÿaÿÿkÿÿuÿÿÿÿ‰ÿÿ“ÿÿ�ÿÿ¨ÿÿ²ÿÿ·ÿÿ¶ÿÿ¯ÿÿ¤ÿÿ™ÿÿ�ÿÿ…ÿÿzÿÿoÿÿbÿÿSÿÿGÿÿCÿÿOÿÿzÿÿªÿÿÖÿÿö'ÿÿÿ4ÿýÿ>ÿøÿHÿñÿRÿéÿ\ÿáÿfÿÙÿpÿÑÿyÿÈÿ‚ÿÀÿŒÿ¸ÿ”ÿ¯ÿ�ÿ§ý¥ÿžú¬ÿ–÷³ÿ�óºÿ…ïÀÿ}ëÆÿtæËÿláÐÿdÜÕÿ\ÖÙÿSÐÜÿKÊàÿEÅâÿFÆâÿMËßÿUÑÜÿ]רÿfÝÔÿnâÏÿvçÊÿìÅÿ‡ñ¾ÿ�õ¸ÿ™ù±ÿ¢ü©ÿ«þ¡ÿ´ÿ˜ÿ½ÿ�ÿÆÿ…ÿÏÿ{ÿØÿqÿáÿfÿêÿ[ÿòÿOÿúÿDÿÿÿ8ÿÿþ,ÿÿû ÿÿ÷ÿÿóÿÿôÿÿ‡ÿÿOÿÿcÿÿpÿÿ}ÿÿŠÿÿ–ÿÿ£ÿÿ±ÿÿ¹ÿÿ´ÿÿ§ÿÿšÿÿŒÿÿ|ÿÿqÿÿˆÿÿÁÿÿæÿÿôÿÿôÿÿ÷ÿÿü"ÿÿþ/ÿþÿ<ÿøÿIÿîÿUÿåÿbÿÛÿoÿÐÿzÿÇÿ…ÿ¼ÿ�ÿ²ÿ›ÿ§þ¥ÿ�û®ÿ“ö¶ÿˆñ¾ÿ~ìÅÿtæÌÿjàÒÿ_Ù×ÿVÒÜÿLËàÿÿkÿÿKÿÿ]ÿÿgÿÿqÿÿ{ÿÿ…ÿÿ�ÿÿ™ÿÿ£ÿÿ­ÿÿµÿÿ¸ÿÿ³ÿÿªÿÿŸÿÿ•ÿÿ‹ÿÿ€ÿÿsÿÿeÿÿYÿÿUÿÿ_ÿÿzÿÿ¢ÿÿÌ ÿÿíÿÿÿ!ÿÿÿ,ÿÿÿ6ÿüÿ@ÿöÿKÿîÿUÿçÿ_ÿßÿiÿÖÿrÿÎÿ|ÿÆÿ…ÿ¾ÿŽÿ¶ÿ–ÿ­þŸÿ¥ý¦ÿœú®ÿ”öµÿŒó»ÿƒîÁÿ{êÇÿsåÌÿjàÑÿcÛÖÿZÕÙÿRÏÝÿJÉàÿCÄãÿCÄâÿIÉáÿRÏÝÿZÕÚÿbÚÖÿjàÑÿsåÌÿ{êÇÿ„ïÁÿŒó»ÿ•÷´ÿžú­ÿ§ý¥ÿ°ÿœÿ¹ÿ”ÿÂÿŠÿËÿ€ÿÔÿvÿÝÿkÿåÿ`ÿîÿUÿ÷ÿJÿýÿ>ÿÿÿ2ÿÿý'ÿÿùÿÿõÿÿñÿÿíÿÿßÿÿkÿÿgÿÿvÿÿƒÿÿ�ÿÿœÿÿ©ÿÿ¶ÿÿ¹ÿÿ¯ÿÿ¢ÿÿ“ÿÿ„ÿÿ€ÿÿ›ÿÿÇÿÿçÿÿïÿÿñÿÿõ ÿÿúÿÿý'ÿÿÿ4ÿýÿAÿõÿNÿëÿZÿáÿgÿ×ÿsÿÍÿ~ÿÃÿŠÿ¸ÿ”ÿ®ÿžÿ¤ý¨ÿ™ù±ÿ�ô¹ÿ…ïÁÿ{êÈÿpäÎÿfÞÔÿ]×ÙÿSÐÝÿIÉáÿ?Áäÿÿ_ÿÿmÿÿxÿÿ�ÿÿ‹ÿÿ•ÿÿŸÿÿ©ÿÿ³ÿÿ¸ÿÿ¶ÿÿ¯ÿÿ¤ÿÿšÿÿ�ÿÿƒÿÿvÿÿjÿÿeÿÿmÿÿ„ÿÿ¦ÿÿËÿÿèÿÿúÿÿÿÿÿÿ&ÿÿÿ0ÿþÿ:ÿúÿDÿóÿNÿìÿYÿäÿbÿÜÿlÿÔÿuÿÌÿÿÄÿˆÿ»ÿ‘ÿ³ÿ™ÿ«þ¡ÿ£ü©ÿšù°ÿ’ö·ÿŠò½ÿ�íÃÿyéÉÿqäÍÿißÒÿ`Ú×ÿYÔÚÿQÎÞÿHÈáÿAÃãÿAÂãÿFÆâÿOÍÞÿWÓÛÿ_Ø×ÿgÞÓÿoãÎÿxèÉÿ€íÄÿ‰ñ¾ÿ‘õ·ÿšù°ÿ£ü¨ÿ¬ÿ ÿµÿ˜ÿ¾ÿŽÿÇÿ…ÿÐÿ{ÿØÿpÿáÿfÿêÿZÿóÿOÿûÿCÿÿÿ8ÿÿþ,ÿÿû ÿÿ÷ÿÿóÿÿîÿÿêÿÿéÿÿ³ÿÿkÿÿ|ÿÿ‰ÿÿ–ÿÿ¢ÿÿ¯ÿÿ¹ÿÿ¶ÿÿ©ÿÿ™ÿÿŒÿÿ‹ÿÿªÿÿÓÿÿæÿÿìÿÿîÿÿòÿÿ÷ÿÿû ÿÿþ,ÿÿÿ9ÿúÿFÿñÿSÿçÿ`ÿÝÿlÿÓÿxÿÉÿƒÿ¿ÿŽÿ´ÿ˜ÿªÿ¢ÿ ü«ÿ•ø´ÿ‹ó¼ÿ�íÃÿwèÊÿmâÐÿcÛÖÿYÔÚÿOÍßÿFÆâÿ<¾åÿ3·çûÿ~ÿÿˆÿÿ’ÿÿœÿÿ¦ÿÿ°ÿÿ·ÿÿ¸ÿÿ²ÿÿ©ÿÿžÿÿ‘ÿÿ…ÿÿzÿÿuÿÿzÿÿ�ÿÿªÿÿËÿÿäÿÿôÿÿú ÿÿüÿÿü ÿÿý*ÿÿÿ4ÿýÿ>ÿøÿIÿñÿSÿéÿ\ÿáÿfÿÙÿpÿÑÿyÿÉÿ‚ÿÁÿ‹ÿ¹ÿ”ÿ±ÿ›ÿ¨þ¤ÿ û«ÿ˜ø²ÿ�õ¹ÿ‡ð¿ÿìÄÿwèÊÿoãÏÿgÞÓÿ_ØØÿVÒÛÿOÍÞÿFÆâÿ@Áäÿ>ÀäÿDÄãÿLËßÿTÑÜÿ\ÖÙÿdÜÕÿláÐÿtæËÿ}ëÆÿ…ðÀÿŽôºÿ—ø³ÿ û¬ÿ¨þ£ÿ±ÿ›ÿºÿ’ÿÃÿ‰ÿÌÿÿÕÿuÿÞÿjÿæÿ_ÿïÿTÿøÿHÿþÿ=ÿÿÿ1ÿÿý&ÿÿùÿÿõ ÿÿñÿÿìÿÿçÿÿâÿÿÝÿÿ�ÿÿ€ÿÿ�ÿÿœÿÿ©ÿÿ¶ÿÿ¹ÿÿ¯ÿÿ ÿÿ•ÿÿ›ÿÿ·ÿÿÖÿÿäÿÿèÿÿëÿÿðÿÿõ ÿÿùÿÿý&ÿÿÿ2ÿýÿ?ÿöÿLÿìÿXÿâÿeÿÙÿqÿÎÿ}ÿÄÿˆÿºÿ“ÿ°ÿ�ÿ¦þ¦ÿœú¯ÿ‘ö¸ÿ‡ñ¿ÿ}ëÇÿsæÍÿißÓÿ_ØØÿUÒÜÿKËàÿBÃäÿ8»çÿ0´èÿ1µèîÿ™ÿÿ£ÿÿ­ÿÿµÿÿ¸ÿÿ´ÿÿ«ÿÿŸÿÿ“ÿÿŠÿÿ…ÿÿ‹ÿÿœÿÿ®ÿÿÊÿÿàÿÿîÿÿõÿÿöÿÿ÷ÿÿùÿÿü%ÿÿþ/ÿþÿ9ÿûÿCÿõÿMÿíÿWÿåÿaÿÝÿjÿÖÿtÿÎÿ}ÿÆÿ†ÿ¾ÿŽÿ¶ÿ—ÿ®ÿŸÿ¥ý§ÿ�ú®ÿ•÷´ÿŒó»ÿ„ïÁÿ|ëÇÿtæÌÿláÑÿdÜÕÿ\ÖÙÿTÑÜÿLËßÿDÅâÿ=¿äÿ<¾åÿAÂãÿIÈáÿQÏÝÿYÔÚÿaÚÖÿißÒÿråÍÿzéÈÿ‚îÂÿ‹ó¼ÿ”ö¶ÿœú®ÿ¥ý¦ÿ®ÿžÿ·ÿ•ÿÀÿŒÿÉÿƒÿÒÿyÿÛÿnÿãÿcÿìÿXÿõÿMÿüÿAÿÿÿ6ÿÿþ*ÿÿûÿÿ÷ÿÿóÿÿîÿÿéÿÿåÿÿßÿÿÝÿÿÀÿÿ‰ÿÿ–ÿÿ¤ÿÿ°ÿÿ¹ÿÿ´ÿÿ¦ÿÿŸÿÿ©ÿÿÁÿÿÙÿÿáÿÿäÿÿéÿÿîÿÿòÿÿ÷ÿÿûÿÿþ,ÿÿÿ8ÿúÿEÿòÿRÿèÿ^ÿÞÿkÿÔÿvÿÊÿ‚ÿÀÿ�ÿ¶ÿ—ÿ«ÿ¡ÿ¡üªÿ—ø³ÿ�ô»ÿ‚îÃÿxéÉÿnãÐÿdÜÕÿ[ÖÚÿQÏÞÿGÈâÿ>Àåÿ4¸èÿ-²éÿ1µèÿ:½æèÿ´úÿ¸ÿÿ´ÿÿ¬ÿÿ¡ÿÿ˜ÿÿ•ÿÿ™ÿÿ¨ÿÿ¼ÿÿÍÿÿßÿÿéÿÿîÿÿñÿÿóÿÿõ ÿÿøÿÿû!ÿÿþ+ÿÿÿ5ÿýÿ?ÿøÿIÿñÿSÿéÿ\ÿáÿfÿÚÿoÿÒÿxÿÊÿ�ÿÂÿŠÿºÿ“ÿ²ÿ›ÿªþ¢ÿ¢üªÿšù±ÿ’õ·ÿ‰ò¾ÿ�íÃÿyéÉÿqäÎÿißÒÿaÚ×ÿYÔÚÿRÏÝÿJÉáÿBÃãÿ;½åÿ:¼æÿ?ÁäÿGÇâÿOÍÞÿWÓÛÿ_ØØÿgÞÓÿoãÏÿxèÊÿ€íÄÿˆñ¾ÿ‘õ¸ÿšù±ÿ¢ü©ÿ«ÿ¡ÿ´ÿ™ÿ½ÿ�ÿÆÿ†ÿÏÿ|ÿØÿrÿáÿgÿéÿ\ÿòÿQÿúÿFÿÿÿ:ÿÿþ/ÿÿü#ÿÿøÿÿõ ÿÿðÿÿëÿÿçÿÿâÿÿÝÿÿ×ÿÿÓÿÿ£ÿÿ›ÿÿ«ÿÿ¶ÿÿ·ÿÿ­ÿÿªÿÿ¶ÿÿÊÿÿØÿÿÞÿÿáÿÿæÿÿëÿÿðÿÿõ ÿÿúÿÿý%ÿÿÿ2ÿþÿ?ÿ÷ÿKÿíÿXÿãÿeÿÚÿpÿÏÿ|ÿÅÿ‡ÿ»ÿ’ÿ±ÿœÿ§þ¦ÿœû¯ÿ’ö·ÿˆñ¿ÿ~ìÆÿtæÍÿjàÒÿ`Ù×ÿVÓÜÿLÌàÿCÄãÿ:½æÿ0µéÿ,±éÿ1¶èÿ:½æÿCÄããÿ®éÿ§ÿÿ§ÿÿªÿÿ³ÿÿÂÿÿÑÿÿÜÿÿäÿÿèÿÿëÿÿíÿÿðÿÿô ÿÿ÷ÿÿúÿÿý'ÿÿÿ1ÿþÿ;ÿúÿEÿôÿOÿíÿXÿåÿbÿÝÿkÿÖÿtÿÎÿ}ÿÆÿ†ÿ¾ÿ�ÿ¶ÿ—ÿ®ÿŸÿ¦ý¦ÿžû®ÿ–÷´ÿŽôºÿ†ðÀÿ}ëÆÿuçËÿnâÐÿfÝÔÿ^ØØÿVÒÛÿNÍßÿGÇâÿ?Àäÿ9¼æÿ8»æÿ=¿åÿEÆâÿMÌßÿUÒÜÿ]רÿeÝÕÿmâÐÿuçËÿ~ëÆÿ†ðÀÿ�õºÿ—ù³ÿ ü«ÿ©þ£ÿ²ÿ›ÿºÿ’ÿÃÿ‰ÿÌÿÿÕÿuÿÞÿkÿæÿ`ÿïÿUÿøÿIÿþÿ>ÿÿÿ2ÿÿý'ÿÿúÿÿöÿÿòÿÿíÿÿèÿÿäÿÿÞÿÿÙÿÿÕÿÿÑÿÿ¼ÿÿ¤ÿÿ²ÿÿ¸ÿÿ´ÿÿ³ÿÿ¿ÿÿÍÿÿÖÿÿÚÿÿßÿÿäÿÿéÿÿîÿÿóÿÿøÿÿüÿÿþ-ÿÿÿ9ÿúÿEÿòÿRÿèÿ_ÿÞÿkÿÔÿvÿÊÿ‚ÿÀÿ�ÿ¶ÿ—ÿ¬ÿ¡ÿ¢ýªÿ—ù³ÿ�ô»ÿƒïÂÿyéÉÿoãÏÿeÝÕÿ[ÖÚÿRÏÞÿHÈâÿ?Áåÿ5¹çÿ,±éÿ+°êÿ2¶èÿ;¾æÿDÅãÿMÌàÓÿ¾ÕÿÇÿÿÒÿÿÙÿÿßÿÿãÿÿåÿÿèÿÿìÿÿðÿÿóÿÿ÷ÿÿúÿÿý$ÿÿþ.ÿÿÿ8ÿüÿAÿ÷ÿKÿðÿUÿèÿ^ÿàÿhÿÙÿqÿÑÿzÿÉÿƒÿÁÿ‹ÿ¹ÿ“ÿ±ÿœÿ©þ£ÿ¡üªÿšù±ÿ’ö·ÿŠò¾ÿ‚íÃÿzéÈÿqåÎÿjàÒÿbÚÖÿZÕÚÿSÐÝÿKÊàÿCÄãÿ;¾åÿ6¹çÿ6ºçÿ<¾åÿDÅãÿLËàÿSÐÝÿ[ÖÙÿcÛÖÿkáÑÿsæÌÿ|ëÇÿ„ïÁÿ�ô»ÿ•øµÿžû­ÿ§þ¦ÿ°ÿ�ÿ¸ÿ•ÿÁÿŒÿÊÿ‚ÿÓÿxÿÛÿnÿäÿcÿíÿXÿöÿMÿüÿBÿÿÿ6ÿÿþ*ÿÿûÿÿ÷ÿÿóÿÿïÿÿêÿÿåÿÿàÿÿÛÿÿÖÿÿÑÿÿÍÿÿÇÿÿ²ÿÿ·ÿÿºÿÿ¼ÿÿÄÿÿÎÿÿÔÿÿØÿÿÝÿÿâÿÿçÿÿìÿÿñÿÿö ÿÿúÿÿþ&ÿÿÿ3ÿýÿ@ÿöÿLÿìÿYÿãÿeÿÙÿqÿÏÿ}ÿÅÿˆÿ»ÿ’ÿ±ÿ�ÿ¦þ¦ÿœû¯ÿ’ö¸ÿˆñ¿ÿ~ìÆÿsæÍÿjàÒÿ`Ú×ÿVÓÜÿMÌàÿCÄãÿ:½æÿ1µéÿ)®êÿ*¯êÿ3·èÿ;¾æÿDÅãÿMÌßÿWÓܽÿÙ¶ÿÝÿÿàÿÿäÿÿèÿÿìÿÿïÿÿòÿÿöÿÿùÿÿü"ÿÿþ,ÿÿÿ5ÿýÿ?ÿøÿIÿòÿRÿêÿ\ÿãÿeÿÛÿnÿÓÿwÿÌÿ€ÿÄÿˆÿ¼ÿ‘ÿ´ÿ™ÿ¬ÿ ÿ¥ý§ÿ�ú¯ÿ•÷µÿ�ô»ÿ…ðÁÿ}ëÆÿuçËÿnâÐÿeÝÔÿ^ØØÿVÓÛÿOÍßÿGÇâÿ@Áäÿ8»æÿ3·èÿ5¸çÿ;½æÿCÄãÿJÊàÿRÏÝÿZÕÚÿbÛÖÿjàÒÿråÍÿzêÈÿƒïÂÿ‹ó½ÿ”÷¶ÿœú¯ÿ¥ý§ÿ®ÿŸÿ·ÿ—ÿ¿ÿŽÿÈÿ„ÿÑÿzÿÙÿpÿâÿfÿëÿ[ÿôÿPÿûÿEÿÿÿ9ÿÿþ-ÿÿü"ÿÿùÿÿõ ÿÿðÿÿìÿÿçÿÿâÿÿÝÿÿØÿÿÓÿÿÎÿÿÊÿÿÆÿÿ¾ÿÿ¼ÿÿÂÿÿÆÿÿÍÿÿÑÿÿÖÿÿÛÿÿàÿÿæÿÿëÿÿïÿÿôÿÿùÿÿü"ÿÿÿ.ÿÿÿ;ÿúÿGÿñÿTÿçÿaÿÝÿlÿÓÿxÿÉÿƒÿ¿ÿŽÿµÿ˜ÿ«ÿ¢ÿ¡ü«ÿ–ø´ÿŒô¼ÿ‚îÃÿxéÊÿnãÐÿeÝÕÿ[ÖÚÿQÏÞÿHÈâÿ>Áåÿ5¹èÿ,±éÿ&¬ëÿ+°êÿ3¸èÿ<¿åÿEÆâÿNÍßÿXÔÛÿaÚ×™ÿã‚ÿçÿÿëÿÿïÿÿòÿÿö ÿÿùÿÿü!ÿÿþ*ÿÿÿ4ÿþÿ=ÿúÿGÿóÿPÿìÿZÿåÿcÿÝÿlÿÕÿuÿÎÿ~ÿÆÿ†ÿ¾ÿ�ÿ·ÿ–ÿ¯ÿžÿ§þ¦ÿŸû¬ÿ—ø³ÿ�õ¹ÿˆñ¿ÿ€íÄÿxèÉÿpäÏÿhßÓÿaÚ×ÿYÕÚÿRÏÝÿKÊàÿCÄãÿ;¾åÿ4¸çÿ1µèÿ4·çÿ:½æÿBÃãÿJÉáÿQÏÞÿYÔÚÿaÚ×ÿißÓÿqäÎÿyéÉÿ�îÃÿŠò¾ÿ’÷·ÿ›ú°ÿ£ý©ÿ¬ÿ¡ÿµÿ˜ÿ¾ÿ�ÿÇÿ†ÿÏÿ}ÿØÿrÿáÿhÿéÿ]ÿòÿRÿúÿGÿÿÿ;ÿÿÿ0ÿÿý$ÿÿùÿÿõ ÿÿòÿÿíÿÿèÿÿãÿÿÞÿÿÙÿÿÕÿÿÐÿÿËÿÿÆÿÿÂÿÿÀÿÿÁÿÿÆÿÿËÿÿÏÿÿÔÿÿÙÿÿÞÿÿäÿÿéÿÿîÿÿóÿÿ÷ÿÿüÿÿþ*ÿÿÿ6ÿüÿCÿôÿOÿêÿ\ÿáÿhÿ×ÿtÿÍÿÿÄÿŠÿ¹ÿ”ÿ¯ÿžÿ¥þ¨ÿ›ú°ÿ‘ö¸ÿ†ñÀÿ|ëÇÿråÍÿiàÓÿ_ÙØÿUÒÜÿLËàÿCÄãÿ9½æÿ0´éÿ'­êÿ%«ëÿ,±éÿ5¹çÿ=ÀåÿFÇâÿOÎÞÿYÕÛÿbÛÖÿlâÑbÿïAÿóþÿö ÿÿùÿÿü ÿÿþ)ÿÿÿ3ÿþÿ<ÿúÿEÿõÿOÿíÿXÿæÿbÿÞÿjÿ×ÿtÿÏÿ|ÿÈÿ…ÿÀÿ�ÿ¹ÿ•ÿ±ÿœÿ©þ¤ÿ¡üªÿšù±ÿ’ö¸ÿŠò½ÿ‚îÃÿzêÈÿsåÍÿkáÑÿcÜÕÿ]×ÙÿTÑÜÿMÌßÿFÆâÿ?Áåÿ7ºçÿ1µèÿ/³éÿ2·èÿ:½æÿAÃäÿIÉáÿQÏÞÿXÔÛÿ`Ú×ÿhßÓÿpäÎÿxéÊÿ�îÄÿ‰ò¿ÿ‘ö¸ÿšú±ÿ¢ýªÿ«ÿ¢ÿ´ÿ™ÿ¼ÿ‘ÿÅÿˆÿÎÿ~ÿ×ÿtÿßÿjÿèÿ_ÿðÿTÿùÿIÿþÿ=ÿÿÿ2ÿÿþ'ÿÿúÿÿöÿÿóÿÿîÿÿéÿÿåÿÿàÿÿÛÿÿÖÿÿÑÿÿÌÿÿÈÿÿÃÿÿÀÿÿÁÿÿÅÿÿÉÿÿÎÿÿÓÿÿØÿÿÝÿÿâÿÿèÿÿìÿÿñÿÿö ÿÿúÿÿþ%ÿÿÿ2ÿþÿ?ÿøÿKÿîÿXÿäÿdÿÛÿoÿÑÿ{ÿÇÿ†ÿ½ÿ‘ÿ³ÿ›ÿ©ÿ¤ÿŸü®ÿ”ø¶ÿŠó½ÿ€îÄÿvèËÿmâÑÿcÜÖÿYÕÛÿPÎßÿFÇâÿ=Àåÿ4¸èÿ+°êÿ$ªëÿ%«ëÿ-²éÿ6ºçÿ?ÁäÿHÈâÿQÏßÿZÖÚÿdÜÖÿmãÑöwéË'ÿù ÿüÛÿþ)ÿÿÿ2ÿþÿ;ÿûÿEÿõÿOÿîÿXÿçÿaÿßÿjÿØÿsÿÑÿ{ÿÉÿƒÿÂÿŒÿºÿ”ÿ²ÿ›ÿ«þ£ÿ£ý©ÿ›ú°ÿ“÷¶ÿŒó¼ÿ„ïÂÿ|ëÇÿuçÌÿmâÐÿfÝÔÿ^ØØÿWÓÛÿOÎÞÿHÈáÿAÃäÿ:½æÿ2¶èÿ-²éÿ-²éÿ2¶èÿ:½æÿAÃãÿIÉáÿPÎÞÿXÔÛÿ`Ù×ÿhßÔÿpäÏÿxéÊÿ€íÄÿˆò¿ÿ‘ö¹ÿ™ú²ÿ¢ýªÿªÿ£ÿ³ÿšÿ¼ÿ’ÿÄÿ‰ÿÍÿÿÖÿuÿÞÿkÿçÿaÿïÿUÿøÿJÿþÿ?ÿÿÿ4ÿÿþ(ÿÿûÿÿøÿÿóÿÿïÿÿêÿÿæÿÿáÿÿÜÿÿ×ÿÿÒÿÿÍÿÿÉÿÿÄÿÿÁÿÿÁÿÿÄÿÿÈÿÿÍÿÿÒÿÿ×ÿÿÜÿÿáÿÿæÿÿëÿÿðÿÿõ ÿÿùÿÿý"ÿÿÿ.ÿÿÿ;ÿúÿGÿñÿTÿèÿ`ÿÞÿlÿÔÿwÿÊÿ‚ÿÀÿ�ÿ¶ÿ˜ÿ¬ÿ¡ÿ¢ý«ÿ˜ù³ÿŽô»ÿ„ðÂÿzêÉÿpäÏÿfÞÔÿ]×ÙÿSÑÝÿJÊáÿAÃäÿ7»çÿ.³éÿ%«ëÿ!¨ëÿ'¬ëÿ/´éÿ8»çÿ@ÂäÿJÉáÿSÐÞÿ\×ÚÿeÝÕÿoäÐÿyéÊÀƒïÃþÿ<„ûÿEÿõÿOÿîÿXÿçÿaÿàÿjÿØÿrÿÑÿ{ÿÊÿƒÿÂÿ‹ÿ»ÿ“ÿ³ÿ›ÿ«ÿ¢ÿ¤ý©ÿœû¯ÿ•÷¶ÿ�ô»ÿ…ðÁÿ~ìÆÿvèËÿoãÐÿgÞÔÿ`ÙØÿXÔÛÿQÏÞÿKÊáÿCÄãÿ<¾åÿ4¸èÿ.³éÿ+°êÿ,²éÿ3·èÿ:½æÿAÃãÿIÉáÿPÎÞÿXÔÛÿ`ÙØÿhßÔÿpäÏÿxèÊÿ€íÅÿˆò¿ÿ‘ö¸ÿ™ú²ÿ¡ý«ÿªÿ£ÿ²ÿ›ÿ»ÿ’ÿÄÿ‰ÿÍÿ€ÿÕÿvÿÞÿlÿæÿaÿïÿVÿ÷ÿKÿýÿ@ÿÿÿ5ÿÿþ*ÿÿüÿÿøÿÿôÿÿðÿÿëÿÿæÿÿáÿÿÝÿÿØÿÿÓÿÿÎÿÿÉÿÿÅÿÿÁÿÿÀÿÿÃÿÿÇÿÿÌÿÿÑÿÿÖÿÿÛÿÿàÿÿåÿÿêÿÿïÿÿôÿÿøÿÿüÿÿþ+ÿÿÿ7ÿüÿDÿôÿPÿêÿ]ÿáÿiÿ×ÿtÿÎÿÿÄÿŠÿ¹ÿ”ÿ¯ÿžÿ¥þ¨ÿ›û°ÿ‘ö¸ÿ‡ñÀÿ}ìÇÿsæÍÿjàÓÿ`Ú×ÿWÓÜÿMÌàÿDÅãÿ;¾æÿ2¶èÿ(®êÿ!§ìÿ!§ìÿ(®êÿ1µéÿ9½æÿBÄäÿKËáÿUÑÝÿ^ØÙÿgßÔÿqåÏÿ{ëÈÿ…ðÂ`îÿY!æÿaïßÿjÿØÿsÿÑÿ{ÿÉÿƒÿÂÿ‹ÿ»ÿ“ÿ³ÿšÿ¬ÿ¡ÿ¤ý©ÿ�û¯ÿ•øµÿ�ô»ÿ†ðÀÿìÆÿwèËÿpäÏÿhßÓÿaÚ×ÿZÕÚÿRÐÝÿKËàÿEÅãÿ=Àåÿ6ºçÿ/³éÿ*¯êÿ)®êÿ-±éÿ3·èÿ;½æÿBÃãÿIÊáÿQÏÞÿYÔÛÿ`Ú×ÿhßÓÿpäÏÿxéÊÿ€íÅÿˆò¿ÿ‘ö¹ÿ™ú²ÿ¢ý«ÿªÿ£ÿ³ÿ›ÿ»ÿ“ÿÄÿ‰ÿÍÿ€ÿÕÿvÿÝÿlÿæÿbÿïÿWÿ÷ÿLÿýÿAÿÿÿ6ÿÿþ*ÿÿüÿÿùÿÿõÿÿðÿÿìÿÿçÿÿâÿÿÝÿÿØÿÿÓÿÿÏÿÿÊÿÿÆÿÿÂÿÿÀÿÿÂÿÿÇÿÿËÿÿÐÿÿÕÿÿÚÿÿßÿÿäÿÿéÿÿîÿÿóÿÿ÷ÿÿüÿÿþ)ÿÿÿ4ÿýÿAÿöÿNÿíÿZÿãÿeÿÚÿqÿÐÿ|ÿÆÿ‡ÿ¼ÿ’ÿ²ÿœÿ¨þ¥ÿžü®ÿ”ø¶ÿŠó½ÿ€îÅÿwèËÿmâÑÿcÜÖÿYÕÛÿPÏßÿGÈâÿ>Àåÿ5¹èÿ,±êÿ#©ëÿ¤ìÿ"¨ìÿ+°êÿ3·èÿ;¿æÿDÅãÿMÌàÿWÓÜÿ`ÚØÿiàÓÿsæÍÿ}ìÇÿ‡ñÀÚ‘ö¹Ðÿ|„Éÿ„ÿÂÿŒÿºÿ”ÿ³ÿ›ÿ«ÿ¢ÿ¤ý©ÿœû¯ÿ•øµÿŽô»ÿ†ñÀÿíÆÿxéËÿpäÏÿiàÓÿbÛ×ÿZÖÚÿSÑÝÿLËàÿEÆãÿ>Àåÿ7»çÿ0´éÿ)¯êÿ&¬ëÿ'­êÿ-²éÿ4¸èÿ<¿æÿCÅãÿJÉáÿRÐÞÿYÕÛÿaÚ×ÿißÓÿqäÏÿyéÉÿ�îÄÿ‰ò¿ÿ‘ö¸ÿšú²ÿ¢ý«ÿ«ÿ£ÿ³ÿ›ÿ¼ÿ’ÿÄÿ‰ÿÍÿ€ÿÕÿvÿÞÿlÿæÿbÿïÿWÿ÷ÿLÿýÿAÿÿÿ6ÿÿÿ+ÿÿüÿÿøÿÿõ ÿÿñÿÿìÿÿçÿÿâÿÿÞÿÿÙÿÿÔÿÿÏÿÿËÿÿÆÿÿÂÿÿÀÿÿÂÿÿÆÿÿËÿÿÏÿÿÔÿÿÙÿÿÞÿÿäÿÿéÿÿíÿÿòÿÿ÷ ÿÿûÿÿþ&ÿÿÿ2ÿþÿ?ÿøÿKÿïÿWÿæÿcÿÜÿoÿÒÿzÿÉÿ…ÿ¿ÿ�ÿµÿ™ÿ«ÿ£ÿ¡ý¬ÿ—ù´ÿ�ô¼ÿƒïÃÿyéÉÿoäÐÿfÞÕÿ\×ÚÿSÑÞÿIÊáÿ@Âäÿ7»çÿ.³éÿ%«ëÿ¤ìÿ¤ìÿ$ªëÿ-²êÿ5¹èÿ>ÀåÿGÇâÿPÎßÿYÕÛÿbÛ×ÿlâÑÿvèÌÿ€îÅÿŠó¾ÿ”ø·^¹ÿ•²ÿœÖ«ÿ£ÿ£ý©ÿœû°ÿ•ø¶ÿ�ô¼ÿ†ðÁÿ~ìÆÿwèËÿpäÏÿißÓÿaÚ×ÿ[ÖÚÿSÑÝÿMËàÿEÆãÿ>Áåÿ8»çÿ1µèÿ*¯êÿ%«ëÿ$ªëÿ(­êÿ/³éÿ6¹çÿ=¿åÿDÅãÿKÊàÿSÑÝÿZÖÚÿbÛ×ÿjàÒÿråÎÿzêÉÿ‚îÄÿŠó¾ÿ’÷¸ÿšú±ÿ£ýªÿ«ÿ¢ÿ´ÿšÿ¼ÿ’ÿÅÿ‰ÿÍÿ€ÿÖÿvÿÞÿlÿçÿaÿïÿWÿ÷ÿLÿýÿAÿÿÿ6ÿÿÿ+ÿÿüÿÿùÿÿô ÿÿñÿÿìÿÿèÿÿãÿÿÞÿÿÙÿÿÕÿÿÏÿÿËÿÿÇÿÿÂÿÿÀÿÿÂÿÿÆÿÿÊÿÿÏÿÿÔÿÿÙÿÿÞÿÿãÿÿèÿÿíÿÿòÿÿö ÿÿûÿÿþ$ÿÿÿ0ÿþÿ<ÿúÿIÿñÿUÿçÿaÿÞÿlÿÔÿxÿÊÿƒÿÁÿ�ÿ·ÿ˜ÿ­ÿ¡ÿ£ýªÿ™ú³ÿ�õºÿ…ðÂÿ{ëÈÿråÎÿhßÔÿ^ÙØÿUÒÝÿLËàÿCÄãÿ:½æÿ1µèÿ(®êÿ¦ìÿ¡ìÿ¥ìÿ'­ëÿ/´éÿ8»çÿ@ÂäÿIÉâÿRÐÞÿ[×ÚÿeÝÕÿoäÐÿyêÊÿƒïÄÿ�ô½ÿ—ùµ·¡ý¬›ú±>“÷·÷Œô½ÿ…ðÂÿ~ìÇÿvèËÿoäÏÿhßÓÿaÛ×ÿZÕÚÿSÑÝÿLËàÿEÆãÿ?Áåÿ8»çÿ1µèÿ*¯êÿ$ªëÿ!¨ìÿ#ªëÿ)¯êÿ1µéÿ8»çÿ?ÁäÿFÆâÿMÌàÿTÒÝÿ\×ÚÿcÜÖÿkáÒÿsæÍÿ{ëÈÿƒïÃÿ‹ô½ÿ“÷·ÿœû°ÿ¤þ©ÿ¬ÿ¡ÿµÿ™ÿ½ÿ‘ÿÆÿˆÿÎÿÿ×ÿtÿßÿkÿçÿaÿðÿVÿøÿKÿýÿ@ÿÿÿ5ÿÿÿ*ÿÿýÿÿùÿÿôÿÿðÿÿìÿÿèÿÿãÿÿÞÿÿÙÿÿÔÿÿÐÿÿËÿÿÇÿÿÃÿÿÁÿÿÂÿÿÆÿÿÊÿÿÏÿÿÔÿÿÙÿÿÝÿÿãÿÿèÿÿíÿÿñÿÿö ÿÿúÿÿý"ÿÿÿ/ÿÿÿ;ÿûÿGÿòÿSÿéÿ_ÿßÿkÿÖÿvÿÌÿ�ÿÂÿ‹ÿ¸ÿ–ÿ¯ÿ ÿ¥þ©ÿ›û±ÿ‘ö¹ÿ‡ñÀÿ}ìÇÿtæÍÿjáÓÿaÚØÿWÔÜÿNÍàÿEÆãÿ<¾åÿ3·èÿ*¯êÿ!¨ëÿ¡íÿ¡íÿ!¨ìÿ*¯êÿ2¶èÿ:½æÿCÄäÿLËáÿUÓÝÿ_ÙØÿhßÔÿræÎÿ|ëÈÿ†ñÂÿ�öºÿšû²ä¤þª#|ëÈeuçÌþnãÐÿgÞÔÿ`ÚØÿYÕÛÿRÐÞÿKËàÿEÆãÿ>Àåÿ7»çÿ1µéÿ*¯êÿ$ªëÿ ¦ìÿ §ìÿ%«ëÿ+±éÿ3·èÿ:½æÿAÂäÿGÈâÿOÎßÿVÓÜÿ^ØÙÿeÝÕÿmâÑÿuçÌÿ}ìÇÿ…ðÂÿ�ô¼ÿ•ø¶ÿ�û¯ÿ¦þ¨ÿ®ÿ ÿ¶ÿ˜ÿ¿ÿ�ÿÇÿ†ÿÏÿ}ÿØÿsÿáÿjÿéÿ_ÿñÿUÿùÿJÿþÿ?ÿÿÿ4ÿÿþ)ÿÿüÿÿùÿÿõÿÿñÿÿìÿÿèÿÿãÿÿÞÿÿÙÿÿÔÿÿÐÿÿËÿÿÇÿÿÃÿÿÁÿÿÂÿÿÆÿÿÊÿÿÏÿÿÔÿÿØÿÿÝÿÿãÿÿçÿÿìÿÿñÿÿö ÿÿúÿÿý!ÿÿÿ.ÿÿÿ:ÿûÿFÿóÿRÿêÿ^ÿáÿiÿ×ÿuÿÍÿ€ÿÄÿŠÿºÿ”ÿ°ÿžÿ¦þ§ÿœü°ÿ“÷¸ÿ‰ò¿ÿíÆÿuèÌÿláÑÿbÜ×ÿXÕÛÿOÎßÿFÇâÿ=Àåÿ4¹èÿ,±éÿ#©ëÿ¢íÿžíÿ£ìÿ$ªëÿ,²êÿ5¹èÿ=ÀåÿFÇãÿOÎßÿXÕÛÿbÛ×ÿkâÒÿuèÌÿíÆÿ‰ò¿ÿ“÷¸ÿ�ü°ô§ÿ§Cÿÿÿ^ÙØvXÔÜþQÏÞÿJÊáÿDÅãÿ=Àåÿ6ºçÿ0´éÿ)¯êÿ#©ëÿ¥ìÿ¤ìÿ!§ëÿ'­êÿ.³éÿ5¹èÿ<¾æÿCÄäÿJÊáÿQÏÞÿXÕÛÿ`ÚØÿhßÔÿoäÐÿwèËÿíÆÿ‡ñÀÿ�ö»ÿ—ù´ÿŸü­ÿ¨þ¦ÿ°ÿžÿ¸ÿ–ÿÁÿŽÿÉÿ…ÿÑÿ{ÿÚÿqÿâÿhÿêÿ]ÿóÿSÿúÿHÿþÿ=ÿÿÿ2ÿÿþ'ÿÿüÿÿùÿÿõÿÿðÿÿìÿÿçÿÿâÿÿÞÿÿÙÿÿÔÿÿÏÿÿËÿÿÇÿÿÃÿÿÁÿÿÂÿÿÆÿÿÊÿÿÏÿÿÔÿÿØÿÿÝÿÿâÿÿçÿÿìÿÿñÿÿöÿÿúÿÿý!ÿÿÿ-ÿÿÿ9ÿüÿEÿôÿRÿëÿ]ÿáÿiÿØÿtÿÎÿÿÅÿŠÿ»ÿ“ÿ±ÿ�ÿ¨þ§ÿ�ü¯ÿ”ø·ÿŠó¾ÿ€îÆÿwèËÿmâÑÿdÝÖÿZÖÛÿQÏßÿHÈâÿ?Áåÿ6ºçÿ-²éÿ%«ëÿ£ìÿ�íÿžíÿ¦ìÿ'­ëÿ/´éÿ8»çÿ@ÃåÿJÉâÿSÐÞÿ\×ÚÿeÞÕÿoäÐÿyêÊÿƒïÄÿ�õ½ÿ—ùµÿ¡þ­ô«ÿ£VÿÿÿÿÿÿÿÿÿBÃäe;¾æö5¹çÿ.³éÿ(­êÿ"¨ëÿ£ìÿ¢íÿ¤ìÿ#©ëÿ*¯êÿ1µéÿ8»çÿ>ÁåÿEÆãÿLÌàÿTÑÝÿ[ÖÚÿbÜ×ÿjàÓÿråÎÿyêÉÿ�ïÅÿ‰ó¿ÿ‘÷¹ÿšú²ÿ¢ý«ÿªÿ¤ÿ²ÿœÿ»ÿ”ÿÃÿ‹ÿËÿ‚ÿÓÿyÿÜÿoÿäÿeÿìÿ[ÿôÿPÿûÿFÿÿÿ;ÿÿÿ0ÿÿþ%ÿÿüÿÿøÿÿôÿÿðÿÿëÿÿæÿÿâÿÿÝÿÿÙÿÿÔÿÿÏÿÿËÿÿÆÿÿÂÿÿÁÿÿÂÿÿÆÿÿËÿÿÏÿÿÔÿÿÙÿÿÞÿÿãÿÿçÿÿíÿÿñÿÿöÿÿúÿÿý!ÿÿÿ-ÿÿÿ9ÿüÿEÿôÿQÿëÿ]ÿâÿhÿØÿtÿÏÿ~ÿÅÿ‰ÿ¼ÿ“ÿ²ÿ�ÿ¨ÿ¦ÿžü®ÿ”ø·ÿ‹ó¾ÿ�îÅÿxéËÿnãÑÿdÝÖÿ[ÖÚÿRÐÞÿIÉâÿ@Âäÿ7»çÿ.³éÿ&¬ëÿ¤ìÿ�íÿ›íÿ¡íÿ"©ëÿ*°êÿ3·èÿ;¾æÿDÅãÿMÌàÿVÓÝÿ`ÚØÿiàÓÿsæÎÿ}ìÈÿ‡ñÁÿ‘öºÿ›û²ÿ¥þ©ã¯ÿ Eÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ&¬ë@ ¦ìÔ¢ìÿ íÿ¡ìÿ ¦ìÿ&¬ëÿ-²éÿ4¸èÿ;½æÿAÃäÿHÉâÿOÎßÿWÓÜÿ^ØÙÿeÞÕÿmãÑÿuçÌÿ}ìÈÿ„ðÂÿŒô½ÿ”ø·ÿœû°ÿ¥þ©ÿ­ÿ¢ÿµÿšÿ½ÿ’ÿÅÿ‰ÿÎÿ€ÿÖÿvÿÞÿmÿæÿbÿïÿXÿ÷ÿNÿüÿCÿÿÿ8ÿÿÿ.ÿÿþ"ÿÿûÿÿ÷ ÿÿóÿÿïÿÿêÿÿæÿÿáÿÿÜÿÿ×ÿÿÓÿÿÎÿÿÊÿÿÆÿÿÂÿÿÁÿÿÃÿÿÇÿÿËÿÿÐÿÿÔÿÿÙÿÿÞÿÿãÿÿèÿÿíÿÿòÿÿö ÿÿúÿÿý ÿÿÿ-ÿÿÿ9ÿüÿEÿõÿQÿëÿ]ÿâÿhÿÙÿsÿÏÿ~ÿÅÿ‰ÿ¼ÿ“ÿ²ÿœÿ¨ÿ¦ÿŸý®ÿ•ù¶ÿ‹ô¾ÿ‚ïÅÿxéËÿoäÐÿeÞÕÿ\×ÚÿSÐÞÿJÊâÿ@Âäÿ8¼çÿ/´éÿ'­ëÿ¥ìÿ�íÿ™íÿ�íÿ¥ìÿ&¬ëÿ.³éÿ6ºçÿ?ÁåÿHÉâÿQÏÞÿZÖÛÿcÝÖÿmãÑÿwéÌÿ€îÅÿ‹ô¾ÿ•ø¶ÿŸý®ÿ©ÿ¥¶³ÿœ&ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŸí¤ì„#©ëí*¯êÿ1µéÿ7»çÿ>ÀåÿEÆãÿLËáÿSÐÞÿZÖÛÿaÛ×ÿiàÔÿpåÏÿxéËÿ€îÆÿˆòÀÿ�öºÿ—ù´ÿŸý­ÿ¨ÿ¦ÿ°ÿŸÿ¸ÿ—ÿÁÿ�ÿÈÿ†ÿÑÿ}ÿÙÿsÿáÿiÿéÿ_ÿñÿUÿùÿJÿþÿ@ÿÿÿ5ÿÿÿ*ÿÿýÿÿúÿÿö ÿÿòÿÿîÿÿéÿÿåÿÿàÿÿÜÿÿ×ÿÿÒÿÿÎÿÿÉÿÿÅÿÿÁÿÿÁÿÿÃÿÿÇÿÿÌÿÿÐÿÿÕÿÿÚÿÿßÿÿäÿÿéÿÿîÿÿòÿÿ÷ ÿÿûÿÿþ"ÿÿÿ.ÿÿÿ:ÿüÿFÿôÿRÿëÿ]ÿâÿhÿØÿtÿÏÿÿÆÿ‰ÿ¼ÿ“ÿ²ÿ�ÿ©ÿ¦ÿŸý®ÿ•ù¶ÿ‹ô¾ÿ‚ïÄÿxéËÿoäÐÿeÞÕÿ\×ÚÿSÑÞÿJÊáÿAÃäÿ8¼çÿ0µéÿ'­ëÿ¥ìÿžíÿ˜íÿšíÿ¡íÿ"¨ìÿ*¯êÿ2·èÿ;¾æÿCÄäÿLËàÿUÒÝÿ^ÙÙÿhßÔÿqæÏÿ{ëÉÿ…ñÃÿ�ö»ÿ™û³ÿ£þ«Ù®ÿ¡b¸ÿ˜ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ4¸è#;¾æƒBÃäÚIÉâÿPÎßÿVÓÜÿ^ØÙÿeÝÖÿmãÑÿtçÍÿ|ìÈÿ„ðÃÿŒô¾ÿ”ø¸ÿœû±ÿ¤þªÿ¬ÿ£ÿ´ÿ›ÿ¼ÿ“ÿÄÿ‹ÿÌÿ‚ÿÔÿyÿÜÿoÿäÿfÿìÿ\ÿôÿQÿûÿFÿÿÿ<ÿÿÿ1ÿÿÿ&ÿÿýÿÿùÿÿõÿÿñÿÿíÿÿèÿÿãÿÿßÿÿÚÿÿÖÿÿÑÿÿÍÿÿÈÿÿÄÿÿÁÿÿÁÿÿÄÿÿÉÿÿÍÿÿÑÿÿÖÿÿÛÿÿàÿÿåÿÿêÿÿîÿÿóÿÿø ÿÿûÿÿþ#ÿÿÿ0ÿÿÿ;ÿûÿGÿôÿSÿêÿ^ÿáÿiÿØÿuÿÎÿ€ÿÄÿŠÿ»ÿ”ÿ±ÿ�ÿ¨ÿ¦ÿžý¯ÿ•ù¶ÿ‹ô¾ÿ‚ïÅÿxéËÿoäÐÿeÞÕÿ\×ÚÿSÑÞÿJÊáÿAÃäÿ8¼çÿ0µéÿ'­ëÿ¦ìÿžíÿ˜îÿ—îÿ�íÿ¥ìÿ%¬ëÿ.³éÿ6ºçÿ?ÁåÿHÈâÿPÏßÿZÖÛÿcÜ×ÿlâÒÿvèÌÿ€îÆÿŠó¿ÿ”ø¸÷žý°Á©ÿ¦c²ÿ�ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿTÑÝ [ÖÚAbÛ×�jàÓµqåÏÔyêÊé€îÅëˆòÀò�ö»ÿ˜ù´ÿ ý®ÿ¨ÿ§ÿ°ÿŸÿ¸ÿ—ÿÀÿ�ÿÈÿ‡ÿÐÿ~ÿØÿuÿàÿkÿèÿaÿðÿWÿ÷ÿMÿýÿBÿÿÿ8ÿÿÿ-ÿÿþ"ÿÿûÿÿø ÿÿôÿÿðÿÿëÿÿçÿÿâÿÿÞÿÿÙÿÿÔÿÿÐÿÿËÿÿÇÿÿÃÿÿÁÿÿÂÿÿÅÿÿÊÿÿÎÿÿÓÿÿ×ÿÿÜÿÿáÿÿæÿÿëÿÿïÿÿôÿÿø ÿÿüÿÿþ%ÿÿÿ1ÿþÿ=ÿúÿHÿóÿTÿéÿ`ÿàÿkÿ×ÿvÿÍÿ�ÿÄÿ‹ÿºÿ•ÿ°ÿžÿ§þ§ÿ�ü¯ÿ”ø·ÿŠô¿ÿ�îÅÿwéËÿnãÐÿeÝÖÿ\×ÚÿSÐÞÿJÊáÿAÃäÿ8»çÿ0µéÿ'­ëÿ¦ìÿŸíÿ—îÿ •îÿ™îÿ¡íÿ"©ìÿ*°êÿ2·èÿ;¾æÿCÅãÿLÌáÿUÓÝÿ^ÙÙôhàÔæræÏå{ëÉ×…ñþ�ö»›™û³e£þ«*­ÿ¢ÿðÿÿÀÿÿÿþü?øðàÀÀ€€€€ÀÀàðøü?þÿÿÿÀÿÿðÿevolvotron-0.8.3/dist/evolvotron.desktop0000644000175000017500000000025615230700302017151 0ustar karlkarl[Desktop Entry] Type=Application Name=Evolvotron Comment=Interactive generative art program Exec=evolvotron Icon=evolvotron Terminal=false Categories=Qt;Graphics;2DGraphics; evolvotron-0.8.3/dist/bump_ver.b0000644000175000017500000000025015230700302015315 0ustar karlkarlold: 0,8,2 new: 0,8,3 files: [ %VERSION [{echo "$v"}] %libevolvotron/common.h [{APP_VERSION "$v"}] %dist/evolvotron.spec ["Version: $v"] ] evolvotron-0.8.3/dist/app.rc0000644000175000017500000000010615230700302014441 0ustar karlkarlIDI_ICON1 ICON DISCARDABLE "dist/evolvotron.ico" evolvotron-0.8.3/common.pro0000644000175000017500000000320615230700302014406 0ustar karlkarl# Shared definitions included by the other .pro files # qmake should NOT be executed on this file directly # append debug or release CONFIG+= qt thread stl exceptions release #release #debug # QT += ####################################### # Version numbering. VERSION_NUMBER should have been set on the qmake command line (see .configure script) # qmake's library code can use this too (but only for shared libraries which we don't use) VERSION=$$VERSION_NUMBER ####################################### # Disable assertions in release version QMAKE_CXXFLAGS_RELEASE += -DNDEBUG QMAKE_CFLAGS_RELEASE += -DNDEBUG ###################################### # Other stuff: # Disable implicit cast from QString to/from char* - we should be using .local8Bit and ::fromLocal8Bit # NB We don't use the corresponding -DQT_NO_CAST_ASCII because it breaks QString("...") which is used all over the place # This probably wouldn't be usable until all the strings were moved out of the app - see Qt I18N docs. # Also add gcc threading option (not entirely clear whether this is needed but it doesn't seem to hurt) # Used to use -pthread -DBOOST_SP_USE_PTHREADS as a workround for debian bug 485434 (maybe only needed on sparc?) # but it seemed to cause problems with app not quitting once boost::program_options started being used. QMAKE_CXXFLAGS_RELEASE += -DQT_NO_ASCII_CAST QMAKE_CXXFLAGS_DEBUG += -DQT_NO_ASCII_CAST ###################################### # Hide intermediate build files away MOC_DIR = moc RCC_DIR = moc OBJECTS_DIR = ../obj ################## # OPTION: Enable these options for profiling # #QMAKE_LFLAGS_RELEASE += -pg #QMAKE_CXXFLAGS_RELEASE += -pg evolvotron-0.8.3/cbuild0000755000175000017500000000316215230700302013565 0ustar karlkarl#!/usr/bin/bash # Container build script for Evolvotron. if [ ! -s project.tar.gz ]; then copr -a -t mingw fi TIME=$(date +%H%M%S) SCRIPT=build-$TIME ID=${SCRIPT} HDIR=/tmp CDIR=/tmp AVER=$(./VERSION) ARC_DIR=/tmp/evolvotron-$AVER clean_dir () { if [ -d "$1" ]; then rm -rf "$1"/*; else mkdir -p "$1"; fi } container_build () { clean_dir ${ARC_DIR} podman run -d -it --name=$ID $1 /bin/bash || exit podman cp project.tar.gz $ID:$CDIR podman cp $HDIR/${SCRIPT} $ID:$CDIR/${SCRIPT} podman exec -it $ID /bin/bash $CDIR/${SCRIPT} } case $1 in windows) echo ' mkdir evo cd evo tar xf /tmp/project.tar.gz copr -t mingw ' >$HDIR/${SCRIPT} container_build dev/f35-mingw podman cp $ID:/home/build/evo/evolv.exe ${ARC_DIR}/evolvotron.exe || exit podman cp $ID:/home/build/evo/evolv_mutate.exe ${ARC_DIR}/evolvotron_mutate.exe podman cp $ID:/home/build/evo/evolv_render.exe ${ARC_DIR}/evolvotron_render.exe # Build zip archive. if [ "$2" != "-b" ]; then FN=`readlink -f arc/mingw-qt_app.tar.gz` tar xf $FN -C ${ARC_DIR} --strip-components=1 cd ${ARC_DIR%/*}; zip -r evolvotron-$AVER.zip ${ARC_DIR##*/} fi ;; linux) echo ' mkdir evo cd evo tar xf /tmp/project.tar.gz copr ' >$HDIR/${SCRIPT} container_build dev/f35 podman cp $ID:/home/build/evo/evolv ${ARC_DIR}/evolvotron || exit podman cp $ID:/home/build/evo/evolv_mutate ${ARC_DIR}/evolvotron_mutate podman cp $ID:/home/build/evo/evolv_render ${ARC_DIR}/evolvotron_render ;; *) echo "Usage: $0 {linux|windows} [-b]" echo -e '\nOptions:' echo ' -b Build binary only; do not create archive.' exit 1 esac echo "$SCRIPT done!" podman stop $ID evolvotron-0.8.3/VERSION0000755000175000017500000000041315230700302013444 0ustar karlkarl#!/bin/sh # Script to echo the current version number. # The number is also hardcoded in these files: # libevolvotron/common.h # evolvotron.spec # NB If you edit this, "make distclean" and then rebuild (./BUILD) as there is no dependency checking echo "0.8.3" evolvotron-0.8.3/USAGE-update.sh0000755000175000017500000000131715230700302015060 0ustar karlkarl#!/bin/bash echo "Rebuilding built-in user documentation..." HTML=evolvotron.html QTDOC=libevolvotron/usage_text.h if command -v boron &> /dev/null ; then ./text_to_markup.b -html USAGE >$HTML || echo "Couldn't build $HTML" ./text_to_markup.b -qml -s USAGE >$QTDOC || echo "Couldn't build $QTDOC" else ./text_to_markup.py -html $HTML || echo "Couldn't build $HTML" ./text_to_markup.py -qml -s $QTDOC || echo "Couldn't build $QTDOC" fi if ! test -s $QTDOC ; then echo "\"Full built-in user documentation not available due to problem during build configuration\"" > $QTDOC echo "Something went wrong, used built-in user documentation fallback plan" fi echo "...built built-in user documentation" evolvotron-0.8.3/USAGE0000644000175000017500000006500315230700302013166 0ustar karlkarlEVOLVOTRON USER MANUAL ====================== Evolvotron is interactive "generative art" software to evolve images/textures/patterns through an iterative process of random mutation and user-selection driven evolution. On starting the application, a grid of images is displayed. Resize or maximise the application if you like, but the more pixels have to be calculated, the slower it will be. (For the default 2D image mode, you will need a fast machine or patience. For the optional animation mode, you will need both.) Simply repeat the following until bored: - Click (singleclick) on an image you like to spawn the next generation of its mutant offspring. - Wait until variations on it are regenerated in sufficient detail that you can decide which one you like best again. IMPORTANT: Initially you should select images with some sort of variation. If you select a uniform image, you may get stuck in a degenerate zone with little to mutate and therefore little chance of escape to more interesting images. You can always reset/restart from the "File" menu (the difference is that "reset" also resets the mutation parameters to their default values). Selecting one of the "warp" options from a context menu (right-click on an image) can also help by introducing an additional opportunity for mutation on subsequent spawns. Note that various spirals, grids and tiles, although complex looking, are actually implemented by a single function node and may leave you stuck too. COMMAND LINE OPTIONS ==================== The following are equivalent: - evolvotron --grid 12x8 - evolvotron --grid=12x8 - evolvotron -g 12x8 GENERAL OPTIONS --------------- -a, --autocool Enable autocooling by default, and cause resets of mutation parameters to re-enable autocooling if it was disabled. -F, --fullscreen Start in "fullscreen" mode (NB for Qt on X11 this means a screen-filling borderless/undecorated window is used; it's not simply maximising the window, and it's not the sort of framebuffer hijacking used by SDL games). The Qt documentation claims some window managers may not be entirely cooperative with this (in which case sorry, you're on your own). evolvotron actions which bring up dialog boxes (e.g save) seem to generally behave fairly sensibly but child windows (e.g enlargements or dialogs) can show some "interesting" behaviour. Fullscreen mode can be toggled within the application using CTRL-F key. The Esc key will also exit it. -g, --grid x Sets size of the grid of image display cells in the main application area (defaults to 5x6) -h, --help Print summary of command line options and exit. -j, --jitter Enable sample jittering. Samples will be made at a random position within a pixel instead of on a regular grid, providing some antialiasing. -m, --multisample Enables additional antialiasing passes. Specifying 2 or 3 will provide an additional pass with 2x2 or 3x3 samples per pixel. Specifying 4 (or higher) will provide a 2x2 and a final 4x4 pass. Specifying 1 provides the default behaviour of one sample per pixel. For best rendering quality also specify -j. -M, --menuhide Start with menu and status bar hidden. Nice with --fullscreen. Hiding can be toggled within the application using CTRL-M. The Esc key will also bring them back. -p, --spheremap Images are produced by sampling the underlying 3D function on the latitude-longitude grid of a sphere. The resulting images should be usable as spheremaps/spherical environment maps. Animations vary the radius of the sphere. NB when in spheremap mode, middle mouse button adjustments do not yet behave like you'd expect. -S, --startup Specify a function filename (evolvotron's XML format) to load on startup (or reset). The option can be provided multiple times, and this is also the interpretation of any positional arguments. Startup functions are placed in the grid from left to right, top to bottom. -U, --shuffle Use in conjunction with -S / --startup options, to display the specified functions in random order, both on application startup and on each reset of the application. ANIMATION OPTIONS ----------------- -f, --frames Number of frames in animations (defaults to 1 i.e no animation) -l, --linear Vary z linearly with time rather than sinusoidally. Sinusoidal variation generally looks better when animations are "bounced" forwards and backwards, but this option is useful when generating slices to use as volumetric textures. -s, --fps Rate at which frames are displayed per second (integer). (Defaults to 8). POWER-USER & DEBUG OPTIONS -------------------------- Note that the usual Qt/X11 options (for example, -geometry x option to set on-screen size in pixels) are processed and removed before evolvotron options are checked. -D, --debug Puts the certain aspects of the app into a more debug oriented mode. Currently (ie this may change) it simply changes function weightings so virtually all function nodes are FunctionNoiseOneChannel. By itself this is a pretty pointless thing to do, but in conjunction with the -X options it's useful for examining the behaviour of specific functions. -E, --enlargement-threadpool Use a separate thread pool for computing enlargements. Using this option ensures computation of enlargements continue to make some progress even while the main grid is being actively worked on. However, this will be at the expense of main grid rendering performance. Without this option, enlargements' final high-resolution renderings are invariably lower priority than computation for images in the main grid. See also the -N option to control the priority of threads in this pool. -n, --nice Sets additional niceness (relative to the main application thread) of the compute (rendering) thread(s). It's useful to run compute threads at a slightly lower priority ("nice 4" is the default without this option) than the main (GUI) part of the program (but note that this means other normal/lowish priority tasks running on your machine may slow evolvotron down a bit more than expected). -N, --Nice Sets additional niceness (relative to the main application thread) of the compute thread(s) computing enlargements (default value is 8). Only effective in conjunction with -E option. -t, --threads Sets number of compute threads. If this is not specified, then as many compute threads are created as there are processors on the system (unless this cannot be discovered in which case only a single compute thread is created). Non-linux builds will likely not include code to determine processor count (suitable patches gratefully received). -u, --unwrapped Modifies -F behaviour so that the specified "favourite" function is NOT wrapped by space/colour transforms. NB For functions without leaf nodes or parameters (e.g FunctionSphericalToCartesian) this doesn't leave any scope for variation or future mutation. Function name recognition is case sensitive. Example: $ evolvotron -F FunctionKaleidoscope -u -v, --verbose Verbose mode, writes various things to application stderr. This is primarily intended to assist debugging. This option used to be useful for getting a list of supported function names for use with the -F option, but those can also be inspected via the Settings dialogs. -x, --favourite Force a specific "favourite" function type to be used at the top level of all function trees. The specified function is still wrapped by spatial and colour warping functions which may disguise it considerably. A list of all the function names understood by evolvotron is output during app startup when the -v option is specified. Function name recognition is case sensitive. Example: $ evolvotron -F FunctionSpiralLinear MOUSE CONTROL ============= LEFT-CLICK ---------- A left-click on an image in the main window can either mutate it or toggle its lock. The lock is toggled when clicking in the upper right corner. Clicking elsewhere spawns the mutant offspring of that image to all the other (non-locked) displays in the grid. RIGHT-CLICK CONTEXT MENU ------------------------ Right clicking on an image gets you a few more options: - "Respawn" regenerates just the current image from whatever it was spawned from (and using recolour or warp, if that's what was used to produce it). The main use of this is to make your grid of images look nice for screendumps, by regenerating any which aren't up to scratch. NB May not work as expected after an "undo". - "Spawn" is the same as clicking an image. It generates mutated images to all unlocked images in the grid. - "Recolour" to produce different coloured variants of the selected image - "Warp"'s sub-options produce variants of the image which have been zoomed/rotated/panned. - "Lock" to prevent an image from being overwritten by spawns from other images (select again to toggle). - "Enlarge" to produce a blow-up of the image in a single window. Submenu items select either a freely resizable window or a scrollable view of a fixed size image. If the application is running in fullscreen mode (NB this is NOT the same as a simply "maximised" window) then the enlarged image will also be fullscreen (the "Resizeable" mode is probably what you want in this case as the image will automatically be rendered at the correct resolution). - "Save image" to save the image in a file (.ppm or .png). You generally want to save an enlarged image: if you save a small image from the grid, the size you see on the screen is the size you get in the file. Save isn't allowed until the full resolution image has been generated; if you try to save too early a dialog box will be displayed telling you to try again later. - "Save function" to store the function to an XML file. - "Load function" to load a stored function from an XML file. NB if the file was saved from a different version numbered evolvotron, a warning message will be generated. Save/load of functions is an experimental feature and you should not count on future versions of evolvotron being able to load files saved from old versions, or producing the same image from a loaded function. Attempting to load functions from later versions into earlier versions is even less likely to succeed. - "Simplify" prunes the function tree of redundant branches where possible (the same action can be applied to all images from the main "Edit" menu). This doesn't change the appearance of the image, but may make it recompute faster. - "Properties" brings up a dialog box containing some information about the image (e.g the number of function nodes it contains). MIDDLE MOUSE BUTTON ------------------- [NB This feature will probably only be of practical use to those with high-end machines]. You can use the middle mouse button to drag-adjust individual images. This is useful for "final composition" type tweaks, e.g centering an image's most interesting feature, or just for satisfying your curiosity about what's off the edge of the image. It also works on enlarged images, although it's virtually unusable without a bit of practice on smaller, faster ones (just boldly make the adjustment you want, release the button... and wait). Changes made can be rolled-back on the main Edit/Undo menu item, one drag-action at a time. An unmodified middle-mouse drag pans the image around following the mouse motion. A SHIFT-middle drag zooms the image in and out with scaling proportional to the distance from the centre of the image. Beware of generating huge zooms by clicking too near the centre of the image. An ALT-SHIFT-middle drag is similar but anisotropic: the scaling may be different in X and Y. Warning: this technique is very sensitive and can be quite tricky to use! In particular, if you initially click near the centre axes of the image the zoom factor can be HUGE, so the best way to start using this is to click about halfway on a diagonal between the image centre and a corner and gently move in and out radially. Dragging from one side of the image to the other flips it over (the degenerate case of infinite zoom at the centre is handled cleanly I think). If it all goes horribly wrong, undo and try again. A CTRL-middle drag rotates the image about its centre. A CTRL-ALT-middle drag shears the image (the best way to see what this does is to click in the corner of an image and move the mouse horizontally or vertically). MOUSE WHEEL ----------- Scrolling the mouse wheel zooms the image in and out. KEYBOARD CONTROL ================ There are some keyboard shortcuts. MAIN WINDOW ----------- - "r"/"t"/"x" perform various starts of reset/restart. - "CTRL-Q" quits the application. - "u" (and also CTRL-Z) does an undo. - "CTRL-F": full-screen mode. See also "-F" command line option. Fullscreen mode propagates to enlarged image display windows. NB The application may completely disappear from the screen for a brief interval while switching mode. - "CTRL-M": hides status and menu-bar hiding, which can be nice when in full-screen or window-maximised mode. See also "-M" command line option. Also note that while the menu bar is hidden, most of these keyboard shortcuts won't function as they're tied to the menu system. - Esc: exits full-screen and/or menu-hiding mode, putting the application into its normal default state. ENLARGEMENT WINDOWS ------------------- The image display windows created by selecting "Enlarge" from a context menu also have a couple of keyboard operations: - "f" : [NB only available with fullscreen build option] toggles full-screen mode. When returning to normal mode, if the main app window was fullscreen then it will also drop back to normal mode. - Esc : [NB only available with fullscreen build option] completely closes a fullscreen-mode enlargement window. GUI ELEMENTS ============ MAIN MENU BAR ------------- - File menu: Items to restart, reset and quit the application. The difference between restart and reset is that reset sets the mutation parameters back the their default values. The "randomize function weights" version of restart scrambles the relative probability of the various function types (if you think evolvotron just keeps generating the same kinds of images give it a try). The "restart with specific function" item duplicates the functionality of the "-x" and "-X" command-line options. - Edit menu: "Undo" lets you undo certain actions: e.g spawn, middle-button adjustment, simplification and lock/unlock. There is a large but limited number of levels of undo. "Simplify" is of curiosity value only: it prunes redundant branches from images ("junk DNA"); this may help them recompute faster but at the cost of there being less mutatable material. - Settings menu: "Mutations" brings up a dialog to modify the amount of change spawned images are subject to. (See "advanced usage" below.) "Functions" brings up a dialog to modify the relative probability of functions being used. By default all functions are equally likely except for iterative functions and fractals, which are almost but not completely suppressed. But if you think there are too many spirals or grids (or not enough fractals) then this is the place to adjust the frequency with which they appear. If the software was built with the fullscreen option, that can also be controlled from this menu. "Favourite" brings up a dialog which allows you to select a specific function type to always be used as the root node of any new functions. The function can be wrapped by some other random stuff, or unwrapped. See also the -X and -x command line options. - Help menu: Items to bring up documentation, and the usual "About" box (which includes the license). STATUS BAR ---------- An area on the status bar shows how many compute "tasks" are outstanding (or "Ready" when there are none). When two task totals are reported, the first is for the main grid and the second for any enlargements being computed. Each "task" is the recomputation of an image at some resolution. Tasks are prioritised by their number of pixels (small image implies higher priority). This is why, if the main grid is still recomputing, recalculations of enlargements will appear to freeze after they have reached a certain resolution, at least until other lower resolution tasks have completed. The status bar also provides some control over the "autocool" mechanism which reduces mutation strength with time. See the advanced usage section below. TIPS ==== - Don't start a session with any preconceived ideas about the kind of image you want to get out of it. You will be disappointed. - I get the best results when I click the image which most immediately catches my eye as they start appearing. If you stop to think about it too much then things seem to go downhill. - If you seem to be just getting the same old spirals and grids all the time, stop clicking on spirals and grids! (The same goes for random mush). - Don't get too hung up on using the warp and middle-mouse drag adjustments every iteration... use those tools for final polishing of your masterpiece. - You can quickly cycle through a lot of initial images (until you find one with real potential) by bashing on CTRL-R to repeatedly restart. - To add variety to an image's mutations, nudge it with a small middle-mouse drag. This introduces a top level transform, and therefore more parameters to be varied. - Enlargements take a long time to complete their final high-resolution rendering pass (especially with multisampling enabled). Most convenient practice seems to be to go away and leave them to complete, then come back and save them later. Continuing to click away on the main grid effectively starves them of CPU, unless the -E command-line option is used. ANIMATION ========= As of version 0.2.0 evolvotron contains some experimental support for generation of animations (although so far the results have been pretty disappointing IMHO, but it's still early days). NB THIS IS EVEN MORE COMPUTATIONALLY AND MEMORY INTENSIVE THAN THE STATIC IMAGE MODE. Simply supply a -f command line option and evolvotron will generate animated sequences with the specified number of frames. These will be displayed at the frame rate specified by the optional -s option (default 8). So "evolvotron -s 24" will generate 3 second long animations. Animations reverse direction at each end to avoid a sudden jump. If you save an animation as PPM or PNG, multiple files will be saved with .fnnnnnn (where nnnnnn is the zero-filled frame number) inserted in each filename before the filetype qualifier. For example, if you enter foo.ppm as the filename to save, files foo.f000000.ppm, foo.f000001.ppm... will be saved. If you have the ImageMagick tools you can convert these to an animated GIF playing at approx. 8 frames per second with: $ convert -delay 12 foo.f??????.ppm foo.gif ADVANCED USAGE ============== Evolvotron's idea of an image is a function which converts XYZ co-ordinates to an RGB colour (however we can only display a 2D plane for now so the input Z is fixed to zero, or varied with time when animating). The image functions are constructed from trees of function nodes. (In the mathematical expression 1+(2*x) the "+" and the "*" would be function nodes.) Evolvotron's functions tend to correspond to geometric or colour-space operations or anything else which can be applied to a 3D vector. By mutating the structure of the function tree (adding random branches, for example) and the values of the constant embedded within it, the image can be changed. The mutation parameters are under control from the dialogs accessible via the Settings menu, and the "autocool" mechanism exposed in the status bar also has some influence. There are two kinds of mutation: perturbations to the magnitude of constants, and structural mutations which re-arrange the function tree of an image. Four types of structural mutations are currently implemented: - replacement of a function branch by a new random stub (a "Glitch" mutation). - a random shuffle of a node's sub-nodes - insertion of random nodes between a node and it's sub-nodes - the substitution of a node with one of a different type, with sub-nodes unaffected where possible). The probability (per function node) of these mutations is controlled from spinboxes on the "Mutation Parameters" dialog (expressed as chances-in-a-hundred), as is the size of perturbations to constants. It is useful to think of the perturbations to constant parameters as being a thermal effect (hence the "heat" and "cool" buttons), while structural alterations are more drastic and are caused by high energy gamma rays or something (hence "irradiate" and "shield" buttons to adjust the probability of structural mutations). So why would you want to change the mutation parameters from the initial defaults ? Basically, if you're getting too much variation in spawned images (this tends to happen after many generations of images, by which time the function trees have grown quite large and therefore are experiencing a lot of mutations) then cool and/or shield. If all the images look too similar, heat and/or irradiate. The "autocool" mechanism (enabled from the statusbar or mutation parameters dialog) automatically reduces the strength of mutations from the base values with successive generations. The cooling can be cancelled by disabling autocooling or pressing the "Reheat" button to zero the number of generations counted for cooling. The effect of the cooling is a compound halving of the mutation strength after some number of generations (this number is the "half-life" controllable from the mutation parameters dialog). Note that if autocooling is enabled then eventually, after a number of iterations more than many multiples of the half-life has passes, spawned images will differ very little from their parents (hence the need for "reheat"). There is also a dialog accessible from "Functions..." on the "Settings" menu. This allows control over the relative proportions in which functions occur. There is a tab showing the relative weighting of all functions (log-2 scale: each tick halves the probability of the function occurring), and additional tabs for various classifications of function for quicker access. The "Randomize" button on each tab assigns random weightings and helps increase the uniqueness of your session. The "Functions" dialog also has a "Dilution" tab which allows the average function-tree branching ratio to be controlled (by changing the proportion of trivial zero-branch functions added): note that using a high branching ratio results in very complex images which will take a long time to compute, while reducing the ratio results in simple, boring images. 3 types of function node are considered fundamental: constant nodes (which return a constant), identity nodes (which return their position argument) and transform nodes (which transform their position argument by random parameters). On the "Dilution" tab of the "Functions" dialog there are two slider controls to affect things related to these: - "proportion constant" controls the proportion of diluting fundamental nodes which are constants. Changing this from its default value of 0.5 doesn't actually seem to have much effect. - "proportion transforms" sets the proportion of non-constant nodes diluting which are transforms (as opposed to identity nodes). The main effect of this is that images are less commonly obviously centred on the origin or aligned with the axes. I think this is a good thing, so the value is at 1.0 by default. OTHER EXECUTABLES ================= This release also builds some other command-line driven (non-GUI, non-interactive) utilities. Consult the man pages for full details. evolvotron_render reads a XML function description from its standard input and renders it to the file specified. evolvotron_mutate reads an XML function description from its standard input and outputs a mutated version. A command line option allows the "genesis" situation of creating a random function description with no input. EXAMPLES -------- Evolving and mutating on the command line: $ evolvotron_mutate -g | tee fn.xml | evolvotron_render /tmp/xxx.ppm ; display /tmp/xxx.ppm $ cat fn.xml | evolvotron_mutate | evolvotron_render -j -m 4 /tmp/xxx.ppm ; display /tmp/xxx.ppm Animating a function ani.xml saved from evolvotron in animation mode: $ cat ani.xml | evolvotron_render -f 100 -v -s 256 256 ani.ppm ; animate ani.f??????.ppm FUTURE DEVELOPMENTS =================== Please check the TODO file first before you send me suggestions! Please don't ask me to port evolvotron to proprietary platforms. You are of course Free under the terms of the GPL to do so yourself, but please read http://www.fefe.de/nowindows/ first. THANKS ====== To those who have contributed feedback, suggestions and patches: - Dmitry Kirsanov - Jonathan Melhuish - Karl Robillard - Linc Davis - Paolo Greppi - Marcin Wojtczuk - Michael Sterrett - Massimiliano Guastafierro - Goetz Waschk - Forrest Walter - "chr_bl" at web.de And to the anonymous Linspire reviewer who perhaps came up with the best summary of evolvotron yet: "Fascinating. Utterly pointless, but fascinating." The friezegroups wouldn't have been possible without http://michaelshepperd.tripod.com/resources/groups.html Thanks to www.di.fm, www.somafm.com and Trance4Ever for music to code to. Thanks especially to a SIGGRAPH conference panel many years ago (likely including Karl Sims, the pioneer in this area) who first got me interested in this stuff. WHY ? ===== I have always admired those who have the skill to wield a pen or paintbrush and fill a sheet of paper or a canvas with some striking image from their imagination. Unfortunately I lack the patience to learn such skills, and probably the necessary manual dexterity and imagination too. Evolvotron, and several predecessors developed on and off over a decade since I first came across the idea, are an attempt to compensate for this using the skills I do have i.e some mathematical sensibility and the ability to write working code (well, sometimes). If you like an image it produces, then as far as I'm concerned that's as satisfying a result as if you liked something I'd drawn myself. Tim Day evolvotron-0.8.3/TODO0000644000175000017500000003547515230700302013101 0ustar karlkarlProximity to one end or the other of this list does not necessarily imply it will be done sooner or later than other items! Infrastructure -------------- - Update mkdeb as per fracplanet's debhelper experiment Conventional Mode ---------------- - Commandline option/control for grid spacing. - Migrate to a stock threading/thread pool/futures lib. - Just make "fullscreen mode support" be the default (and remove text in USAGE). - Link on webpage to gallery http://gigrafx.110mb.com/evolvotron/index.html - ...also flickr stuff (xargs?) - Mouse manipulations: frame rate should be clamped to allow some time to produce a nice image - At least split out evolvotron_main_history.cpp, even if the class remains nested in .h - Smaller fragments for big enlargements; seeing unused processors. - More feedback on when enlargements are ready for saving (have split tasks count now... need more ? yes) - Triangles quantization mode (c.f hexes, pixels and voxels) - Linear and cubic interpolation for pixel and voxel mode quantizer - Enlargement menu: submenus for square, 4:3, 8:5, 16:9. 16x10. 5:4 SXGA 1024x1024 is a bit of an oddball. And name them, see http://en.wikipedia.org/wiki/Computer_display_standard - Friezegroups: Cut taken out for 0.5.0 release. Want cut and blend for those that support it. Blend should use two functions in some cases. Can't see how to blend cuts; needs something more like old warp approach. - Work out how to add warping/blending to the (frieze) symmetry groups so they dont look so "cut". Hop - Basic, Blend and Cut done. Cut needs attn to fit in with spinhop. Jump - Basic, Blend and Cut done. (Is just Hop with y=0 reflection). Cut needs attn to fit in with spinhop. Sidle - Basic. Can't be blended or cut as there are only reflection lines. (Could be blended, but doesn't hide much). Spinjump - Basic. No blend or cut as there are only reflection lines. (Is just Sidle with y=0 reflection). (Again, could blend but not much point). Spinhop - Basic. Blend done. Cut done. Spinsidle - todo Step - todo - Not entirely convinced by separate thread pool for enlargements. On the other hand, do need some mechanism to progress enlargements while working on main grid. - Add functions for the 17 "wallpaper" symmetry groups. ref: http://www.scienceu.com/geometry/articles/tiling/wallpaper.html Wikipedia http://en.wikipedia.org/wiki/Wallpaper_group is good. Presumably there are 3D versions too. See also http://www.mi.sanu.ac.yu/vismath/ana/ana5.htm - The function properties dialog could construct a QListView instead of just displaying the XML. But then you'd want full editing capabilities too (and why not?) - When mutating parameters, have a chance of a "special" reset to "interesting" values, and maybe even patterns of values. - Debian transitioning Apps to Applications (post Etch) see bug #361418 - GPLv3 ? Don't understand what else needs to be (e.g Qt3 etc) - Maybe icon setting could do with some more attention; probably there are more things which should set it (e.g respawn coloured) and loading could set a flag defering icon setting until that view is ready. - MutatableImageComputer::push_todo could handle defer a bit better. Actually, complete overhaul of queue/computer kill/defer/abort would be better. Computers should check priority on head of queue periodically and switch if there's something better to work on. - Move InstanceCounted out of useful.h (and #include with it) - Changing lock state triggers a redisplay. Lock state would be better associated with displays than MutatableImages, but the history archive doesn't support anything but changing images; needs additional abstraction of general notion of change of a display's state. Can live with this for now. - Use reStructuredText instead of own python txt->html converter. (Then use fracplanet htm->qml converter). - Mode (genesis mode?) which traverses grid, creating a new image every few seconds. First click stops mode. Useful for getting started. - Transform<->vector should output basis vectors first, translation last. - is_constant not enough to avoid boring images. Need to actually check amount of variation. - Get rid of heat/cool etc buttons cluttering up status bar and just have (new) autocool tick, and reheat button ? - Functions with similar names probably do much the same thing so reduce their weighting to avoid them dominating. - FriezeGroups should add an extra parameter for repeat length rather than using 1 all the time. Likewise for spheres. - Move LoadHandler out of mutatable image. - QFileDialog seems to support previewing; enable it for file contents previewing in file dialog. - Internationalization. Make it as easy as possible for contributors to submit new languages. - Ability to set animation mode from GUI (property of an image function ?) - Ability to set spheremap mode from GUI (property of an image function ?) - Keyboard shortcuts for all of reset/restart/remix - Display mutation parameters permanently on status bar. - Scripts entry on context menu; pipes XML to things in ~/.evolvotron/scripts directory - Make middle-mose-button adjustments work sensibly with -spheremap - Option for save function to also generate thumbnail at the same time ? (Maybe not with previewing) - Look into mime-type registration and auto-thumbnailing in nautilus, KDE etc (pipe through evolvotron_render) - Browse window to show thumbnails for all .xml files in a directory. - DialogFunctions and DialogMutationParameters don't notice when the other dialog modifies MutationParameters. Fortunately this doesn't matter because they (will) control completely disjoint aspects of it. Could do with proper model update propagation/validation if things get any more complex though.. - linz and -spheremap need rationalising before we add more projections - Ability to change linz and spheremap attributes on properties menu. - Supplement spheremaps with... what ? Cubemaps ? Volume output ? - Heat/Cool etc buttons in status bar not very interesting. Replace with autocool controls, or have them actually fire off a respawn from the last spawned image; would get more of an idea of how much effect there is then. - MutationParameters should be held by EvolvotronMain with pointers passed to dialogs. - Different projections for evolvotron_render, maybe main app (e.g spheremaps, cubemaps, volumes). - Display properties dialog should have small copy of image - "Evolvotron corpus"; publish mode & viewer app to see other users' creations How ? Jabber conference! (It's all XML). - Quick 'n easy way of pushing to Flickr ? - Proper dependency and generation by qmake of libevolvotron/usage_text.h - Rationalise configure options: fs/nofs (doc/nodoc?) - -h & --help option. Print version and functions supported. - man pages ? Knock off something simple. - Window ordering (and whether fullscreen) should be an input to compute priority. Need to be able to change priorities once tasks are in queue, and re-order queue. - Give some sort of control over pixel aspect ratio. A nice circular image in a square display on the screen is squished when rendered to a rectangular image. Best solution probably to offer cropped modes e.g "640x480 from 640x640". Alternative solution would be 4:3 mode for the whole app where the evaluation range is changed. Harder to explain though. - [Local] Clean up evolvotron_admin/evolvotron_gallery - Check qmake can be found by configure. Check $(QTDIR)/bin first... RH seem to be unusual in copying it to /usr/bin - evolvotron_render default output (or with filename "-") should be to stdout. (The problem is that Qt's image writing libs only support file output). Could create a /tmp file behind the scenes, or write something simple like PPM. - File save dialogs should remember which directory they were last accessing. (Maybe a Qt problem) - Replace FunctionNode::stub() with FunctionRegistry based code - Create registry of all function node types (done) - Use to bring up a panel for setting relative frequencies (check for exploding branching ratios) - Button to spawn images with a specific type of top level node (would be great for testing) - Allow iterative/allow fractal would then become convenience buttons for quick-setting a whole group of frequencies - Classification scheme for function types (basic, smooth, chooser, complex, expensive). - More types of mutation - Substitute a node for a different type, retaining it's settings (expand/cull as necessary) - Nodes near top level should have more chance of mutation ? - evolvotron_mutate standalone exe should provide more control (heat/cool/irradiate/shield options, recolour/warp options, animation options). - Combining/breeding image pairs. Use drag-and-drop Either: Create a new top level node with 2 or more args and add the parents to it. Create a new random stub and insert the parents at random points. Insert one image at a random point into the other. Concatenate (function compose) the 2 images (probably not v. interesting) Need to prune too to keep size under control. - Get rid of silly xyz and matrix dependence on general tuples and templates. (Can be well optimised, but only with heavyweight compile options.) - Profile & optimise. - Spawn recoloured could be linear, quadratic (or generalised?) versions. - Undo needs to save more state to work properly (e.g state for respawn) Make history know about "MutatableImageHolders" rather than Displays, and have last spawned be held in such an object too. - Have a function type which can suck in random images from directories of images (specified by environmental variable ?) Filename would need to be retained in node and XML for reproducibility. - Optimise drag: just recompute new area (needs image subregions for tasks). - Option (default on) to automatitcally respawn boring constant images as soon as they've been computed to a certain resolution. - Web front end to commandline tools: an evolvotron web-server. - Command line option for border around images... use space to indicate locked status. - Maybe add "view" menu: like warp but just applying to current image (like drag) (would need explicit control over amounts: maybe drag approach better ?). - Last method used should point to an object encapsulating the behaviour (so warp spawn method can encapsulate a transform factory). Needed for breeding behaviour (so can keep 2 last images). - Undo needs to restore _last_spawned too (but do above first and keep hisory of spawn methods). - Command line option to enable/disable fractal and iterative types. - "Unlock all" on edit menu - Reset & Restart: combine and bring up modal "are you sure" dialog box which can also contain check boxes for what to reset: mutation parameters function freqencies (when implemented) locked displays - Quit should bring up "are you sure" dialog. - Option to increase number of iterations of certain types of iterative node in an image (i.e "accuracy") (probably makes sense for Mandelbrot/Julia or a sampling blur where it just increases the detail, but less useful for repeated function mapping). - "Move all locked to start" on edit menu (or move them to a "safe area", or save them in reloadable form). - Save whole grid as a single image (from File menu). - Save whole grid to an XML file. - Context menu option to bring up info about an image (in particular number of nodes and max depth) - Reference counting for images (far too much deepcloning currently; e.g to tasks and history). But if it ain't broken don't fix it. - Use hourglass cursor over displays which haven't got final high resolution yet ? (Really need combined hourglass/pointer cursor but Qt doesn't have one built in). - Computing zero co-ordinate sometimes gives unusual output (black lines across images). Avoid by jittering co-ordinate (would break up jaggies), or just avoid exact zero ? - Why stop at screen resolution ? Antialiasing by supersampling. - Separate tool (?) to evolve images towards a given image. How close would it get and how quickly ? Would the process of getting there be interesting (e.g as an animation) ? - Compute farms on multiple remote machines. - Menu options to add/remove rows/columns from display grid - Autocool of mutation parameters (probably shouldn't be on by default; control from command line). - Heat/cool etc should act in proportion to current values (probably wanted for autocool). - Evolve other things e.g parameters of celluar automata/reaction diffusion equations/iterated function systems. - Rationalise MutatableImageNode::stub so more work is done by Node constructors (just pass in a MutationParameters). - Avoid misleading moire patterns by jittering samples - No low-res images option for when using remotely via X11 over slow link (they take longer to display than compute) (running over compressed ssh helps a lot though). - Evolvotron_mutate should support -x/-X options. - Think of more functions: Blending counterparts for switching/choosing functions. Streaking version of windmill functions. Generalised rotations Square "Bhuddist mandala" versions of kaleidascope Concentric rings Iterative function generating a list of point co-ordinates... then test for blobs or make paths (would be more efficient with a cached/precomputed element to functions). - Vector/SVG mode, using Qt SVG creation/rendering support - User defined functions using Qt's javascript engine - (Re)consider options for root node colour space transformations. - Builtin XML editor, or better still treeview of structure with all parameters tweakable by slider, wheel, data-entry etc, and nodes changeable by pull-down maybe. Animation --------- - Could avoid bitBlt when reassembling fragmentary animation renders by fragmenting on frame instead of by screen area. Don't think this is a big enough deal (saves a bit of copying in a little used feature) to be worth bothering with. - More warp types (rotate time into space etc) - More control over animation (frames & framerate) from edit/options menu (or on a display by display basis ? Then "big" images could have more frames and higher framerates) - Ability to degrade temporal resolution with spatial resolution at low-res render levels - Support animation in evolvotron_render - Sync animation to xmms beat somehow ? - Option to sweep z sinusoidally or linearly - Option to bounce or cycle z - Make frames, frame-rate, sine vs. linear, loop vs. bounce properties of the image. Extras ------ - evolvotron_match hasn't been seen to do much but converge towards general overall color of target. Try matching in edge-detected space or something ? Rejected -------- - Add #ifdef INSTANTIATE_FN (or move to .cpp) around evaluate methods implemented in .h ? Only really justifiable for fn .h included in multiple places (not that many of them; NB function registration doesn't see these). Not worth bothering with. evolvotron-0.8.3/README.md0000644000175000017500000001136115230700302013654 0ustar karlkarlEvolvotron ========== Evolvotron is interactive "generative art" software to evolve images/textures/patterns through an iterative process of random mutation and user-selection driven evolution. If you like lava-lamps, and still think the Mandelbrot set is cool, this could be the software for you. It uses C++, Boost, and the Qt GUI toolkit (v5.5 or later). It's multithreaded (using Qt's threading API). Home page: http://www.bottlenose.net/share/evolvotron This file describes how to build evolvotron. See the USAGE file for details of what the built executable can do. If you manage to make practical use of evolvotron, especially if evolvotron derived imagery makes it into print or other mass media, I'd love to hear about it: please email! Have fun Tim ![Screenshot](https://wickedsmoke.github.io/image/evolvotron.jpg) LICENSE ------- 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. [The license should be in the LICENSE file in the same directory as this README] BUILDING -------- There's no reason it shouldn't work on any platform with a correctly set up qmake. You do NOT need to be root (there is no install stage). In the top level directory, you can either do qmake "VERSION_NUMBER=x.x.x" main.pro make or just have both done for you by doing ./BUILD.sh which will pick up the VERSION_NUMBER from the file VERSION in this directory. Make will recurse into and build the libfunction & libevolvotron directories (which is 99% of the work) and some additional subdirectories with executables. Among other things, this will give you an `evolvotron` executable which you can run immediately with ./evolvotron/evolvotron and/or copy where you like (there are no shared libs or "resource files" needing additional attention). See the `USAGE` file (or in-app manual) for instructions. The author mainly tracks Debian stable. ### Debugging builds Many build failures are simply because the necessary Qt build tools aren't in your path: which qmake which moc should both find something. If you have gcc/c++ compile problems problems: If you have to change anything, the chances are it should be changed in `common.pro`. Remember that any Makefiles you can see are generated by qmake from .pro files and therefore hacking on the Makefiles is generally a fruitless exercise. Some source releases have had problems with other versions of gcc than the ones I test on. A COMPLETE record of a failed build would be appreciated (including the initial display of the gcc version). If you can fix it, then patches would be even better! INSTALL ------- The evolvotron sources don't try to provide an installer. The assumption is that packagers will have a better idea of where files should be copied to on their systems, and the tools to do it. Doing `make install` will recursively descend into the various build directories, but does nothing in each one. The things you're likely to want to install are (in order of interest): The main executable and man page: ./evolvotron/evolvotron ./man/man1/evolvotron.1 User documentation (standalone version of the builtin manual): USAGE An HTML version of the above: ./evolvotron.html Command-line driven tools and their man pages: ./evolvotron_render/evolvotron_render ./man/man1/evolvotron_render.1 ./evolvotron_mutate/evolvotron_mutate ./man/man1/evolvotron_mutate.1 There are NO extra supporting files built (e.g shared libraries, config files, "resource" files) which need to be in special places for the software to work. PACKAGING --------- There are a few things which might be useful to packagers: mkdeb - script to build .deb files (using the strangely unpopular "yada", and pbuilder). This is used to build the .debs put up on sourceforge, but the "official" Debian ones (and Ubuntu derivatives) are more conventionally packaged by Gurkan Sengun. Yada is obsoleted as of Debian's "Wheezy" release however. evolvotron.spec - For building RPM packages. CODE DOCUMENTATION ------------------ If you have doxygen (and graphviz too) and want to build the source code documentation, execute `doxygen` at the top level. The documentation then appears in `./doc/html/`. evolvotron-0.8.3/NEWS0000644000175000017500000003040515230700302013074 0ustar karlkarlRelease 0.8.3 (Jul 24, 2026): - Support C++17. Release 0.8.2 (Apr 23, 2024): - Support Qt 6. - Add extras/evolvotron_complexity script. Release 0.8.1 (Feb 25, 2023): - Add application icons and Linux .desktop file. - Remove deprecated code (binary_function & QXmlSimpleReader). - Minor changes to built-in documentation. - Tweak dialog layouts a bit. Release 0.8.0: - Show lock icon on images and allow lock toggling with left click. - Allow zooming with mouse wheel. - Improve enlarged image display. - Save window size, function path & image path in settings. - Use standard shortcuts for some actions. - Remove some boost dependencies. - Get Windows build working with MinGW. - Update build to work on Debian Jessie. Release 0.7.1: - Uses `CONFIG += ordered` in `main.pro`; enables parallelised make. - Fold in typos fixed by Debian downstream. - tarball on Sourceforge files. Release 0.7.0: - Got to compile vs Qt5.9.1 on Debian Stretch & Jessie; preparing for Qt5-only on Buster. - Get rid of precompiled header use (more trouble than it's worth these days). - Upgrade std::auto_ptr use to std::unique_ptr - cleans up compiler's deprecated warning spew. From release 0.6.3: - Version to 0.6.4 From release 0.6.2: - Version to 0.6.3 - Files derived from USAGE (evolvotron.html and usage_text.h) are now under svn control and no longer need to be generated as part of the build of a fresh checkout. - Migrated to new SourceForge platform. Needed: svn switch --relocate https://evolvotron.svn.sourceforge.net/svnroot/evolvotron "svn+ssh://timday@svn.code.sf.net/p/evolvotron/code/" From release 0.6.1: - Version to 0.6.2 - CHANGES renamed to NEWS - License boilerplate managed using "headache" - Add some "tartan" inspired functions. - Add pixel/voxel/hex grid quantizing functions. - Port command line options to boost::program_options, rationalize commandline options. - Fix to evolvotron_mutate from Pedro Gimeno. - Update mkdeb script to work on squeeze - Functions to be loaded on startup can be specified on the commandline. - Add option to shuffle startup functions. From release 0.6.0: - Version to 0.6.1 - Fix bug in saved functions: quotes missing around version attribute From release 0.5.1: - Version to 0.6.0 - Switch to Qt4. - (Qt4 related) keyboard shortcuts rationalized many removed, ctrl-modifiers dropped - (Qt4 related) image displays now have a frame around them - (Qt4 related) Remove non-standard Qt animated PNG support - evolvotron_match removed - Platform specific code (e.g number of processors identification) isolated in libevolvotron/platform_specific.[h|cpp] and selected by PLATFORM_LINUX or PLATFORM_BSD (Fink Qt's __DARWIN_X11__ also detected and used to select PLATFORM_BSD). - Repository migrated to svn From release 0.5.0: - Version to 0.5.1 - Replace not often used frontside heating/cooling buttons with autocooling mechanism. - Separate tabs for info & license on "About" dialog. - Better formatting of function properties dialog, and also shows XML function tree. - Dialog with rendering controls - Multisampling (antialiasing) options - -a/-j/-s command line options for autocool/jitter/multisample - evolvotron_render adds -j/-s to control jitter & multisampling - Option (-E) of separate thread pool (with different nices: -n/-N) for enlargements. Task totals for each reported separately. - Enlargement and solo renderings are fragmented into multiple smaller jobs to better utilize multiprocessor systems. - Generally better use of ref-counted QImage and QPixmap. - Middle-mouse drag adjustments flicker less. From release 0.4.0: - Version to 0.5.0 - Lists of functions in alphabetic order. - New FunctionTop always at top level. - New functions: Frieze groups. - Constantness of functions more conservative (less overrides) and hopefully less buggy. - Final colour space transform range more constrained to keep colours sane. - More sensible mutation of top level spatial transform (less arbitrary shearing). - Note that above changes mean old saved functions will appear different. - New mutation parameter: probability of a function's parameters being reset. - Code clean up: - More std::auto_ptr, boost::shared_ptr, boost::ptr_vector. Code is now delete free. - Get rid of hacked static function registration; uses auto-generated register_all_functions. - Compute threads use QWaitCondition, not polling. - Default number of threads is number of processors. - Compute threads run at lower priority. - -n command line option to control compute thread priority. (NB assumes Linux NPTL's non-Posix compliant behaviour of threads NOT sharing a common nice value; see "man pthreads" on Linux.) - About dialog displays number of threads. - Use precompiled headers (build time 2m45s down to 1m45s). - code_review script - Set an icon on various dialogs and main frame. - Add -D (function debug) massively weighting in favour of FunctionNoiseOneChannel. Useful with -x/-X. - Believed to fix Debian bug #436231 and gentoo #144160 - MutatableImage has serial number (fix problems caused by pointer value being wrongly used as equivalent) From release 0.3.1: - Version to 0.4.0 - Lock state moved to mutatable image so is stored in undo history - Mandelbrot & Julia set only in x,y plane. Julia set uses fixed parameters. - Add Juliabrot. - Fix "Randomize" button on "All" functions tab. - "Favourite" function dialog provides access to -x/-X command-line functionality - Undo after reset works better - Fix broken FunctionGradient. Replace with GradientOfMagnitude, DivergenceOfMagnitude, Divergence, Curl - Migrate float->double via typedef real - Always builds with fullscreen option. From release 0.3.0: - Version to 0.3.1 - Fix for gcc 3.4 - ./configure made (slightly) more robust From release 0.2.3: - Version to 0.3.0 - Get rid of troublesome system call to ../VERSION in common.pro and pass settings from configure script instead - Add not-very-useful .qt-mng image file output format - Add function stats to Properties dialog - Add function simplification (more useful for debugging than anything) - Don't use True and False in doc-building python script (seems to be quite new thing, not in 2.1.x ?). Use 0 and 1 instead. - Internal changes - Add pkg/debian .deb builder script (still under development) - Fix buggy Y rotation matrix - Eliminate template-tastic Tuple and Matrix classes. Fix XYZ and Transform to not require them. - evolvotron_mutate - -g option more likely to generate insteresting functions - -linz and -spheremap options where appropriate - evolvotron_match utility. - New dialog for function weightings (not fully implemented) From release 0.2.2: - Version to 0.2.3 - Break out USAGE file from README - Add text_to_markup.py script to prettify USAGE file, used from configure - Add quick reference and user manual accessible from help menu From release 0.2.1: - Version to 0.2.2 - CPU type an option to ./configure (p3,p4,xp supported) - Build option for fullscreen & menu-hiding modes (from keyboard or command-line) - Fullscreen mode for "Big" image displays - Change default grid to 6x5 (would sooner have fat than thin images) From release 0.2.0: - Bump version to 0.2.1 - Display (not compute) priority to higher resolution images (saves time enlarging low res images unnecessarily) - Blank images on replacement (above change makes this more necessary) - Round-robin dispatch of done tasks to displays means redisplay more balanced. - -x and -X command line options to specify specifc top level function types. - FunctionKaleidoscope*, FunctionWindmill*, FunctionSeparateZ added. - More iterative functions also added: FunctionStreak Function*Ring - Added -f option to evolvotron_render - Internals: function framework changed (avoids FunctionNodeUsing::evaluate wrapper), speed improvement ? - Internals: Type of top-level node can mutate, MutatableImage more sane. - "Undo" keyboard accelerator works - Per-image display "Properties" dialog added (placeholder) From release 0.1.4: - Bump version to 0.2.0 - Filenames converted to/from QString using Qt's "local8Bit" codec. - -f option specifies number of frames (default 1, which is the non-animated behaviour of previous versions) - -r option specifies framerate of full-resolution animation (default 8, about the minimum to look smooth) - Animations save to multiple files From release 0.1.3: - Bump version to 0.1.4 - Function tree growth rate restored to pre-0.1.2 rates - Both multiscale noise types counted as iterative as originally intended. - "Substitute" mutation type added. From release 0.1.2: - Bump version to 0.1.3 - Build lib and separate executables. Use qmake "subdirs" at top level, move code into subdirs. - Add evolvotron_render executable. - Add evolvotron_mutate executable. - Better Args class. - Fix bug in FunctionAverageSamples - Add noise class - Add more functions. - Use better random number generator (MT) - Changes to initial setup probabilities, add chance of identity nodes front and back From release 0.1.1: - Bump version to 0.1.2. This is purely a bug-fix release. - Gentoo compile bug fix (Karl Robillard) - Disable implicit QString conversion (use explicit latin1() method). - Workround "C++ static initializer fiasco" by moving problem static members into instance-get methods. From release 0.1.0: - Bump version to 0.1.1 - Grid size now defaults to 7x5 - More functions! From release 0.0.5: - Bump version to 0.1.0 - Fix nasty bug in computers where a task could be delivered and deleted while the compute thread was still setting state in it (timing related so it never happened with ccmalloc and valgrind). - Massive internal changes necessary for file save/load (also makes adding functions easier) - Save/load individual functions to XML - configure checks QTDIR defined (biggest cause of build problems) From release 0.0.4 - Bump version to 0.0.5 - configure script #!/bin/* changed to sh from csh - Release tar files now unpack to a ./evolvotron directory - More "Big" size options - Big image can create big images - Big image's initial window size decided by Qt - Spawn warped offers more specific controls (zoom/pan/rotate) - Middle mouse button does stuff (pan/zoom/rotate/shear) - Undo menu entry describes type of action which will be undone - Closing a big image cleans up undo history appropriately - Bug with assumed EvolotronMain/MutableImageDisplay destructor order fixed. From release 0.0.3: - Bump version to 0.0.4 - More interesting start up functions - More functions (e.g rotation and spirals, geometric inverse, iterated fns, fractals...) - Controls to enable/disable expensive/ugly iterative and fractal functions (default off). - Fix dumb bug in xy range of image (makes everything generally behave a lot better; most noticeable with warp) - "Identity supression" control which helps eliminate/reduces obvious origin centering. - "Proportion constant" control (doesn't seem to have that much effect). - Separate reset/restart functionality (reset also resets mutation parameters). - Move Cool/Shield buttons to be adjacent (commonly used together). - "is_constant" query method used to eliminate boring constant images. - x&y co-ordinate alignment fixed (not something users would notice) - Spawn warped made less messy: just generates translate/scale/rotate... no shearing. - Reset clears locks / restart doesn't - Gratuitously templatized tuple/matrix class added to help geometric transforms. - Add "configure" script 'cos thats how lots of other apps do it. Apparently. From release 0.0.2: - Bump version to 0.0.3 - Add command line arg control of grid size and threads, don't override -geometry - GUI control of mutation parameters - "Respawn" regenerates a single display area using spawn/recolour/warp as appropriate. - "Cancel" in file save dialog obeyed. - "Insert" mutation type. - "Undo" functionality. From release 0.0.1: - Bump version to 0.0.2 - Switch to QMainWindow base in anticipation of toolbar. - Save as PPM or PNG - Scrollable fixed-size image "Big" windows. - Improvements to app response under load. From release 0.0.0: - Bump version to 0.0.1 - Add volatile to inter-thread communication flags - Added a few more image node function types - Add "spawn_recoloured" - Add "spawn_warped" evolvotron-0.8.3/LICENSE0000644000175000017500000004313115230700302013402 0ustar karlkarl GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. evolvotron-0.8.3/Doxyfile0000644000175000017500000035507615230700302014121 0ustar karlkarl# Doxyfile 1.9.5 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. # # All text after a single hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). # # Note: # # Use doxygen to compare the used configuration file with the template # configuration file: # doxygen -x [configFile] # Use doxygen to compare the used configuration file with the template # configuration file without replacing the environment variables or CMake type # replacement variables: # doxygen -x_noenv [configFile] #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the configuration # file that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # https://www.gnu.org/software/libiconv/ for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the # project for which the documentation is generated. This name is used in the # title of most generated pages and in a few other places. # The default value is: My Project. PROJECT_NAME = evolvotron # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. OUTPUT_DIRECTORY = doc # If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 # sub-directories (in 2 levels) under the output directory of each output format # and will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes # performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to # control the number of sub-directories. # The default value is: NO. CREATE_SUBDIRS = NO # Controls the number of sub-directories that will be created when # CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every # level increment doubles the number of directories, resulting in 4096 # directories at level 8 which is the default and also the maximum value. The # sub-directories are organized in 2 levels, the first level always has a fixed # numer of 16 directories. # Minimum value: 0, maximum value: 8, default value: 8. # This tag requires that the tag CREATE_SUBDIRS is set to YES. CREATE_SUBDIRS_LEVEL = 8 # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode # U+3044. # The default value is: NO. ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, # Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English # (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, # Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with # English messages), Korean, Korean-en (Korean with English messages), Latvian, # Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, # Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, # Swedish, Turkish, Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found # as the leading text of the brief description, will be stripped from the text # and the result, after processing the whole list, is used as the annotated # text. Otherwise, the brief description is used as-is. If left blank, the # following values are used ($name is automatically replaced with the name of # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. # The default value is: NO. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. FULL_PATH_NAMES = NO # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the path to # strip. # # Note that you can specify absolute paths here, but also relative paths, which # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which # header file to include in order to use a class. If left blank only the name of # the header file containing the class definition is used. Otherwise one should # specify the list of include paths that are normally passed to the compiler # using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief # description.) # The default value is: NO. JAVADOC_AUTOBRIEF = YES # If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line # such as # /*************** # as being the beginning of a Javadoc-style comment "banner". If set to NO, the # Javadoc-style will behave just like regular comments and it will not be # interpreted by doxygen. # The default value is: NO. JAVADOC_BANNER = NO # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus # requiring an explicit \brief command for a brief description.) # The default value is: NO. QT_AUTOBRIEF = YES # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this # tag to YES if you prefer the old behavior instead. # # Note that setting this tag to YES also means that rational rose comments are # not recognized any more. # The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO # By default Python docstrings are displayed as preformatted text and doxygen's # special commands cannot be used. By setting PYTHON_DOCSTRING to NO the # doxygen's special commands can be used and the contents of the docstring # documentation blocks is shown as doxygen documentation. # The default value is: YES. PYTHON_DOCSTRING = YES # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new # page for each member. If set to NO, the documentation of a member will be part # of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: # name=value # For example adding # "sideeffect=@par Side Effects:^^" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". Note that you cannot put \n's in the value part of an alias # to insert newlines (in the resulting output). You can put ^^ in the value part # of an alias to insert a newline as if a physical newline was in the original # file. When you need a literal { or } or , in the value part of an alias you # have to escape them by means of a backslash (\), this can lead to conflicts # with the commands \{ and \} for these it is advised to use the version @{ and # @} or use a double escape (\\{ and \\}) ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all # members will be omitted, etc. # The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored # for that language. For instance, namespaces will be presented as packages, # qualified scopes will look different, etc. # The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice # sources only. Doxygen will then generate output that is more tailored for that # language. For instance, namespaces will be presented as modules, types will be # separated into more groups, etc. # The default value is: NO. OPTIMIZE_OUTPUT_SLICE = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, JavaScript, # Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, # VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: # FortranFree, unknown formatted Fortran: Fortran. In the later case the parser # tries to guess whether the code is fixed or free formatted code, this is the # default for Fortran type files). For instance to make doxygen treat .inc files # as Fortran files (default is PHP), and .f files as C (default is Fortran), # use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. When specifying no_extension you should add # * to the FILE_PATTERNS. # # Note see also the list of default file extension mappings. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See https://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up # to that level are automatically included in the table of contents, even if # they do not have an id attribute. # Note: This feature currently applies only to Markdown headings. # Minimum value: 0, maximum value: 99, default value: 5. # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. TOC_INCLUDE_HEADINGS = 5 # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or # globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); # versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make # doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = YES # If one adds a struct or class to a group and this option is enabled, then also # any nested class or struct is added to the same group. By default this option # is disabled and one has to add nested compounds explicitly via \ingroup. # The default value is: NO. GROUP_NESTED_COMPOUNDS = NO # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent # subgrouping. Alternatively, this can be done per class using the # \nosubgrouping command. # The default value is: YES. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) # instead of on a separate page (for HTML and Man pages) or section (for LaTeX # and RTF). # # Note that this feature does not work in combination with # SEPARATE_MEMBER_PAGES. # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and # Man pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small # doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 # symbols. At the end of a run doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 # The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use # during processing. When set to 0 doxygen will based this on the number of # cores available in the system. You can set it explicitly to a value larger # than 0 to get more control over the balance between CPU load and processing # speed. At this moment only the input processing can be done using multiple # threads. Since this is still an experimental feature the default is set to 1, # which effectively disables parallel processing. Please report any issues you # encounter. Generating dot graphs in parallel is controlled by the # DOT_NUM_THREADS setting. # Minimum value: 0, maximum value: 32, default value: 1. NUM_PROC_THREADS = 1 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. # Note: This will also disable the warnings about undocumented members that are # normally produced when WARNINGS is set to YES. # The default value is: NO. EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = YES # If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual # methods of a class will be included in the documentation. # The default value is: NO. EXTRACT_PRIV_VIRTUAL = NO # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES, all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined # locally in source files will be included in the documentation. If set to NO, # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are # included in the documentation. If set to NO, only methods in the interface are # included. # The default value is: NO. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base name of # the file that contains the anonymous namespace. By default anonymous namespace # are hidden. # The default value is: NO. EXTRACT_ANON_NSPACES = NO # If this flag is set to YES, the name of an unnamed parameter in a declaration # will be determined by the corresponding definition. By default unnamed # parameters remain unnamed in the output. # The default value is: YES. RESOLVE_UNNAMED_PARAMS = YES # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO, these classes will be included in the various overviews. This option # has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # declarations. If set to NO, these declarations will be included in the # documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO, these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. INTERNAL_DOCS = NO # With the correct setting of option CASE_SENSE_NAMES doxygen will better be # able to match the capabilities of the underlying filesystem. In case the # filesystem is case sensitive (i.e. it supports files in the same directory # whose names only differ in casing), the option must be set to YES to properly # deal with such files in case they appear in the input. For filesystems that # are not case sensitive the option should be set to NO to properly deal with # output files written for symbols that only differ in casing, such as for two # classes, one named CLASS and the other named Class, and to also support # references to files without having to specify the exact matching casing. On # Windows (including Cygwin) and MacOS, users should typically set this option # to NO, whereas on Linux or other Unix flavors it should typically be set to # YES. # Possible values are: SYSTEM, NO and YES. # The default value is: SYSTEM. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES, the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = NO # If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will # append additional text to a page's title, such as Class Reference. If set to # YES the compound reference will be hidden. # The default value is: NO. HIDE_COMPOUND_REFERENCE= NO # If the SHOW_HEADERFILE tag is set to YES then the documentation for a class # will show which file needs to be included to use the class. # The default value is: YES. SHOW_HEADERFILE = YES # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = YES # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader # which file to include in order to use the member. # The default value is: NO. SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will # be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the alphabetical # list. # The default value is: NO. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo # list. This list is created by putting \todo commands in the documentation. # The default value is: YES. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test # list. This list is created by putting \test commands in the documentation. # The default value is: YES. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if ... \endif and \cond # ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the # documentation. If the initializer consists of more lines than specified here # it will be hidden. Use a value of 0 to hide initializers completely. The # appearance of the value of individual variables and macros / defines can be # controlled using \showinitializer or \hideinitializer command in the # documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # the bottom of the documentation of classes and structs. If set to YES, the # list will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command command input-file, where command is the value of the # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. See also section "Changing the # layout of pages" for information. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool # to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to # standard output by doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error (stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. WARNINGS = YES # If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as documenting some parameters in # a documented function twice, or documenting parameters that don't exist or # using markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete # function parameter documentation. If set to NO, doxygen will accept that some # parameters have no documentation without warning. # The default value is: YES. WARN_IF_INCOMPLETE_DOC = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO, doxygen will only warn about wrong parameter # documentation, but not about the absence of documentation. If EXTRACT_ALL is # set to YES then this flag will automatically be disabled. See also # WARN_IF_INCOMPLETE_DOC # The default value is: NO. WARN_NO_PARAMDOC = NO # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when # a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS # then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but # at the end of the doxygen process doxygen will return with a non-zero status. # Possible values are: NO, YES and FAIL_ON_WARNINGS. # The default value is: NO. WARN_AS_ERROR = NO # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) # See also: WARN_LINE_FORMAT # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" # In the $text part of the WARN_FORMAT command it is possible that a reference # to a more specific place is given. To make it easier to jump to this place # (outside of doxygen) the user can define a custom "cut" / "paste" string. # Example: # WARN_LINE_FORMAT = "'vi $file +$line'" # See also: WARN_FORMAT # The default value is: at line $line of file $file. WARN_LINE_FORMAT = "at line $line of file $file" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). In case the file specified cannot be opened for writing the # warning and error messages are written to standard error. When as file - is # specified the warning and error messages are written to standard output # (stdout). WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. INPUT = # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: # https://www.gnu.org/software/libiconv/) for the list of possible encodings. # See also: INPUT_FILE_ENCODING # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # This tag can be used to specify the character encoding of the source files # that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify # character encoding on a per file pattern basis. Doxygen will compare the file # name with each pattern and apply the encoding instead of the default # INPUT_ENCODING) if there is a match. The character encodings are a list of the # form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding # "INPUT_ENCODING" for further information on supported encodings. INPUT_FILE_ENCODING = # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # read by doxygen. # # Note the list of default checked file patterns might differ from the list of # default file extension mappings. # # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, # *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, # *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C # comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, # *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = *.cpp *.h # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = libevolvotron/moc evolvotron/moc libevolvotron/usage_text.h # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # ANamespace::AClass, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command: # # # # where is the value of the INPUT_FILTER tag, and is the # name of an input file. Doxygen will then use the output that the filter # program writes to standard output. If FILTER_PATTERNS is specified, this tag # will be ignored. # # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. # # Note that doxygen will use the data processed and written to standard output # for further processing, therefore nothing else, like debug statements or used # commands (so in case of a Windows batch file always use @echo OFF), should be # written to standard output. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: pattern=filter # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = # The Fortran standard specifies that for fixed formatted Fortran code all # characters from position 72 are to be considered as comment. A common # extension is to allow longer lines before the automatic comment starts. The # setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can # be processed before the automatic comment starts. # Minimum value: 7, maximum value: 10000, default value: 72. FORTRAN_COMMENT_AFTER = 72 #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will be # generated. Documented entities will be cross-referenced with these sources. # # Note: To get rid of all source code in the generated output, make sure that # also VERBATIM_HEADERS is set to NO. # The default value is: NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. # The default value is: NO. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # entity all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES then for each documented function # all documented entities called/used by that function will be listed. # The default value is: NO. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # to YES then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. REFERENCES_LINK_SOURCE = YES # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system # (see https://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global # - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # # The result: instead of the source browser generated by doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. # The default value is: YES. VERBATIM_HEADERS = YES # If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the # clang parser (see: # http://clang.llvm.org/) for more accurate parsing at the cost of reduced # performance. This can be particularly helpful with template rich C++ code for # which doxygen's built-in parser lacks the necessary type information. # Note: The availability of this option depends on whether or not doxygen was # generated with the -Duse_libclang=ON option for CMake. # The default value is: NO. CLANG_ASSISTED_PARSING = NO # If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS # tag is set to YES then doxygen will add the directory of each input to the # include path. # The default value is: YES. # This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. CLANG_ADD_INC_PATHS = YES # If clang assisted parsing is enabled you can provide the compiler with command # line options that you would normally use when invoking the compiler. Note that # the include paths will already be set by doxygen for the files and directories # specified with INPUT and INCLUDE_PATH. # This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. CLANG_OPTIONS = # If clang assisted parsing is enabled you can provide the clang parser with the # path to the directory containing a file called compile_commands.json. This # file is the compilation database (see: # http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the # options used when the source files were built. This is equivalent to # specifying the -p option to a clang tool, such as clang-check. These options # will then be passed to the parser. Any options specified with CLANG_OPTIONS # will be added as well. # Note: The availability of this option depends on whether or not doxygen was # generated with the -Duse_libclang=ON option for CMake. CLANG_DATABASE_PATH = #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all # compounds will be generated. Enable this if the project contains a lot of # classes, structs, unions or interfaces. # The default value is: YES. ALPHABETICAL_INDEX = NO # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets # that doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" # for information on how to generate the default header that doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the # default header when upgrading to a newer version of doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of # the HTML output. If left blank doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style # sheet that doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefore more robust against future updates. # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance (e.g. the last # style sheet in the list overrules the setting of the previous ones in the # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE tag can be used to specify if the generated HTML output # should be rendered with a dark or light theme. Default setting AUTO_LIGHT # enables light output unless the user preference is dark output. Other options # are DARK to always use dark mode, LIGHT to always use light mode, AUTO_DARK to # default to dark mode unless the user prefers light mode, and TOGGLE to let the # user toggle between dark and light mode via a button. # Possible values are: LIGHT Always generate light output., DARK Always generate # dark output., AUTO_LIGHT Automatically set the mode according to the user # preference, use light mode if no preference is set (the default)., AUTO_DARK # Automatically set the mode according to the user preference, use dark mode if # no preference is set. and TOGGLE Allow to user to switch between light and # dark mode via a button.. # The default value is: AUTO_LIGHT. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE = AUTO_LIGHT # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a color-wheel, see # https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use gray-scales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 # gradually make the output lighter, whereas values above 100 make the output # darker. The value divided by 100 is the actual gamma applied, so 80 represents # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not # change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this # to YES can help to show when doxygen was last run and thus if the # documentation is up to date. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = NO # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML # documentation will contain a main index with vertical navigation menus that # are dynamically created via JavaScript. If disabled, the navigation index will # consists of multiple levels of tabs that are statically embedded in every HTML # page. Disable this option to support browsers that do not have JavaScript, # like the Qt help browser. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_MENUS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to # such a level that at most the specified number of entries are visible (unless # a fully collapsed tree already exceeds this amount). So setting the number of # entries 1 will produce a full collapsed tree by default. 0 is a special value # representing an infinite number of entries and will result in a full expanded # tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: # https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To # create a documentation set, doxygen will generate a Makefile in the HTML # output directory. Running make will produce the docset in that directory and # running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy # genXcode/_index.html for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" # This tag determines the URL of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDURL = # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # on Windows. In the beginning of 2021 Microsoft took the original page, with # a.o. the download links, offline the HTML help workshop was already many years # in maintenance mode). You can download the HTML help workshop from the web # archives at Installation executable (see: # http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo # ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for # words in the documentation. The HTML workshop also contains a viewer for # compressed HTML files. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler (hhc.exe). If non-empty, # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated # (YES) or that it should be included in the main .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO # The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated # (YES) or a normal table of contents (NO) in the .chm file. Furthermore it # enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members to # the table of contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help # (.qch) of the generated HTML documentation. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify # the file name of the resulting .qch file. The path specified is relative to # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace # (see: # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual # Folders (see: # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom # Filters (see: # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom # Filters (see: # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location (absolute path # including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to # run qhelpgenerator on the generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To # install this plugin and make it available under the help contents menu in # Eclipse, the contents of the directory containing the HTML and XML files needs # to be copied into the plugins directory of eclipse. The name of the directory # within the plugins directory should be the same as the ECLIPSE_DOC_ID value. # After copying Eclipse needs to be restarted before the help appears. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO # A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this # name. Each documentation set should have its own identifier. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project # If you want full control over the layout of the generated HTML pages it might # be necessary to disable the index and replace it with your own. The # DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top # of each HTML page. A value of NO enables the index and the value YES disables # it. Since the tabs in the index contain the same information as the navigation # tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag # value is set to YES, a side panel will be generated containing a tree-like # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can # further fine tune the look of the index (see "Fine-tuning the output"). As an # example, the default style sheet generated by doxygen has an example that # shows how to put an image at the root of the tree instead of the PROJECT_NAME. # Since the tree basically has the same information as the tab index, you could # consider setting DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO # When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the # FULL_SIDEBAR option determines if the side bar is limited to only the treeview # area (value NO) or if it should extend to the full height of the window (value # YES). Setting this to YES gives a layout similar to # https://docs.readthedocs.io with more room for contents, but less room for the # project logo, title, and description. If either GENERATE_TREEVIEW or # DISABLE_INDEX is set to NO, this option has no effect. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. FULL_SIDEBAR = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # # Note that a value of 0 will completely suppress the enum values from appearing # in the overview section. # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 250 # If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email # addresses. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. OBFUSCATE_EMAILS = YES # If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg # tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see # https://inkscape.org) to generate formulas as SVG images instead of PNGs for # the HTML output. These images will generally look nicer at scaled resolutions. # Possible values are: png (the default) and svg (looks nicer but requires the # pdf2svg or inkscape tool). # The default value is: png. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FORMULA_FORMAT = png # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands # to create new LaTeX commands to be used in formulas as building blocks. See # the section "Including formulas" for details. FORMULA_MACROFILE = # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # https://www.mathjax.org) which uses client side JavaScript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = NO # With MATHJAX_VERSION it is possible to specify the MathJax version to be used. # Note that the different versions of MathJax have different requirements with # regards to the different settings, so it is possible that also other MathJax # settings have to be changed when switching between the different MathJax # versions. # Possible values are: MathJax_2 and MathJax_3. # The default value is: MathJax_2. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_VERSION = MathJax_2 # When MathJax is enabled you can set the default output format to be used for # the MathJax output. For more details about the output format see MathJax # version 2 (see: # http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 # (see: # http://docs.mathjax.org/en/latest/web/components/output.html). # Possible values are: HTML-CSS (which is slower, but has the best # compatibility. This is the name for Mathjax version 2, for MathJax version 3 # this will be translated into chtml), NativeMML (i.e. MathML. Only supported # for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This # is the name for Mathjax version 3, for MathJax version 2 this will be # translated into HTML-CSS) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory # should contain the MathJax.js script. For instance, if the mathjax directory # is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from https://www.mathjax.org before deployment. The default value is: # - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 # - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # for MathJax version 2 (see # https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions): # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # For example for MathJax version 3 (see # http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): # MATHJAX_EXTENSIONS = ams # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: # http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. # For large projects the javascript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use + S # (what the is depends on the OS and browser, but it is typically # , /