evolvotron-0.8.1/0000755000175000017500000000000014376735121012412 5ustar karlkarlevolvotron-0.8.1/tools/0000755000175000017500000000000014376735121013552 5ustar karlkarlevolvotron-0.8.1/tools/license/0000755000175000017500000000000014376735121015174 5ustar karlkarlevolvotron-0.8.1/tools/license/stripheader0000755000175000017500000000043414376735121017435 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.1/tools/license/config0000644000175000017500000000017414376735121016366 0ustar karlkarl# C/CPP source ".*\\.[ch]" -> frame open:"/*" line:"*" close:"*/" | ".*\\.cpp" -> frame open:"/*" line:"*" close:"*/" evolvotron-0.8.1/tools/license/boilerplate0000644000175000017500000000122714376735121017423 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.1/tools/license/apply0000755000175000017500000000021014376735121016240 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.1/text_to_markup.py0000755000175000017500000001464214376735121016043 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.1/text_to_markup.b0000755000175000017500000001107414376735121015630 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.1/sourceforge/0000755000175000017500000000000014376735121014735 5ustar karlkarlevolvotron-0.8.1/sourceforge/README.md0000644000175000017500000000157614376735121016225 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.1/project.b0000644000175000017500000000155114376735121014225 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] ] default [ cxxflags "-std=c++11" ] 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.1/mktgz0000755000175000017500000000040514376735121013473 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.1/mkdoc0000755000175000017500000000006114376735121013432 0ustar karlkarl#!/bin/sh -v mkdir -p doc doxygen doxygen.cfg evolvotron-0.8.1/mkdeb0000755000175000017500000000677314376735121013437 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.1/man/0000755000175000017500000000000014376735121013165 5ustar karlkarlevolvotron-0.8.1/man/man1/0000755000175000017500000000000014376735121014021 5ustar karlkarlevolvotron-0.8.1/man/man1/evolvotron_render.10000644000175000017500000000417714376735121017670 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.1/man/man1/evolvotron_mutate.10000644000175000017500000000322114376735121017675 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.1/man/man1/evolvotron.10000644000175000017500000001277114376735121016330 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.1/main.pro0000644000175000017500000000030714376735121014060 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.1/libfunction/0000755000175000017500000000000014376735121014726 5ustar karlkarlevolvotron-0.8.1/libfunction/xyz.h0000644000175000017500000001604314376735121015735 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.1/libfunction/xyz.cpp0000644000175000017500000000570214376735121016270 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.1/libfunction/xy.h0000644000175000017500000001136414376735121015544 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.1/libfunction/xy.cpp0000644000175000017500000000307314376735121016075 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.1/libfunction/useful.h0000644000175000017500000001170614376735121016407 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.1/libfunction/useful.cpp0000644000175000017500000000403614376735121016740 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.1/libfunction/update_register_all_functions0000755000175000017500000000173414376735121022767 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 "libfunction_precompiled.h" #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.1/libfunction/transform.h0000644000175000017500000001236314376735121017117 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.1/libfunction/transform.cpp0000644000175000017500000000667414376735121017462 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.1/libfunction/stripcomments.sed0000644000175000017500000000006414376735121020332 0ustar karlkarl:loop s-\(.*\)/\*.*\*/-\1- t loop /\/\*/!b N b loop evolvotron-0.8.1/libfunction/register_all_functions.h0000644000175000017500000000336314376735121021650 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.1/libfunction/register_all_functions.cpp0000644000175000017500000002471314376735121022205 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 . */ /**************************************************************************/ /* 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(FunctionPixelizeHex); REGISTER_DCL(FunctionVoxelize); 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_FunctionPixelizeHex(r); register_FunctionVoxelize(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.1/libfunction/random.h0000644000175000017500000000703514376735121016364 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); } //! Adapter to use our random number generator to feed std::random_shuffle class RandomInt { public: RandomInt(Random01& r01) :_r01(r01) {} uint operator()(uint n) { return static_cast(_r01()*n); } private: Random01& _r01; }; template void random_shuffle(std::vector& v,Random01& r01) { RandomInt r0n(r01); std::random_shuffle(v.begin(),v.end(),r0n); } #endif evolvotron-0.8.1/libfunction/random.cpp0000644000175000017500000000317714376735121016722 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.1/libfunction/noise.h0000644000175000017500000000346514376735121016224 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.1/libfunction/noise.cpp0000644000175000017500000000727114376735121016556 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.1/libfunction/mutation_parameters.cpp0000644000175000017500000001673614376735121021532 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.1/libfunction/margin.h0000644000175000017500000000364214376735121016361 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.1/libfunction/margin.cpp0000644000175000017500000000305414376735121016711 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.1/libfunction/libfunction.pro0000644000175000017500000000030714376735121017764 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.1/libfunction/hex.h0000644000175000017500000000323714376735121015670 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.1/libfunction/hex.cpp0000644000175000017500000000442114376735121016217 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.1/libfunction/functions_transform.cpp0000644000175000017500000000307614376735121021543 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.1/libfunction/functions_tartan.h0000644000175000017500000001267414376735121020472 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.1/libfunction/functions_tartan.cpp0000644000175000017500000000307314376735121021016 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.1/libfunction/functions_spiral.h0000644000175000017500000000555014376735121020466 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.1/libfunction/functions_spiral.cpp0000644000175000017500000000307314376735121021017 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.1/libfunction/functions_spherical.h0000644000175000017500000000743114376735121021146 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.1/libfunction/functions_spherical.cpp0000644000175000017500000000307614376735121021502 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.1/libfunction/functions_shadow.h0000644000175000017500000000471614376735121020464 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.1/libfunction/functions_shadow.cpp0000644000175000017500000000307314376735121021012 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.1/libfunction/functions_render.h0000644000175000017500000001457214376735121020457 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.1/libfunction/functions_render.cpp0000644000175000017500000000307314376735121021004 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.1/libfunction/functions_quantize.h0000644000175000017500000000577714376735121021047 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.1/libfunction/functions_quantize.cpp0000644000175000017500000000307514376735121021367 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.1/libfunction/functions_noise.h0000644000175000017500000000756514376735121020321 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.1/libfunction/functions_misc.h0000644000175000017500000001024614376735121020125 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.1/libfunction/functions_magnitude.h0000644000175000017500000000513214376735121021145 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.1/libfunction/functions_magnitude.cpp0000644000175000017500000000307614376735121021505 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.1/libfunction/functions_kaleidoscope.h0000644000175000017500000001275214376735121021640 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.1/libfunction/functions_kaleidoscope.cpp0000644000175000017500000000310114376735121022157 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.1/libfunction/functions_juliabrot.h0000644000175000017500000001411614376735121021165 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.1/libfunction/functions_juliabrot.cpp0000644000175000017500000000307614376735121021523 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.1/libfunction/functions_gradient.h0000644000175000017500000001563514376735121020776 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.1/libfunction/functions_gradient.cpp0000644000175000017500000000307514376735121021324 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.1/libfunction/functions_geometry.h0000644000175000017500000000644614376735121021034 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.1/libfunction/functions_geometry.cpp0000644000175000017500000000307514376735121021362 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.1/libfunction/functions_friezegroup_step.h0000644000175000017500000000537714376735121022577 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.1/libfunction/functions_friezegroup_step.cpp0000644000175000017500000000310614376735121023116 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.1/libfunction/functions_friezegroup_spinsidle.h0000644000175000017500000000552414376735121023610 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.1/libfunction/functions_friezegroup_spinsidle.cpp0000644000175000017500000000311314376735121024133 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.1/libfunction/functions_friezegroup_spinjump.h0000644000175000017500000000471314376735121023462 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.1/libfunction/functions_friezegroup_spinjump.cpp0000644000175000017500000000311214376735121024005 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.1/libfunction/functions_friezegroup_spinhop.h0000644000175000017500000000763414376735121023302 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.1/libfunction/functions_friezegroup_spinhop.cpp0000644000175000017500000000302614376735121023624 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.1/libfunction/functions_friezegroup_sidle.h0000644000175000017500000000457614376735121022724 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.1/libfunction/functions_friezegroup_sidle.cpp0000644000175000017500000000310714376735121023244 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.1/libfunction/functions_friezegroup_jump.h0000644000175000017500000000757314376735121022577 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.1/libfunction/functions_friezegroup_jump.cpp0000644000175000017500000000310614376735121023116 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.1/libfunction/functions_friezegroup_hop.h0000644000175000017500000000754514376735121022411 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.1/libfunction/functions_friezegroup_hop.cpp0000644000175000017500000000300414376735121022726 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.1/libfunction/functions_filter.h0000644000175000017500000001607014376735121020460 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.1/libfunction/functions_choose.h0000644000175000017500000002502614376735121020454 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.1/libfunction/functions_choose.cpp0000644000175000017500000000307314376735121021005 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.1/libfunction/functions_arithmetic.h0000644000175000017500000001232314376735121021321 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.1/libfunction/functions_arithmetic.cpp0000644000175000017500000000307714376735121021662 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.1/libfunction/function_transform_generalised.h0000644000175000017500000000365514376735121023372 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.1/libfunction/function_transform_generalised.cpp0000644000175000017500000000312314376735121023713 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.1/libfunction/function_transform.h0000644000175000017500000000416214376735121021022 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.1/libfunction/function_transform.cpp0000644000175000017500000000307514376735121021357 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.1/libfunction/function_top.h0000644000175000017500000000630414376735121017611 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.1/libfunction/function_top.cpp0000644000175000017500000001647114376735121020152 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.1/libfunction/function_registry.h0000644000175000017500000000442314376735121020657 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. */ struct FunctionRegistry : public std::map { 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.1/libfunction/function_registry.cpp0000644000175000017500000000472014376735121021212 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.1/libfunction/function_registration.h0000644000175000017500000000624414376735121021524 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.1/libfunction/function_registration.cpp0000644000175000017500000000313714376735121022055 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.1/libfunction/function_pre_transform.h0000644000175000017500000000450314376735121021667 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.1/libfunction/function_pre_transform.cpp0000644000175000017500000000307414376735121022224 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.1/libfunction/function_post_transform.h0000644000175000017500000000453614376735121022074 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.1/libfunction/function_post_transform.cpp0000644000175000017500000000307614376735121022425 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.1/libfunction/function_node_info.h0000644000175000017500000000501214376735121020742 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.1/libfunction/function_node_info.cpp0000644000175000017500000000271614376735121021305 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.1/libfunction/function_node.h0000644000175000017500000002030114376735121017725 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.1/libfunction/function_identity.h0000644000175000017500000000410614376735121020636 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.1/libfunction/function_identity.cpp0000644000175000017500000000307414376735121021174 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.1/libfunction/function_constant.h0000644000175000017500000000434014376735121020636 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.1/libfunction/function_constant.cpp0000644000175000017500000000307414376735121021174 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.1/libfunction/function_compose_triple.h0000644000175000017500000000405614376735121022035 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.1/libfunction/function_compose_triple.cpp0000644000175000017500000000310514376735121022362 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.1/libfunction/function_compose_pair.h0000644000175000017500000000400414376735121021462 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.1/libfunction/function_compose_pair.cpp0000644000175000017500000000307614376735121022025 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.1/libfunction/function_boilerplate_instantiate.h0000644000175000017500000000320214376735121023706 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.1/libfunction/function_boilerplate.h0000644000175000017500000002165514376735121021317 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.1/libfunction/function_boilerplate.cpp0000644000175000017500000000305114376735121021640 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.1/libfunction/friezegroup.h0000644000175000017500000002465214376735121017451 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.1/libfunction/friezegroup.cpp0000644000175000017500000000271214376735121017775 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.1/libevolvotron/0000755000175000017500000000000014376735121015316 5ustar karlkarlevolvotron-0.8.1/libevolvotron/usage_text.h0000644000175000017500000010064414376735121017644 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.1/libevolvotron/transform_factory.h0000644000175000017500000001120014376735121021223 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.1/libevolvotron/transform_factory.cpp0000644000175000017500000000605114376735121021566 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.1/libevolvotron/render_parameters.h0000644000175000017500000000507214376735121021175 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.1/libevolvotron/render_parameters.cpp0000644000175000017500000000335014376735121021525 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.1/libevolvotron/platform_specific.h0000644000175000017500000000345114376735121021163 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.1/libevolvotron/platform_specific.cpp0000644000175000017500000000447114376735121021521 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.1/libevolvotron/mutation_parameters_qobject.h0000644000175000017500000000366014376735121023266 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.1/libevolvotron/mutation_parameters_qobject.cpp0000644000175000017500000000343014376735121023614 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.1/libevolvotron/mutatable_image_display_big.h0000644000175000017500000000453614376735121023165 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.1/libevolvotron/mutatable_image_display_big.cpp0000644000175000017500000000521214376735121023510 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.1/libevolvotron/mutatable_image_display.h0000644000175000017500000002260714376735121022343 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.1/libevolvotron/mutatable_image_display.cpp0000644000175000017500000010007614376735121022673 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(); } void MutatableImageDisplay::mousePressEvent(QMouseEvent* event) { if (event->button()==Qt::RightButton) { _menu->exec(QCursor::pos()); } else if (event->button()==Qt::MidButton) { 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 (event->x() > (width() - 32) && event->y() < 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::MidButton) { 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.1/libevolvotron/mutatable_image_computer_task.h0000644000175000017500000001560714376735121023560 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.1/libevolvotron/mutatable_image_computer_task.cpp0000644000175000017500000000627014376735121024107 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.1/libevolvotron/mutatable_image_computer_farm.h0000644000175000017500000001247014376735121023536 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.1/libevolvotron/mutatable_image_computer_farm.cpp0000644000175000017500000001636314376735121024076 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.1/libevolvotron/mutatable_image_computer.h0000644000175000017500000001355314376735121022534 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.1/libevolvotron/mutatable_image_computer.cpp0000644000175000017500000001137414376735121023066 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.1/libevolvotron/mutatable_image.h0000644000175000017500000001240114376735121020605 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.1/libevolvotron/mutatable_image.cpp0000644000175000017500000003676314376735121021161 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; } /*! Expect 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 \"" + localName + "\"\n"; raiseError(msg); return false; } if (_expect_top_level_element) { if (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 != APP_VERSION) { warning += "Warning: File saved from a different evolvotron version: "+version+"\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 \""+zsweep+"\"\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 \""+projection+"\"\n"; raiseError(msg); return false; } } } else { QString msg = "Error: Expected but got \""+localName+"\"\n"; raiseError(msg); return false; } } else { if (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 (localName=="type") { _expect_characters=true; _expect_characters_type=true; } else if (localName=="i") { _expect_characters=true; _expect_characters_iterations=true; } else if (localName=="p") { _expect_characters=true; _expect_characters_parameter=true; } else { QString msg = "Error: Expected , , or

but got \"" + localName + "\"\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 \"" + localName + "\"\n"; raiseError(msg); return false; } if (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 : \"" + s + "\"\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 \"" + s + "\" 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 \"" + s + "\" 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.1/libevolvotron/license.h0000644000175000017500000000303314376735121017110 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.1/libevolvotron/license.cpp0000644000175000017500000004752614376735121017462 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.1/libevolvotron/libevolvotron.pro0000644000175000017500000000042714376735121020747 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.1/libevolvotron/evolvotron_main.h0000644000175000017500000003365414376735121020723 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.1/libevolvotron/evolvotron_main.cpp0000644000175000017500000006206114376735121021250 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 "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); _popupmenu_file=menuBar()->addMenu("&File"); _popupmenu_file->addAction("Reset (Reset mutation parameters, clear locks)",this,SLOT(reset_cold()),QKeySequence("r")); _popupmenu_file->addAction("Restart (Preserve mutation parameters and locks)",this,SLOT(reset_warm()),QKeySequence("t")); _popupmenu_file->addAction("Remix (Randomize function weights and restart)",this,SLOT(reset_randomized()),QKeySequence("x")); _popupmenu_file->addSeparator(); _popupmenu_file->addAction("&Quit", this, SLOT(close()), QKeySequence::Quit); _popupmenu_edit=menuBar()->addMenu("&Edit"); _popupmenu_edit_undo_action=_popupmenu_edit->addAction("Undo",this,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=_popupmenu_settings->addAction("Fullscreen",this,SLOT(toggle_fullscreen()),QKeySequence(Qt::CTRL + Qt::Key_F)); _menu_action_fullscreen->setCheckable(true); _menu_action_fullscreen->setChecked(start_fullscreen); _menu_action_hide_menu=_popupmenu_settings->addAction("Hide menu and statusbar",this,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())); _popupmenu_help->addAction("User &Manual",_dialog_help_long,SLOT(show()),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_shuffle(_startup_filenames.begin(),_startup_filenames.end()); } 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.1/libevolvotron/dialog_render_parameters.h0000644000175000017500000000531714376735121022516 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.1/libevolvotron/dialog_render_parameters.cpp0000644000175000017500000001017014376735121023042 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,SIGNAL(buttonClicked(int)),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.1/libevolvotron/dialog_mutation_parameters.h0000644000175000017500000001023514376735121023072 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.1/libevolvotron/dialog_mutation_parameters.cpp0000644000175000017500000002573014376735121023433 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.1/libevolvotron/dialog_mutatable_image_display.h0000644000175000017500000000453614376735121023663 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.1/libevolvotron/dialog_mutatable_image_display.cpp0000644000175000017500000000454714376735121024220 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.1/libevolvotron/dialog_help.h0000644000175000017500000000340714376735121017742 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.1/libevolvotron/dialog_help.cpp0000644000175000017500000000712714376735121020300 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.1/libevolvotron/dialog_functions.h0000644000175000017500000001035114376735121021016 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.1/libevolvotron/dialog_functions.cpp0000644000175000017500000002741514376735121021362 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.1/libevolvotron/dialog_favourite.h0000644000175000017500000000605414376735121021017 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.1/libevolvotron/dialog_favourite.cpp0000644000175000017500000001044114376735121021345 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.1/libevolvotron/dialog_about.h0000644000175000017500000000346514376735121020130 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.1/libevolvotron/dialog_about.cpp0000644000175000017500000000635514376735121020464 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.1/libevolvotron/common.h0000644000175000017500000000471214376735121016763 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 #include #define APP_VERSION "0.8.1" #ifdef DEBUG #define APP_BUILD APP_VERSION " (Debug)" #else #define APP_BUILD APP_VERSION #endif #endif evolvotron-0.8.1/extras/0000755000175000017500000000000014376735121013720 5ustar karlkarlevolvotron-0.8.1/extras/spheremap.sh0000755000175000017500000000023214376735121016240 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.1/extras/spheremap.pov0000644000175000017500000000036014376735121016431 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.1/extras/README0000644000175000017500000000045314376735121014602 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.1/experiment/0000755000175000017500000000000014376735121014572 5ustar karlkarlevolvotron-0.8.1/experiment/svg/0000755000175000017500000000000014376735121015371 5ustar karlkarlevolvotron-0.8.1/experiment/svg/svg.pro0000644000175000017500000000106214376735121016711 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.1/experiment/svg/svg.cpp0000644000175000017500000000255314376735121016701 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.1/experiment/svg/drawing0.svg0000644000175000017500000002235714376735121017636 0ustar karlkarl image/svg+xml evolvotron-0.8.1/experiment/svg/GLTRACE.INI0000644000175000017500000000553114376735121017017 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.1/experiment/svg/BUILD0000755000175000017500000000004314376735121016153 0ustar karlkarl#!/bin/sh qmake-qt4 svg.pro make evolvotron-0.8.1/experiment/program_options/0000755000175000017500000000000014376735121020014 5ustar karlkarlevolvotron-0.8.1/experiment/program_options/pair.cpp0000644000175000017500000000444414376735121021461 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.1/experiment/program_options/makefile0000644000175000017500000000011414376735121021510 0ustar karlkarlall: pair pair: pair.cpp g++ pair.cpp -O2 -o pair -lboost_program_options evolvotron-0.8.1/evolvotron_render/0000755000175000017500000000000014376735121016166 5ustar karlkarlevolvotron-0.8.1/evolvotron_render/evolvotron_render.pro0000644000175000017500000000056214376735121022467 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.1/evolvotron_render/evolvotron_render.cpp0000644000175000017500000001505014376735121022447 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.1/evolvotron_mutate/0000755000175000017500000000000014376735121016206 5ustar karlkarlevolvotron-0.8.1/evolvotron_mutate/evolvotron_mutate.pro0000644000175000017500000000056214376735121022527 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.1/evolvotron_mutate/evolvotron_mutate.cpp0000644000175000017500000001004514376735121022506 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.1/evolvotron/0000755000175000017500000000000014376735121014627 5ustar karlkarlevolvotron-0.8.1/evolvotron/icons/0000755000175000017500000000000014376735121015742 5ustar karlkarlevolvotron-0.8.1/evolvotron/icons/lock.png0000644000175000017500000000156414376735121017406 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%tN»‘Ø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.1/evolvotron/icons.qrc0000644000175000017500000000010214376735121016442 0ustar karlkarl icons/lock.png evolvotron-0.8.1/evolvotron/evolvotron.pro0000644000175000017500000000061114376735121017564 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.1/evolvotron/evolvotron.cpp0000644000175000017500000002107714376735121017557 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.1/evolvotron.spec0000644000175000017500000000375714376735121015517 0ustar karlkarlSummary: Evolvotron Interactive Art Generator Name: evolvotron Version: 0.8.1 Release: 1%{?dist} License: GPLv2+ URL: http://sourceforge.net/projects/evolvotron Group: Applications/Graphics Source: %{name}-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRequires: gcc-c++ boost-devel qt5-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 %build qmake-qt5 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 * 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.1/evolvotron.html0000644000175000017500000007271514376735121015531 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.1/doxygen.cfg0000644000175000017500000010757614376735121014570 0ustar karlkarl# Doxyfile 1.2.14 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a 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 (" ") #--------------------------------------------------------------------------- # General configuration options #--------------------------------------------------------------------------- # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the 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 = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # 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 # 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. # The default language is English, other supported languages are: # Brazilian, Chinese, Croatian, Czech, Danish, Dutch, Finnish, French, # German, Greek, Hungarian, Italian, Japanese, Korean, Norwegian, Polish, # Portuguese, Romanian, Russian, Slovak, Slovene, Spanish and Swedish. OUTPUT_LANGUAGE = English # 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 and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = YES # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. 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. EXTRACT_LOCAL_CLASSES = YES # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) 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. 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 (the default) these class will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the BRIEF_MEMBER_DESC tag is set to YES (the default) 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. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) 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. REPEAT_BRIEF = YES # 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. 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. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then 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. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then 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. It is allowed to use relative paths in the argument list. STRIP_FROM_PATH = # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower case letters. If set to YES upper case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # users are adviced to set this option to NO. CASE_SENSE_NAMES = YES # 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. SHORT_NAMES = NO # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the VERBATIM_HEADERS tag is set to YES (the default) 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. VERBATIM_HEADERS = YES # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # 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 # comments will behave just like the Qt-style comments (thus requiring an # explict @brief command for a brief description. JAVADOC_AUTOBRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # reimplements. INHERIT_DOCS = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) 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. SORT_MEMBER_DOCS = 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. DISTRIBUTE_GROUP_DOC = YES # 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. TAB_SIZE = 8 # 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. 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. 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. GENERATE_BUGLIST = YES # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" 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:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consist of 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 initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # 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. OPTIMIZE_OUTPUT_FOR_C = NO # 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. SHOW_USED_FILES = YES #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED 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. WARN_IF_UNDOCUMENTED = YES # 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. WARN_FORMAT = "$file:$line: $text" # 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 stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be 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. INPUT = # If the value of the INPUT tag contains directories, you can use the # FILE_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 the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp # *.h++ *.idl *.odl FILE_PATTERNS = # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should # 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. EXCLUDE = libevolvotron/moc # The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories # that are symbolic links (a Unix filesystem feature) are excluded from the input. 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. EXCLUDE_PATTERNS = # 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. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are 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. INPUT_FILTER = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse. FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # 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. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES #--------------------------------------------------------------------------- # 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. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # 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 one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. 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. If left blank `html' will be used as the default path. 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). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. 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 the tag is left blank doxygen # will generate a default style sheet HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, 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. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the Html help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag 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 and frames is required (for instance Mozilla, Netscape 4.0+, # or Internet explorer 4.0+). Note that for large projects the tree generation # can take a very long time. In such cases it is better to disable this feature. # Windows users are probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # 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. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = YES # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimised for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assigments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_XML = NO #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_PREDEFINED tags. EXPAND_ONLY_PREDEF = YES # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. PREDEFINED = "FUNCTION_BEGIN(FN,NP,NA,IT)=class FN : public FunctionBoilerplate{public:" \ "FUNCTION_END(FN)=};" # If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line and do not end with a semicolon. Such function macros are typically # used for boiler-plate code, and will confuse the parser if not removed. SKIP_FUNCTION_MACROS = NO #--------------------------------------------------------------------------- # Configuration::addtions related to external references #--------------------------------------------------------------------------- # The TAGFILES tag can be used to specify one or more tagfiles. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in Html, RTF and LaTeX) for classes with base or # super classes. Setting the tag to NO turns the diagrams off. Note that this # option is superceded by the HAVE_DOT option below. This is only a fallback. It is # recommended to install and use dot, since it yield more powerful graphs. CLASS_DIAGRAMS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = YES # changed from NO # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = YES # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are gif, jpg, and png # If left blank gif will be used. DOT_IMAGE_FORMAT = gif # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found on the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_WIDTH = 1024 # The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_HEIGHT = 1024 # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermedate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::addtions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO # The CGI_NAME tag should be the name of the CGI script that # starts the search engine (doxysearch) with the correct parameters. # A script with this name will be generated by doxygen. CGI_NAME = search.cgi # The CGI_URL tag should be the absolute URL to the directory where the # cgi binaries are located. See the documentation of your http daemon for # details. CGI_URL = # The DOC_URL tag should be the absolute URL to the directory where the # documentation is located. If left blank the absolute path to the # documentation, with file:// prepended to it, will be used. DOC_URL = # The DOC_ABSPATH tag should be the absolute path to the directory where the # documentation is located. If left blank the directory on the local machine # will be used. DOC_ABSPATH = # The BIN_ABSPATH tag must point to the directory where the doxysearch binary # is installed. BIN_ABSPATH = /usr/local/bin/ # The EXT_DOC_PATHS tag can be used to specify one or more paths to # documentation generated for other projects. This allows doxysearch to search # the documentation for these projects as well. EXT_DOC_PATHS = evolvotron-0.8.1/dist/0000755000175000017500000000000014376735121013355 5ustar karlkarlevolvotron-0.8.1/dist/icon-48.png0000644000175000017500000001000314376735121015236 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˜)èGN2‚Ä 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ñE03Ê–õ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Ž 9r,¹ˆ õ•²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çÏóÎØc9_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.1/dist/icon-128.png0000644000175000017500000003323514376735121015331 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©MXÚ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=²KMJâêÛ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àXPƒ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_ZD€#‚Ë#E2B@$È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+ìˆVBHr›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ïëç{Ù^à"Á9TÁÂ:'ð#áàìËl9üäÚôzú¯Sþù=Cêë!ÌW@ ×†5chd-º1¨‚dײý† gß«âÔîz d#ðÎä ×0:GÕBRKDHP)ª+,ЦêÜ@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 WAQè®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’8qB8§ f=3¾åþ„¥s­(>.²Îõ¡‘¬GukÐ>ÐXöÞÎpÿç—\~‡’!°‚ÿúŸ²]9@ÂQíA ˆsY÷õ+ß1åß\ \b Y„Z÷z2Pk†%ÐÖjóAÉÝoÒƒð%oø.ýú~iäôAI¡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Ïù§?qM9€^ ¹€  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+hl`âÁ`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§ýxc7»ê( ‰„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øYmVød{DŒ"Y2s¹î@ì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<°2K„¢€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‚ÓGi>øšÒ úÛÁ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÷½¿ÜŽ (ð"ˆ[PD8UY™«UMÊ!Á ²‚e‚mA‚A{=ˆöçmÞ‰%ƒ¥D”Žc]ðuði²;f}¬àñ_‡YUhWoüÏ 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óIEª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.1/dist/evolvotron.ico0000644000175000017500000020407614376735121016277 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.1/dist/evolvotron.desktop0000644000175000017500000000025214376735121017164 0ustar karlkarl[Desktop Entry] Type=Application Name=Evolvotron Comment=Interactive generative art program Exec=evolvotron Icon=evolvotron Terminal=0 Categories=Qt;Graphics;2DGraphics; evolvotron-0.8.1/dist/app.rc0000644000175000017500000000010614376735121014460 0ustar karlkarlIDI_ICON1 ICON DISCARDABLE "dist/evolvotron.ico" evolvotron-0.8.1/common.pro0000644000175000017500000000320614376735121014425 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.1/cbuild0000755000175000017500000000316214376735121013604 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.1/VERSION0000755000175000017500000000041314376735121013463 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.1" evolvotron-0.8.1/USAGE-update.sh0000755000175000017500000000131714376735121015077 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.1/USAGE0000644000175000017500000006500314376735121013205 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.1/TODO0000644000175000017500000003547514376735121013120 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.1/README.md0000644000175000017500000001155514376735121013700 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. BUILDING CODE DOCUMENTATION --------------------------- If you have doxygen (and graphviz too) and want to build the source code documentation, execute `./mkdoc` at the top level. The code documentation then appears in `./doc/html/`. This hasn't been tested in a long while now, although the doxygen commenting style has been kept up. evolvotron-0.8.1/NEWS0000644000175000017500000003020014376735121013104 0ustar karlkarl[Most recent at top] Release 0.8.1: - Add application icons and Linux .desktop file. - Remove deprectated 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.1/LICENSE0000644000175000017500000004313114376735121013421 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.1/BUILD.sh0000755000175000017500000000064014376735121013610 0ustar karlkarl#!/bin/sh echo "***" echo "*** This script assumes Debian's Qt setup with a qtchooser supporting the -qt=5 option." echo "*** On Debian Squeeze, change to use -qt=4 instead." echo "*** Other Qt setups may require removing the -qt=5 option from qmake and setting QTDIR and PATH as usual." echo "***" VERSION_NUMBER=`./VERSION` qtchooser -run-tool=qmake -qt=5 "VERSION_NUMBER=$VERSION_NUMBER" main.pro && make -j 4 evolvotron-0.8.1/BUGS0000644000175000017500000000530114376735121013074 0ustar karlkarlKnown bugs: - Enlargements seem to need silly amount of memory. Where's it all going ? - Middle mouse drags sometimes don't seem to have any effect other than triggering redisplay. Thought to be fixed by MutatableImage serial numbers (was using pointer value as substitute for object identity before). - Build dependencies don't seem to be very good; crashes and bad linkage can sometimes be cleared by touching files or rebuild from clean. (precompiled headers something to do with this?) We're at the mercy of qmake here really. - Simplifying functions sometimes changes their appearance (implies "is_constant" probably buggy for some functions). Some random testing of functions before and after simplify would help. - When using -spheremap mode, middle mouse-button adjustments don't work as expected (this is because they're not compensated for the projection). Live with it. - Gradient type operators produce a real mess when applied to noise functions. High frequencies in the noise produce big derivatives. Enlarging up to 4096x4096 sometimes looks a bit more sensible. - Have yet to find a tool which can display anything other than the first frame of a Qt-generated MNG format. (Apparently Qt's MNG actually has nothing to do with the multi-frame PNG format). - Very rarely image calculations appear to arrive seriously out-of-order. May be a more of a problem on slower hardware ? If this is causing trouble, try using "-t 1" command-line option to fix it. - Example of "interesting" fullscreen bahaviour (Metacity on RedHat9): Run app fullscreen. Fire off a fullscreen "Big" display. Open the properties dialog for the "big" window. This results in metacity showing the task bar. Use the task bar to select the main app window into the foreground. Watch both fullscreen windows battle for supremacy! This sort of thing is unlikely to be fixed. - Resizing the evolvotron window queues up crazy numbers of tasks. This didn't matter too much in 2D mode, but with animations the memory reserved for each task's render target is considerably larger. - Undo doesn't always work how you'd expect. e.g respawn after undo doesn't respawn from what you'd expect. Undo of a reset or restart doesn't put the mutation parameters & function weightings back how they were. - Moire patterns & undersampling mean small images can show structures not actually present in larger resolution versions. - Once image colours become saturated there's not much which will cause them to scale back down to sensible ranges, unless you're lucky. - Recolour behaves strangely sometimes (?) (e.g spawns all-black images or subtly warped images) Not seen recently; may be fixed.