Auld’s IFS for 4kb
What is an IFS ?
An iterated function system is a number of transformations, repeatedly applied to a point. Each time the point is transformed a new, random, transform is chosen from the set of possible transforms and the process repeated. After each transform the point is drawn. The result, with correct transformations and enough iterations can be amazing.
Here are some example images, created using an IFS.
How does an IFS Work?
The C code at the heart of an IFS is:
The co-efficients come from the equation:
Which is essentially a 2d transformation of an arbitrary point. However, repeating a single transform many times will only result in simple movement of a point. The first key point about an IFS is that each IFS has a number of 2D transforms. Each iteration, one of the transforms is chosen and applied to the point. The fern example uses 4 sets of co-efficients.
The next key thing to understand is that if a transform is selected completely randomly from the set of transforms, it will take many iterations to produce an image. How many? Perhaps 1,000,000! This is because a point is often tranformed to the same position it was in previously, meaning the same point is plotted and there is no visible improvement in the image. How can this be improved? A bias is applied so that transforms are chosen more often that will move the point to new locations.
The last key element to understand is the idea that when the IFS starts, it takes a few iterations for the IFS to settle down and begin drawing the correct points. Normally, therefore, IFS code is complicated by a few extra iterations which are not plotted at the start of the execution.
Squeezing an IFS Down for 4k Demos
In this section, a number of techniques for reducing the size of IFS code are discussed. The result is code and data for the famous fern IFS which fits into around 250 bytes of compressed binary. One of the resulting functions is generically useful for things like implementing an animation system. All code is in C.
Fixing the Number of Sets of Co-efficients
Key point one above implies that any given image produced by an IFS can use any number of transforms. However, there are an amazing variety of images that can be produced using just two transforms. More so 3 and an astonishing number with 4. In the 4k code below therefore we fix the number of co-efficient sets (transforms) to be 4. This is sufficient to draw all manner of plants, leaves, abstracts, fractal shapes, spirals, dragons and so on. In particular it draws two of the most famous IFS images: the fern and the maple leaf.
Its possible to define less than 4 sets of co-efficients of course, if your image doesn’t require them. I’ll explain how later.
Avoiding the Initial Iterations
The actual image we produce using an IFS is known as the attractor. It is the set of interesting points. Other points are not intersting. The peculiar thing about IFS is that once you find one point on the attractor, the rest of the iterations will always produce another point on the attractor.
Normally, we iterate a few times and do not plot the points which are produced until we reach the attractor. This complicates the code.
The best way to avoid this is simply to know ahead of time, one point in the attractor. This is possible to work out mathematically but its a lot of maths. Better is simply to draw the image, starting with any point and then redefine your start point closer and closer to the attractor yourself by observation. This means we pass the initial point into the IFS code. For the Barnsley fern for example, (0,0) can be used as the initial point.
It is tempting to define 6 arrays for a,b,c,d,e,f..something like
This will make copying sets of co-efficients from web pages very easy. However, the compiler will produce bad code for this. Much better is to define a single array with all your co-efficients. Further, it is better for the compiler, to define in the order they are used in the equations: a,b,e,c,d,f.
Thus, an IFS with 4 transfoms would have an array with co-efficients:
Iterations and Loops v Recursion
I have found that simple tail recursion is more byte efficient than a loop counting through the iterations. This was tested with GCC.
Avoiding IFs and SWITCH
Much of the code on the internet to draw an IFS has something like:
This produces a lot of bytes in the compiled code. Instead, better is to write a function to chose the correct set of co-efficients to use and then use this to index into the array described previously. The function for chosing the correct set of co-efficients to use is described below…
How to chose the Random Transform
We are trying to implement a probability distribution function. The probabilties for the 4 sets of co-efficients we use can be found on the internet. So we generate a random number and test against the ACCUMULATED probabilities.
For example if our 4 transforms have the following percentage chances
of being chosen, then the cummulative values would be
We then chose a random number between 0,99 and check which pair of numbers we are between. In the (inefficient) code below we use rand()%100. This can be better written as rand()&99. However it can be less code.
The rand() function returns a value between 0..32767 normally (you need to check on the given platform but this is usually safe). Therefore scaling our cummulative probabilities to be between 0..32767 results in not needing to use &100.
Theoretically this is much better as rand(), as normally implemented, is less random in the lower order bits and doesn’t give good randomness when used in conjunction with mod. I digress.
NB this is not implemented in the code sample below.
Scaling the resulting Points
Normally code on the internet to do IFS will have a small section to scale the resulting points, transformed and ready to plot, to an area of the screen that is useful. To get rid of this code, you can pre-scale the IFS co-efficients. To do so, you need to know which ones to alter.
add some theory later…when the wifes in bed
Basically, a,b,c and d contain scaling factors. Pre-multiplying these gives you a smaller and smaller (or bigger and bigger) resulting image. Of course e and f are the translation factors which can be altered to put your scaled fern anywhere you wish.
rm-hull / barnsley-fern.cljs
|( ns big-bang.examples.barnsley-fern|
|[jayq.core :refer [show]]|
|[big-bang.core :refer [big-bang]]|
|[enchilada :refer [ctx canvas canvas-size]]|
|[monet.canvas :refer [fill-rect fill-style]]))|
|( def width ( first ( canvas-size )))|
|( def height ( second ( canvas-size )))|
|( def scale ( / height 10 ))|
|( def offset ( / w >2 ))|
|( def black-spleenwort [|
|; Probability Co-efficients|
|[ 0.01 [ 0.00 0.00 0.00 0.16 0.00 0.00 ]]|
|[ 0.86 [ 0.85 0.04 -0.04 0.85 0.00 1.60 ]]|
|[ 0.93 [ 0.20 -0.26 0.23 0.22 0.00 1.60 ]]|
|[ 1.00 [ -0.15 0.28 0.26 0.24 0.00 0.44 ]]])|
|( def initial-state [ 0 0 ])|
|( defn pick-coeffs [prob affine-transforms]|
|( for [[cumulative-prob coeffs] affine-transforms|
|:when ( prob cumulative-prob)]|
|( defn apply-transform [[x y] [a b c d e f]]|
|[( + ( * a x) ( * b y) e)|
|( + ( * c x) ( * d y) f)])|
|( defn update-state [event world-state]|
|( pick-coeffs ( rand ))|
|( apply-transform world-state)))|
|( defn render-fern [[x y]]|
|( fill-rect ctx <|
|( Math/floor ( + offset ( * scale x)))|
|:y ( Math/floor ( + height ( * scale y -1 )))|
|:w 1 :h 1 >))|
|( show canvas)|
|( fill-style ctx » green » )|
- © 2020 GitHub , Inc.
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
How to create a formula with nested IFs
In this video, I’ll show you how to create a formula that uses multiple, nested IF statements. This is a common technique to handle multiple conditions.
Let’s take a look.
This worksheet shows a class of students with five test scores in columns D through H, and and an average in column I.
In column J we need to add a formula that calculates a grade based on the average. This can be done with nested IF statements.
When you need to create nested IF, follow these steps:
First, make the logic you need to implement is clear. In this case, I’ve made a table that clearly shows what score is needed for each grade.
Next, if you’re new to nested IFs, list out the IF formulas you’ll need. Here I’ve added IF statements directly to the table.
The first columns shows the IF functions needed when moving from low scores to high scores The second column shows the IF statements needed to move from high scores to low scores.
It’s important that you work in one direction. In this example, let’s work from low to high.
Now add the first IF statement. If we stop there, the formula returns FALSE, because the average is not less than 64 and we aren’t supplying anything for value if false in the formula.
To continue, we need to add the next IF statement as the value if false in our first IF statement.
This is the key to building a formula that uses nested IFs.
Once I’ve added the 2nd IF statement, I need to add the third, as the value if false to the second. And so on.
In the last IF statement, supply the final value for value if false. In this case, that’s the grade «A». That is, if all previous IF statements return false, the grade should be A.
To finish off the formula, I need to one closing parentheses for each IF statement we’ve. In this case, that’s four closing parentheses.
When I copy the formula down, we’ll get the correct grade for each score.
To recap, in this example multiple IF statements are arranged in order, testing scores from low to high.
Each IF statement contains a test, and a value if true, and a value if false. Additional IF statements as the value if false for the previous IF statement.
In another video, we’ll look at how to make this kind of formula easier to read.
Construction Steps of Barnsley’s Fern
I am helping a friend with his thesis and we would like to do the following:
We would like to show the construction of Barnsley’s fern fractal by starting on the zeroth step with a big ellipse, then on the first step drawing two smaller ellipses, rotated and placed on the sides of the first one plus one more ellipse of the same size, placed on the bottom etc. We are actually trying to show each iteration as a sequence of pictures in order for it to be understood by the reader.
So far, I have only found the Barnsley’s ftern to be constructed in way similar to the Chaos game sierpinski triangle, but none in the way I mention above. Is it possible to do so?
2 Answers 2
After playing with the variables in a Manipulate I came up with these numbers for the arguments of the AffineMap functions.
They aren’t perfect. I recommend tuning them yourself:
You set the initial conditions: AffineMap provides the fractal Step
This is Roman Maeder’s AffineMap function and IFS
The examples below are from the book and they use points.
I took this from
I’ve got a package that makes dealing with iterated function systems pretty easy. You can download it off of my webspace. That package implements both deterministic and stochastic alorithms to generate images of self-affine sets like the Barnesly fern
Also, I think we can use a better initial shape than an oval. Let’s use the functions of the IFS to obtain an outline of the set:
Now, if you have the package above installed, you can do the following:
The result illustrates a difficulty with this approach when the pieces of the attractor have different sizes like this. The ShowIFS command implements another version of the deterministic algorithm where the pieces are decomposed until they reach a certain size, rather than a certain depth. To access this approach, we simply make the second argument a real number smaller than one to indicate how small we want the sizes to be — rather than an integer indicating the depth. This allows us to generate a picture like so:
If you’d like to illustrate how this process works, it probably makes the most sense to do so dynamically:
This allows you to see the decomposition happen as you move the slider down.
How to Create a Query in Access
To create a query in Access 2013 or 2020:
- Click the CREATE > Query Design button on the Ribbon.
- Choose the tables to include in the query
- Choose the fields to include, and adjust the criteria
- Click the Run button (or just switch to Datasheet view)
The results of the query will be displayed.
You also have the option of saving your query. To save the query, right-click on the query tab. click Save, and name it at the prompt.
Below are screenshots showing the above steps.
The Query Design Button
Click the Query Design button to create a query in Design view. You could also use the Query Wizard button next to it to launch the Query Wizard, however, Design view gives you more control over the query.
Tables to Include in the Query
The Show Table dialog allows you to choose which tables to include in the query. You can also include other queries to use within a query.
Query Design View
Query Design View allows you to specify the precise criteria for the query. You can choose which tables are shown in the results, which fields to use, add filtering criteria, and more.
The Run Button
Clicking the Run button will run the query. Clicking the Datasheet view button next to it will also run the query.
The Query Results
The query results are displayed in Datasheet view.
Saving the Query
Modifying the Query
You can go back and forth between Datasheet view and Design view to modify your query. Design view allows you to specify the exact criteria for your query.
For example, you might want the query to return only those products from a certain company. Or you might need a list of all users who have spent over a certain amount. The query Design view enables this and much more.
Design view allows you to add criteria with which to filter the results. Here, we’ve added criteria to filter the results to only those with a price over a certain amount (80000).
Only records with a value greater than $80,000 are returned. This is because we specified >80000 in the Criteria field.
More Options for the Query
You can extend your query further with options from the Ribbon. For example, clicking Totals will add a row into your query builder that will enable you to use the total sum of certain records.
The Ribbon contains further options for building your query, such as the Totals option.
Here’s how that affects the query designer:
Clicking Totals in the Ribbon adds a Totals record in the query designer. You can then specify how each field will use the total.
In this case, we use the Total option to display the sum of all purchases from a given customer, and to group each customer.
Query results. We now see that the last column is called “SumOfPrice” and displays the sum of all products purchased by that customer.
Benefits of Design View
You can also use the Query Wizard to build basic queries. This can be handy for beginners who don’t feel confident enough to create queries in Design view. However, Design view allows you to build more complex queries, as you can be very specific with your criteria.
Behind the scenes of each query, Access is generating SQL code. If you know how to code in SQL, you could build your queries in SQL. However, Design view enables you to build complex queries without needing to know SQL.
A Barnsley fern is a fractal named after British mathematician Michael Barnsley and can be created using an iterated function system (IFS).
Create this fractal fern, using the following transformations:
- ƒ1 (chosen 1% of the time)
- ƒ2 (chosen 85% of the time)
- ƒ3 (chosen 7% of the time)
- ƒ4 (chosen 7% of the time)
Starting position: x = 0, y = 0
ALGOL 68 [ edit ]
This program generates a PBM file.
Applesoft BASIC [ edit ]
BBC BASIC [ edit ]
C [ edit ]
This implementation requires the WinBGIm library. Iteration starts from (0,0) as required by the task however before plotting the point is translated and scaled as negative co-ordinates are not supported by the graphics window, scaling is necessary as otherwise the fern is tiny even for large iterations ( > 1000000).
C++ [ edit ]
C# [ edit ]
Common Lisp [ edit ]
This code uses the opticl package for generating an image and saving it as a PNG file.
Delphi [ edit ]
Hint: After putting a TPaintBox on the main form align it to alClient. Client width / height of the main form should be no less than 640 x 480.
EasyLang [ edit ]
Fōrmulæ [ edit ]
In this page you can see the solution of this task.
Fōrmulæ programs are not textual, visualization/edition of programs is done showing/manipulating structures but not text (more info). Moreover, there can be multiple visual representations of the same program. Even though it is possible to have textual representation —i.e. XML, JSON— they are intended for transportation effects more than visualization and edition.
The option to show Fōrmulæ programs and their results is showing images. Unfortunately images cannot be uploaded in Rosetta Code.
Building an Interactive IFS Editor
O, Thou hast damnable iteration; and art, indeed, able to corrupt a saint.
— William Shakespeare, Falstaff, Scene II
I’m a software engineer, working on distributed cloud application management software, but sometimes I like to take a break from that and write code that does something more, well, fun… To that end, I have been working on and off for the last few years on a fractal visualisation system.
I’d like to show off some of the parts I’m proud of, but also some that I think need improved or fixed. I will talk about the design and implementation, and the code that makes it work, and in the process explain why I think it’s useful to have a long-term project like this.
First, let me introduce the project. Iterator is a program that renders IFS fractals. These are Iterated Function Systems, a set of transforming functions that operate on the 2D plane and are repeatedly evaluated on a source image to produce a resulting fractal. The project itself is around five years old now, and I recently released version 1.5.0 and I would encourage you to download the distribution and play with the IFS Explorer. The codebase is just over 6000 lines (not including comments and blank lines) written in Java 8 with HTML documentation — also available as a PDF. If you configure your JVM to trust the GitHub server then an easy way to get started is to use the JNLP launcher.
Rendering an IFS fractal like the one above turns out to be possible as both a recursive series of evaluations or as a stochastic process known as the Chaos Game. My program uses the chaos game method, which is computationally less demanding and has scope for a broader range of visualisations. I have actually implemented an IFS renderer using the lisp-based macro language in AutoCAD, allowing an initial vector image to be copied, scaled, and transformed repeatedly. This is also known as the MRCM or Multiple-Reduction Copy-Machine method, and the PC I was running it on rapidly filled its 512 KiB memory after only a few iterations!
This is a technical article, but not a mathematical one. The references at the end of this article give more detailed explanations of IFS mathematics than I ever could, so I am not going to try and write yet another tutorial on how Sierpinski Triangles and Barnsley Ferns work — please use the same primary sources that I d >Computational Beauty of Nature, which covers not just Iterated Function Systems (in Chapter 7) but also a huge range of other interesting topics such as Cellular Automata or Neural Networks that will provide inspiration for your own projects.
The Iterator project started as a single application, IFS Explorer, which allows interactive creation and viewing of IFS fractals, and now includes a stand-alone image renderer and a scriptable animation creation application. These all use the same shared codebase and configuration mechanism, so I will mostly be describing the explorer application in depth, but will point out how the components are used in the other parts.
There are several other IFS applications available, and it is a popular choice as a computer graphics project at universities. I felt that the programs available d >IFS Explorer was designed as an easy to use application that would let anyone create Sierpinski gaskets or Barnsley Ferns just by clicking and dragging on screen with the mouse. This means my choice of language and framework was restricted to one with good 2D graphics and UI component APIs. I chose Java due to my familiarity with the language, having used it since its introduction in the early 90s. The Swing and AWT toolkits are getting a little old, but are simple to use and provide broad platform support. The Java 2D drawing APIs are not as complex or featured as OpenGL, Core Graphics or DirectX but they provide the usual range of primitives including affine transforms, which is sufficient for this application.
The basic functions used in an IFS are affine transforms, which map a point on the plane to another point reversible, after scaling, rotating, skewing, translating or flipping it. Because the affine transform objects are already provided by the Java APIs, I did not need to re-implement the matrix mathematics required for an IFS, which helped immensely getting started. The next choice was whether to use Swing, AWT, JavaFX or perhaps Eclipse SWT as the UI component API. In this instance, Swing seemed the best choice. It is tightly integrated with Java 2D, I have a reasonable amount of experience with it already, and it provides a good cross-platform experience. JavaFX would perhaps be a nice alternative, but it is lacking some of the OSX integration present in Swing, and AWT is generally too primitive and ugly. Eclipse SWT, while powerful, is much more difficult to use, and I have never developed a large application using it. Finally, I wanted to use a minimum of external libraries, so chose Google Guava as a useful utility toolkit, but stopped short of dependency injection frameworks or other tools. Initially I used the 1.7.0 JVM but recently changed to Java 8, to make full use of the latest language features.
So, having run git init iterator in my terminal window, I then had to create the >IFS Renderer high resolution single image creator and the IFS Animator scripted animation tool which renders frames showing manipulations of the individual transforms in an IFS based on a DSL describing the changes. The views also include a display of the underlying matrices making up the IFS and editing dialogs for the transforms and the application configuration properties. Configuration is seen as part of the controller, but is decoupled from the user interaction components.
In the explorer application there is an additional part to the controller, the Google Guava EventBus. This is used to pass the model state (i.e. the IFS data) between the controller and the views when the user makes changes. The Guava eventbus is a simple, in-memory pub-sub queue system. The view and controller components register as subscribers to the model data. When a view component is finished editing it publishes the updated model and the rest of the application can then reconfigure and redisplay as appropriate. The diagram below shows some of the interconnections between classes.
The MVC architecture lends itself to encapsulation and has very well defined points of contact between components. It is very common for both desktop and web applications, and in fact the Iterator components as they stand could easily be reused in a web application with a browser based UI running in an HTML5 canvas, with the rendering being done by a REST API driven service using the same mechanism as the IFS Renderer application. In a future release I will probably implement something along these lines. This illustrates the fact that the project is a work in progress, and allows me to learn and build software spanning multiple disciplines, giving me more depth of experience than my day-to-day work. This is an important part of working on a side project. Additionally, it gives insight into the entire project lifecycle, from design to release management and documentation. This should improve your skillset and help you in your regular work.
The actual implementation of IFS Explorer proceeded fairly straightforwardly to begin with, and I concentrated on writing the basics of a user interface to edit the IFS transforms. Although the fact that the Java 2D APIs included an AffineTransform class precluded having to write a matrix manipulation library, the 2D geometry aspect of the code is still very much in evidence. In this section I will illustrate some of the code that performs these actions.
The initial setup of the MVC architecture using the EventBus >iterator.util.Subscriber interface. This had two methods whose implementation would be annotated with @Subscribe and the whole >bus.register(this) during construction.
Now, when the editor makes a change to the IFS object, it can call bus.post(ifs) and all registered subscribers will receive a call to their updated(ifs) method and can perform the appropriate actions. This allowed building an MVC application without worrying about composition or coupling of components, since all communication is mediated through the event bus with a minimum of configuration.
This architecture handles changes to the model, but there is more to rendering an IFS than simply the list of affine transforms. While the event bus is ideal for propagating live changes to the model, there is also a requirement to be able to update and apply changes to configuration properties like the rendering style such as from grayscale to colour, or to change the maximum number of threads in the rendering pool.
I required a configuration mechanism that would allow key/value pairs to be set, with varying types for the value, and loaded from files on disk. The .properties format is >Properties object as part of its core APIs.
The property keys and values can be represented in-memory as a Map with getters and setters prov >ForwardingMap interface that the main iterator.util.Config >put(key, value) and get(key) operations to an internal field. Loading is performed by the Properties object and saving involves a simple loop to iterate through the keys, writing them and their values to a file in the correct format. The values are generally assumed to be either the boxed forms of primitives, Strings or enumerations. There is a cast(value, type) method that handles conversions from String to the required type, although some setter methods also perform conversions, such as those handling colours. The setGradientStart() method is seen below, obtaining the RGBA value as an integer representing only RGB and then converting it to a hex string. The cast() method has an else clause that decodes these hex strings back to an integer and then a Java Color object.
The configuration object is important as a part of the controller, as it prov >IFS Renderer and IFS Animator applications this is the only extra >IFS Explorer application also provides a view onto the configuration, via a dialog that presents current values and will allow them to be changed and updated.
The configuration dialog, implemented as the iterator.dialog.Preferences >iterator.util.Dialog > interface which is both AutoCloseable and a Supplier of the dialog object. You can see that the get() method of the supplier interface simply returns the dialog, and the static show() method uses both this and the abstract showDialog() method to display the dialog and handle exceptions with optional consumers of Throwable .
This is implemented as an abstract base >iterator.util.AbstractPropertyDialog which extends the Swing JDialog >AbstractFormatter >iterator.util.Formatter >BaseFormatter version that is implemented for various different objects such as DoubleFormatter and OptionalIntegerFormatter and is used throughout the application where numbers need to be displayed as Strings in a consistent fashion.
When a typed field is added to a dialog, it must be possible to set and to retrieve its value, and the methods for doing this are inconsistent across the various Swing components for text fields, drop-down menus and numeric spinners. The Property >Supplier interface, and as can be seen in the code for the Preferences dialog each field has an associated property object.
These objects are in fact returned by the various calls to add the UI components representing the fields, as the dialog is constructed. There are no concrete implementations of the Property interface, rather an anonymous inner >attach(field) static method in the interface, which is overloaded for each type of component used.
After editing the properties in a dialog and clicking the button to accept the changes, the dialog handler will call the get() method on each Property object and then call the appropriate setter method on the Config object. This transfers the changes to the shared configuration map, and the views can be alerted to update their display.
The gradient fill property is an interesting special case, which required several anonymous helper >addGradientPicker(string) was added to create the field. This used an anonymous extension of the JButton >paint() method to display the gradient fill as it would appear, and a new Pair tuple >Color objects representing the start and end colours of the gradient. Rather than having the button perform an Action when clicked, an extension of the MouseAdapter >mouseClicked(event) method and added as a listener. This >JColorChooser for either the start or end colour.
Although the Swing colour chooser dialog is customisable, the provided mechanisms are not particularly helpful.
Setting the preview panel to an empty JPanel was required to remove the existing preview, since setting it to null had no effect. The filtering of the chooser panels to determine which was the swatch picker, and then remove it, is necessary because there is no way to instantiate a new set of chooser panels, nor is it possible to modify the array of panels in-place.
The end result is an intuitive and visually attractive way of displaying and editing a gradient fill.
The actual display of the IFS is one of the most interesting parts of this project. It involves some maths, although not incredibly complicated or advanced, mostly a basic understanding of geometry and trigonometry. Initially, the implementation was single-threaded, but the current versions use a multi-threaded approach to gain more performance. This required a good understanding of concurrency and the available tools and primitives provided by Java, and also Guava.
For example, the points being iterated must be accessible by all the threads performing the iteration calculations. I eventually settled on an atomic reference to an array of Point2D objects, available as the AtomicReferenceArray >updateAndGet(i, updateFunction) to evaluate the application of the transform on a point and atomically set the result and return it. The second version instead returns the original point before performing the update.
This enables multiple threads to execute their application of a (randomly chosen) transform concurrently, without worrying about issues like the X value being set by thread A and the Y value by thread B causing problems and generating incorrect images. Relying on these implementation provided primitives meant that I did not worry so much about correctness, and could trust they would do the right thing. However, managing multiple threads was still an issue, and not something that the JDK made simple.
The problem is to ensure that a pool of N threads can execute concurrently, and will all stop when required as well as being able to increase and decrease the pool size, even while the iteration process is running. Executing a thread will return a Future which can be cancelled, but this is not as useful as it sounds. In fact, I had to design the tasks that would execute concurrently to respond to separate stop signals for indiv >AtomicBoolean latches, one for each thread, that would be checked periodically at the same time as checking for a global stop signal.
As you can see here, the tasks (a Runnable object, which was implemented as a lambda) wait on a latch object to ensure they start at the correct time, then obtain a token value which is an AtomicLong that is used to halt all threads if its value changes. The threads have their Future objects stored according to the task type in the tasks Multimap and the AtomicBoolean cancel objects are stored in the state map, linking them to the futures for their threads. This is used to stop an indiv >AtomicBoolean to true.
All of the concurrency mechanics are encapsulated in the iterator.view.Iterator >Config and IFS objects to execute. It will generate a BufferedImage Java 2D object containing the rendered IFS image. This means that both Swing applications and headless console mode applications can use it to generate images. Additionally, it is not necessary to always execute the image generation tasks concurrently. The iterate() method is public, and the Editor view of IFS Explorer uses this to produce a live view of the IFS while it is being edited.
Looking at the code, you will see that the minimum number of threads is two, yet the editor view executes a single iterator task. This is because there are actually two types of task.
For rendering modes that use a density estimation mechanism, the iterator tasks do not change the BufferedImage pixel, rather they update an array of density values. The second type of task, PLOT_DENSITY , then iterates over that array and sets the pixels in the image appropriately. So for N threads running the LOG_DENSITY_FLAME_INVERSE rendering mode there are actually N-1 tasks of type ITERATE and one PLOT_DENSITY task. Later I will go into much more detail regarding the plotting and iteration mechanisms, and the modes and configuration available.
A non-obvious problem in the display routines was the plotting of gr >N pixels, similarly for vertical lines. What is more complex is doing this for a viewport onto the unit square, which may be centered anywhere and have either positive or negative magnification. Obviously the gr >(0,0) if they appear. The simplistic approach, which I tried first, of iterating from a very negative to a very positive number and only drawing the line if it intersects the viewport (using line.intersects(rectangle) in the Java 2D API) quickly eats up the available CPU at high magnification.
Instead you must calculate how many multiples of the grid spacing are present from the origin to the left margin and then what the remainder or offset is to the first visible line. This code took many tries to get correct, and required essentially empirical checks of where the grid-lines intersected a part of the fractal, and verifying that this remained consistent across magnification and reduction and changes of viewport. The complete algorithm is shown below, although it works as expected, I believe that some simplification is certainly possible.
The IFS model is fairly simple, needing only to hold the lists of transforms with the parameters for each affine transform. The model also contains the name of the IFS (used as the window title) and the window size, which is required because the transforms are defined in terms of screen space pixels and therefore must be resized for rendering at different output resolutions. I decided to use JAXB (Java API for XML Binding) annotations on the model classes, allowing them to be saved as XML files without needing any additional libraries, since JAXB is part of the JDK.
The XML is saved and loaded by creating a JAXBContext for the model and using that to create Marshaller or Unmarshaller JAXB objects. Once any configuration properties have been set, such as for pretty-printing the XML, it is a simple matter to call the marshaller.marshal(jaxbElement, writer) to output the XML. In future releases I may change this to support JSON formatted model data instead, using the Google GSON library which is also annotation based and has equally simple marshalling and unmarshalling methods. The only problem with this change would be maintaining backwards compatibility with older XML saved models, and it may end up being necessary to simply support both formats.
The IFS >Comparator implementations, one to sort the transforms by z-order for help when selecting overlapping transforms in the editor view, and one to sort any type of Function by id . These are defined as lambdas, with the IFS.Z_ORDER comparison using the Guava ComparisonChain builder, which is a very simple but effective way of building complex comparators, although in this case used for a single check.
There are two parts to the model, the IFS parent >Transform and Reflection objects, and the CoordinateTransform enumeration which represents functions to be applied after each transform or reflection that will modify the coordinates in some way. All three of these implement the iterator.model.Function interface which is also a UnaryOperator
that operates on Java 2D points. This allows the functions to be easily composed, as was seen earlier when looking at how the AtomicReferenceArray of points was updated.
Although the function interface has a getTransform() method returning an AffineTransform , this is only used in the default implementation of the apply(src) method of the operator interface. The coordinate transforms throw an UnsupportedOperationException instead, and implement the apply(src) method directly with their particular transformation.
This example is from the iterator.model.functions.Spherical >Fractal Flame paper and their id field is the variation number used in its appendix, where they are defined. Not all the variations are implemented, since some of them use coefficients from the previous affine transform matrix as input to the function, and this would prevent me from implementing them as operators and introduced too much complexity. However, in the future this may be an interesting addition.
The Chaos Game implementation involves maintaining a record of a point in the (X,Y) plane, and repeatedly choosing at random one of the transforms in the IFS model. The transform is then applied to the point, followed by the application of the coordinate transform. Note that there is an >stealing if the file used is an image or photograph, or using a file containing a gradient fill generated from the config.getGradientStart() and config.getGradientEnd() colours) or by mapping to a point in HSV colour space, known as ifs-colour mode.
The Task.ITERATE threads simply execute the iteration repeatedly and if the mode does not involve density estimation, they plot a point in the required colour after each iteration. I perform colour correction and scaling in the HSB space, after converting from RGB, since this allows more useful control of the result. The unity() and octet() methods each return a function that clamps its input to a value in the range [0.0,1.0] or [0,255] respectively. Note that variables like hsb and rect are not defined here. This is because they are used in the m >rect variable is used because I want to set some (X,Y) point to the required colour, but Java2D does not have the concept of a point as a displayable object. Instead, I use a one-by-one pixel sized rectangle, and fill it with the chosen colour, or for the live view of the IFS a two-pixel wide rectangle.
For the density estimation rendering modes, the Task.ITERATE threads simply carry out the iterations and update a series of arrays containing the density and the colour of points. The generation of the image is handled by the Task.PLOT_DENSITY thread. The density array is updated by incrementing its elements at each iteration, with the array index being calculated from the 2D coordinates. Because the process can involve a very large number of iterations, there is a danger of these density values overflowing, especially when using the Render.LOG_DENSITY_POWER rendering mode that not only increments, but then multiplies the density value to increase it by 1%. Fortunately Guava prov >LongMath.checkedAdd(a, b) method, which throws an ArithmeticException on overflow. This means I do not need to perform checks for negative values. Interestingly, the multiplication does not use this method, instead I convert the long to a double, perform the multiplication, and use Math.min(a, Long.MAX_VALUE) to clamp the result.
I will only show part of the plotDensity() method that performs the work for the Task.PLOT_DENSITY thread here. This code extracts RGB byte values for a particular point, using bitmasks, and then either scales them by a fixed ratio or uses the logarithm of the density at that point to perform colour scaling. This is based on >Render.LOG_DENSITY_FLAME . Note that for the inverse mode we can simply subtract the calculated ratio from one. Here we also see how the gamma quantity is used, as the exponent in a call to Math.pow(a, b) , to modify the ratio. After scaling the RGB values the colour is converted to HSB space and the brightness component is rescaled and the value component replaced by the calculated density ratio, and the same range clamping is applied as described above.
The colour manipulation code is probably the most important in terms of how the final rendered image appears, and small changes here can have large effects on the output. Unfortunately, the code is more complex than I would like, since it has to deal with conversions between double, float and long that obscure the intent of some calculations. There are definitely still issues present, and more eyes reviewing it would help immensely. For example, colours saturate to white or black too easily and alpha blending sometimes does not operate as desired, causing dithering and artifacts. Any new configuration parameter that affects the output will have to be checked and used here, which requires careful though as these methods are the hottest part of the code and adverse performance impacts would be easily created. I think that this is one of the most interesting parts of the codebase, however, and it is always enjoyable adding a new feature or tweaking a parameter and seeing the visual effects that produces.
Next, I would like to show how the Java 2D graphics APIs were used to display the IFS rendering on screen.
This code encapsulates performing some action using a Graphics2D context object, obtained from a passed in Graphics context and then disposed of after use. This pattern repeats many times in the code, with the graphics context coming from various places, perhaps a Swing component or a BufferedImage object. The action performed is passed in as a lambda, taking the Graphics2D context object as its argument. The exception handler implementing BiConsumer
For example, here is how a new BufferedImage is filled with a particular colour.
And, during startup, I wanted to use a splash screen with the current version number displayed but without having to create a new bitmap image for each release. The -splash:./lib/splash.png option to the java executable (or SplashScreen-Image in the manifest file of a Jar) allows an image file to be loaded as a splash screen, and I use a PNG with a composite of the editor and viewer displays for this. Java allows access to this image with the SplashScreen.getSplashScreen() method, and the graphics context for the image can then be obtained. I use the same image and text overlay in the About dialog box, so it was simple to extract the code to add the text overlay to a method that accepts a Graphics2D context and re-use it during startup.
The most complex part of the image rendering for the IFS Explorer is actually the interactive editor view. The non-interactive viewer (and the IFS Renderer application) simply execute the iterate() method repeatedly, stopping after some number of iterations if configured, and copy the results from a BufferedImage to either a Swing component or writing to a PNG file. The editor must repeatedly render the IFS based on the current values of the transforms being modified. This is done using a Swing Timer that fires and executes an actionPerformed(event) method every 100ms to repaint the viewport. User interaction updates the properties of the Transform object until the mouse is released, then the transform is added to the IFS list of transforms and the model is pushed out to the eventbus by the controller.
The editing actions are intended to be reasonably intuitive and obvious for anyone who has ever used a paint ot vector graphics editing application. The transforms are displayed as rectangle outlines showing the result of applying their affine transform to a unit square, with grab handles at the corners for resizing and a circular handle at the top centre for rotation. Additionally the keyboard arrow keys can be used for movement, and on OSX trackpad gestures can be used to rotate and resize the transforms.
The resize action performed by dragging a corner of a transform must operate on all four corners, and if shift is held down must maintain the current aspect ratio. This needs to work correctly on rotated and sheared transforms, and to show that resize is possible the cursor should change when the mouse is moved over one of the resize handles. To do this, a Corner enumeration was created to represent the four compass directions Corner.NW , Corner.NE etc.
This represents the X and Y coordinates of the corners of a unit square, and the appropriate Swing cursor to use. The cursor displayed is not necessarily the same as the >X component, then their Y component with the leftmost and topmost corner showing the Cursor.NW_RESIZE_CURSOR cursor and so on. It is simple enough to determine if the mouse is over a corner by transforming the point at the corner of a unit square with the affine transform and determining if a box centered on that new point contains the mouse location.
More complex is the code to dec >X and Y coordinates) of the transform or the size (the W and H values) and this must be done in the rotated and sheared reference frame of the transform. To help with this, unit vectors in the X and Y directions are inverse transformed, and their indiv >X and Y components are then used to calculate the changes to the transform. The case statement below implements this logic, with checks for e.isShiftDown() being used to maintain a fixed aspect-ratio.
The third view component of the IFS Explorer application is probably the simplest. It generates a display of the matrix coefficients for the IFS transforms, and the properties of the reflections. The iterator.view.Details >JTextPane component and uses an HTMLEditorKit with MIME type text/html to display its content. The content is created as CSS and HTML Strings which are then parsed by the Swing editor kit and displayed.
Notice that the CSS rules are split into two groups. The CSS_BRACKET_RULES collection are re-used in the dialog box for editing the matrix coefficients of an affine transform. This dialog is structured to look like a matrix displayed in a textbook, with square brackets on either s >div .
One of the hardest things to implement in the UI turned out to be printing. The Swing printing mechanism is very sparsely documented, and there are multiple techniques possible. I wanted to allow users to print both the Viewer and Details components, and the first step is to implement the Printable interface and its print(graphics) method. The easiest printing mechanism to use was that prov >PrinterJob >Printable component has been registered along with a PageFormat to use, the job.printDialog() method can be called. This will display the native operating system print dialog, and on successful return the job.print() method can be called to actually print the page. Unfortunately beyond being able to set the print job name, I was unable to work out how to accomplish tasks like setting a header or footer on the page. The printing code is called from a menu action, and is written as a lambda that is passed to the pauseViewer(action) method that will halt the iteration tasks if they are running, and restart them after the lambda has completed.
One aspect of the application that I wanted to ensure was cross-platform support. This is fairly straightforward with Java, since the compiled Jar files will run anywhere with a JVM implementation. However I also wanted to make the UI look-and-feel compatible with the different native platforms. I use a MacBook Pro as my daily work laptop, so most of the customisation has been for OSX, with Windows and Linux being left using standard Swing components for now. Some of the platform customisation happens in the launcher scripts, which are prov > ./bin directory of the distribution archive. There are three versions; for IFS Explorer they are explorer.cmd for Windows explorer.sh for Linux and explorer.command for OSX.
Additionally I added a dependency on the orange-extensions library for compilation, which prov >iterator.AppleSupport >Quit, About and Preferences… menu items which are provided by OSX, and in the UI set-up code these are only created explicitly on other platforms. This library also enables gesture support, which I use for rotation and magnification of transforms in the editor view. This turned out to be surprisingly simple to achieve, and the effect is that of a well-integrated native application.
I hope this journey through the codebase has been interesting, and perhaps also useful. If you want to explore the code on GitHub please do, I would be more than happy to review pull requests and fix any issues discovered.
So, what have I accomplished, and what else can be done? IFS Explorer achieved the goal of making an easy-to-use fractal creation and viewing application, allowing me to explore and generate a w >Fractal Flame paper was an interesting exercise in translating equations from a scientific paper into working code, and the resulting images generated by the new feature were well worth the effort. Similarly, the work expended in writing the density estimation and colour management routines was paid back in exceptional and vivid fractals. I found that the simplicity of the editing interface encouraged prolonged intuitive exploration, meaning that images can be designed and iterated on quickly until something suitably eye-catching is arrived at.
The additional programs were made possible by the modular nature of the code and the decision to use the MVC architecture. IFS Renderer, in combination with the ability to save and reuse the entire configuration, makes it possible to generate high-resolution renderings of particular fractals. I hope to use this to create large poster-sized prints of my favourite images. IFS Animator has not proved as useful, but it is able to produce pleasing scripted animations of fractals. This application could do with more work, in particular a graphical user interface to design the animations, since writing the script file for the required changes can be tedious. It would also be good to generate the movie files directly using something like JMF (the Java Media Framework) or one of the Java implementations of ffmpeg, rather than outputting thousands of PNG files.
Another interesting project to work on, but one that would be much more complex, is that of extending the IFS rendering to three dimensions. Affine transforms can be easily extended to 3D by increasing the size of the matrix, and Java has 3D APIs, so the framework for rendering should be straightforward enough. The complexity arises when you think about the user interface. Extending the concept used in IFS Explorer, we would need the ability to manipulate a transformed unit cube in space, with at least six degrees of freedom. Probably this would require virtual reality or some other 3D display interface to be really intuitive and usable.
For version 2.0.0 of Iterator I would like to at implement least some of the above improvements to IFS Animator, and also to continue working on the rendering modes for IFS Explorer. Perhaps not moving to 3D, as that would better suit a completely new application, however there are plenty of variations of the coordinate transform function left to implement. As noted, the multi-threaded performance could probably be improved, perhaps using some JNI library to take advantage of Intel CPU vector instructions.
The documentation is another area that needs more work, starting with a description of the animation DSL and also more details of the different rendering modes and transforms with graphical examples of each. The code itself should also be documented, with the JavaDoc output being included in the documentation website. Finally it would be good to make it easier for users to run the applications and this requires some work on the code signing for the JNLP launcher. A Docker image that runs the Linux version of IFS Explorer over VNC would also make it simple to get started.
What do I think I have learned from this multi-year project? An important take-away is that it has been fun. I don’t think I would have been able to sustain interest in a project for so long unless it was enjoyable. Secondly, the rendered IFS images are visually stunning in many cases, and the ability to explore the space of possibilities interactively is an enjoyable and interesting process. I have also learned a lot about Java Swing and the Java 2D APIs for creating desktop applications, which has been an interesting change from my day job dealing with web services and applications. The concurrency issues have helped me think constructively about multi-threaded performance, which is a useful skill to have. And the exercise of mathematical skills that had grown very rusty since undergraduate classes at University has helped keep them up-to-date and accessible at work.
I still have some concerns and questions about the performance and the correctness of the multi-threaded code. For example, what are the consequences of the shared state being accessed (such as the density array) by multiple threads? Is it really necessary for the thread cancellation checks to use an AtomicBoolean or would a primitive boolean have sufficed? Could use of locking or private ThreadLocal state help speed things up? What about using multiple BufferedImage objects, one per thread, and compositing them together for display?
One thing I think I should have worked harder on in this application is testing. Many times I have implemented changes, only to see the output of the rendered IFS looking completely broken and wrong. The lack of unit tests is partly due to the difficulty of testing a Swing UI, but I expect that indiv >Robot would probably help.
I would definitely recommend starting your own side project like Iterator. Find something that looks fun and engaging and dive in. Applications that generate pretty pictures or produce some other kind of interesting output are probably the best choice, particularly if, like Iterated Function Systems, it is easy to get started and produce something but there is also a huge expanse of complexity and nuance to explore.
As a simpler first step, have a look at the Iterator codebase on GitHub and perhaps think about implementing one of the features I discuss above, or fixing one of the many bugs that are still present. I would be happy to review pull requests and respond to issues. The important thing is to do something that interests you.
The following Wikipedia links , papers and books give more background on Iterated Function Systems and their mathematics and implementation. In particular, the Draves and Reckase paper on the Fractal Flame algorithm was very useful for inspiration when implementing rendering modes. The Barnsley book is the >Stealing rendering modes.
RPGPGM.COM — From AS400 to IBM i
Advice about programming, operations, communications, and anything else I can think of
This blog is about IBM i for PowerSystems
Wednesday, September 24, 2014
How to map an IFS folder as a Windows share folder
After reading the post Easy way to convert CSV file to DDS file Martin Coates emailed me with the following question:
How do you map a folder in the IFS and share is on the pc? I am an As400 “purist” but more and more I find programming requests overflowing into the pc domain.
In this post I will discuss how to create a folder in the IFS, and then how to share it as a folder that can be accessed by a Windows PC. If you already know how to create folders in the IFS feel free to skip to the second part.
How to create a folder in the IFS
I can create folders using either the Operations Navigator or the browser based IBM Navigator for i.
In this example I am going to create folder called simonh, which is a subfolder within the folder users. In other words the path for the folder will be:
Note: You can click on any of the images below to see a bigger version of them.
Creating a folder using the Operations Navigator
I open the Operations Navigator, and I select the IBM i I want to create the folder on.
I click on the + (plus sign) next to File Systems.
Then I click on the + next to Integrated File System.
I riight click on the Root, and select New Folder.
In the pop-up windows, shown on the right, I am going to enter:
- New folder name: /user/simon
- Audit objects created in folder: None. I use «None» as I do not want to cause an audit entry to be sent to the auditing journal whenever this folder is used.
- Scan objects created in folder: No. I do not want any files created in this folder to be scanned by the scan-releated exit program.
- Restrict rename and unlink: Unchecked.
When I have entered and changed what I want I click on the OK button and the subfolder simonh is created in the users folder.
Creating a folder using the IBM Navigator for i
I log into the IBM Navigator for i for the IBM i I want to create the folder on.
In the menu on the right I find Files Systems and click on the + next to it.
Under the Integrated File Systems heading I click on the Create Integrated File System Folder link, see above.
I do not enter the path name here, above, I click on the Browse button. I have found it is easier to select the folder, users, and add the subfolder there.
When I have found the users folder I click on it. Then I click on the add icon, circled in red, to create my subfolder, see above.
I enter the subfolder name in the Folder Name box, see above, and click the OK button.
And the subfolder is created, see above.
How to share the IFS folder
Having created the subfolder simonh I need to share it. This will make it available to my Windows PC.
Sharing using Operations Navigator
I find the folder users, and click on the + next to it to see the subfolder simonh. I right click on simonh and select Sharing, see below.
I enter a share name, SimonH, and changed the access to Read/Write.
Finally I click the OK button and I am done.
Sharing using IBM Navigator for i
In the menu on the right I find File Systems and click on the + next to it, and then I click on the Create File Share link, see below.
I enter a share name, SimonH, changed the access to Read/Write, and in the Path Name I enter the path /users/simonh, see below.
When I am done I click the OK button.
How to map the folder to the Windows PC
Now to map the IFS folder I can do it one of two ways:
- Manually map a drive to IFS folder using Windows Explorer
- Using a batch file (program) to map a drive to IFS folder
When I map to an IFS folder I only do so when I need to as there is no point in wasting time when booting up my Windows PC to map the drive to the IFS folder that I might not use today.
Manually map a drive to IFS folder using Windows Explorer
I am sure many of you already have drives mapped to folders on various servers and this is no different. In the Windows Explorer I click on Tools on the menu bar and select Map network drive.
The dialog box above is displayed. I choose a drive letter that is not being used.
For the Folder I enter the path to the IFS folder. Which would be:
I would, of course, replace my-ibmi with the name of my IBM i.
As I said above I always make sure that the Reconnect at logon is unchecked.
My Windows login and IBM i signon and passwords are different so I check the Connect using different credentials.
Then I click on the Finish button, and the Enter Network Password dialog appears, see below.
This is where I enter my IBM i user name and password. I never check the Remember my credentials. When finished I click the OK button.
Voila! I now have a Z: drive which is mapped to my IFS folder.
Using a batch file (program) to map drive to IFS folder
Rather than perform this mapping manually every time I want to use the folder I will create a batch file (program) to do the same thing. It would look like:
I would replace my-ibmi with the name of my IBM i.
Hey presto! I now have drive Z: mapped to my IFS folder.
So why do I use the pause in the batch file? If there is a problem with connecting to the IBM i or mapping to the IFS folder I will see the message. If it is missing the batch file will complete and I will be none the wiser to why I am not mapped to Z:
This article was written for IBM i 7.1, and it should work with earlier releases too.
How to create the ifs fern
IFS (Iterated Function Systems) produce some of the best known fractal images, like the famous Berensley fern. They have been used for image compression, but more frequently just as a method to build the fractal images since the 80s. There are many software packages that can render IFS fractals in many of their variations, like the Flames.
I made my first IFS images back in 1998 in basic, but later on I wrote a simple C program that could render high resolution images, like these ones below, that where in fact computed at 6000×9000 pixels with 2×2 antialias (12000×18000 effective sampling points). One of them made it into the finals of a fractal image contest, and the other one was used as background for a cover of a book, but that’s another story.
Really understanding the maths of IFS is not that easy, but implementing it is amazingly simple. The images are the attractors of the actual IFS. The functions are just linear functions, affine transformation T if you want, that take a point p and transform it into p’ with rotation, skew and scale factor A and a translation B:
p’ = T(p) = Ap + B that can also be written as
When applying T to all the points of a plane (an image if you want) this gets expanded or contracted, and that contraction factor is just the determinant of A (since the transformations are linear), as usual.
contraction = |A| = ad — bc
For rendering all the IFS images in this site I only used four such transformations, but you can choose any number. We will be applying these transformations to points in the plane, and assuming the overall transformation is contracting, the iterative process will makes the complete plane converge to a given set, the final image. The geometry of this set, the attractor of the IFS, is usually fractal, even if the transformations are linear, but that’s out of the scope of this little article.
The iterations happened like this: choose a random point in the plane, one of the four transformations at random, and apply it. This gives a new point. Now, pick again one of the four transformations at random, and apply it again. Repeat, few thousand millions of times.
This will give an «orbit» for that very first starting point we chose. The chaos game theory ensures that if the average contraction factor is less than that one, we will get not a random point cloud neither an exploding orbit, but an well defined shape, the attractor.
Well, for this to be true, the chaos theory and symbolic dynamic mathematics say that you must randomly choose the transformation from the transformation set of the IFS. This way, the orbit densely overlaps the attractor. In the other hand, to allow the chaos game converge faster, it is better not to randomly select a transformation from the transformation set of the IFS, but with a probability propotional to the area covered by this transformation over the total area of all the transformations:
To make things more interesting, it is also possible not to only record the attractor, but also the density of the attractor. This can be interpreted as the probability of the iteration to step at a given point across the orbit. After selecting the probabilities according to the equation above, this density over the attractor should be quite smooth.
Finally, a bit more interesting images can be created if other transformations can be applied before accumulating the orbit on the plane. It is important to note that to keep the chaos game unaltered, this transformations must be done out of the iteration feedback loop. To create these images, a simple rotating transformation was applied, in which the rotating angle was proportional to the signed horizontal distance from the point to the origin.
Additionaly, a sinousoidal component was added to this angle, that changed each iteration.
Adjusting the frequency and amplitude of this sinusoidal component, the thickness and intensity of the «arcs» on the picture can be adjusted. Without this variation, the arcs would become just «threads».
The following images below were created by randomly choosing the transformation functions (you can click on them to see a higher resolution version):
I wrote a small application that randomly created thousands of IFS images. To quickly discard those transformations creating disperse attractors, the application only used those random transformations with a contracting coefficient smaller than 1.5. These images where, of course, low-resolution and low quality (low number of iterations). The very first two images in this page were created by choosing from this collection of random images.
For example, to make the first image, I chose one of the random images I liked, and worked on it. It’s color was decomposed in the hue and his intensity. As explained, the iterative process does not just show the attractor, but its density. So, for the color intensity, the density of the attractor was chosen. In fact, it is the square root of the density normalized to the maximum/minimum value over the image. The square root was not chosen for any mathematical reason; it was just used to adjust the contrast of the image in the image-synthesis part (where the colors are kept in floating point), to avoid crappy manipulation in Photoshop using 8 bit precision.
The color was a bit more complicated to create. Actually, it stores important information about the dynamics happening on the attractor: each point in the attractor is accessed from another given point of the attractor by the application of one of the transformations used, his «preimage» (if these transformations overlap, there is more than one preimages exist). In other words, each point in the attractor can be identified by the symbolic sequence of transformations used to get that point from the original one. This sequence is called the «address». This address, expressed in the correct base (four in my case, because I selected four transformations), defines a number between 0 and 1. The coloring of this images was done based on that number. Each new point on the orbit generated a color based on his actual address, and the color was accumulated on the plane using a 5%-95% blending with the previously accumulated color. This is how many applications out there produce the Flame images.
This color was multiplied by the previously explained intensity value to get the final color. To get a color based on the address of a point, a sinusoidal function was used for each color component (red, green and blue):
red = 0.4 + 0.25*sin( 0.5 + address )
green = 0.6 + 0.25*sin( 0.9 + address )
blue = 0.7 + 0.25*sin( 1.3 + address )
This color was desaturated in a 30% (mixed with his grey-level version). Finally, a «glowing» postprocess effect was done to enrich the visual quality. This effect is responsible for the light emission effect on some parts of the image (the brighter ones). To get it, the image was low-pass filtered (a gaussian filter) and added back to the original image in a 50% proportion.
Details of extension .ifs
2 extension(s) and 0 alias(es) in our database
Below, you can find answers to the following questions:
- What is the .ifs file?
- Which program can create the .ifs file?
- Where can you find a description of the .ifs format?
- What can convert .ifs files to a different format?
- Which MIME-type is associated with the .ifs extension?
FractInt IFS File
Other types of files may also use the .ifs file extension. If you have helpful information about .ifs extension, write to us!
Is it possible that the filename extension is misspelled?
We found the following similar extensions in our database:
The .ifs filename extension is often given incorrectly!
According to the searches on our site, these misspellings were the most common in the past year:
Can’t open a .ifs file?
If you want to open a .ifs file on your computer, you just need to have the appropriate program installed. If the .ifs association isn’t set correctly, you may receive the following error message:
Windows can’t open this file:
To open this file, Windows needs to know what program you want to use to open it. Windows can go online to look it up automatically, or you can manually select from a list of programs that are installed on your computer.
To change file associations:
- Right-click a file with the extension whose association you want to change, and then click Open With.
- In the Open With dialog box, click the program whith which you want the file to open, or click Browse to locate the program that you want.
- Select the Always use the selected program to open this kind of file check box.
Supported operating systems
Windows Server 2003/2008/2012/2020, Windows 7, Windows 8, Windows 10, Linux, FreeBSD, NetBSD, OpenBSD, Mac OS X, iOS, Android