Friday, January 17, 2020

Fractal Friday 2020.01.17

This week's images again come from some experiments with new features for MathPaint, the flagship software app I'm working on.

Previously I posted some experiments with edge rendering in fractal geometry, where only the boundary between levels of output are drawn. It shows the boundary between iteration levels but does not indicate the level itself (which is normally shown by a color gradient value).

This week's experiment takes a different approach to interpreting iteration values, which are integers in a fairly small range (usually 1 to 100 or at most a few hundred). Rather than render the level as a color, we convert it to a size - and draw a shape centered at the point, at the indicated size. Higher iterations create bigger shapes, quick iteration boundaries create very small shapes. We use a sparser grid (only evaluating one of ever five, eight, or 10 pixels - the setting can be adjusted). The idea is similar to an alternate vector field rendering which was explored in this blog.

Here's the familiar Mandelbrot set, rendered with squares drawn at sizes corresponding to iteration levels:


I like the rather stark, structured aesthetic that the squares lend to the shape. A bit more lively is this Julia set zoom, drawn with the same square shapes (and a different line color):


Different shapes can change the character of the rendered images. Here's a z^5 julia set (one of my favorite forms) rendered with circles, drawn with a 2-point line:


And a zoom in on the same image, with background and foreground colors changed - I like this as an abstract image that isn't recognizably a fractal, but the underlying math gives subtle organic pattern to parts of it:


Finally here is a regular Julia set rendered with 45° diagonal lines, first zoomed in, then zoomed back out with thinner lines:



More MathPaint screenshots and mathematical art coming next week! You can follow Mathaesthetics on FacebookTwitterInstagram, and Pinterest.

Wednesday, January 15, 2020

Hello World, from MathPaint! (Preview)

If you've been following Mathaesthetics posts you've seen a variety of images shared - different types of generated art from fractals to repeated 2D plots to vector fields and scalar fields and more.

All images on this blog are created by our flagship software product, which has been in development since November 2019. Today for the first time I'm publicly sharing some screenshots of the user-interface, starting with a few document windows:

Hello World, from MathPaint!

These MathPaint documents were used to create our app icon and current Facebook cover.

MathPaint is a Mac OS desktop application written in Swift. A private beta release is planned for February 2020, and the completed 1.0 application will be released later this year, through the Apple AppStore.

CoreImage effects can be applied to any MathPaint canvas
I've always felt that creativity and mathematics belong together. MathPaint is designed for creative professionals who would like to harness of of the endless generative capability of mathematics to create visual forms, patterns, textures, and algorithmic art. You don't need to be a programmer to create such designs with MathPaint, and the release will include visual templates and presets that are intuitive to browse and modify, plus cool automation features:

The "Repeater" feature can add multiple iterated re-renderings to a model

I also think MathPaint is a natural tool for students. While there are robust software products for mathematical modeling and computation, MathPaint focuses on aesthetics and uniquely permits the creative impulse to guide mathematical learning and exploration.

I will be using MathPaint to make art, and I hope to see a community of makers who create original expressive work with this software. Even algorithmic artists used to coding may find some rewarding features and workflows with this tool.

Document settings give you a page-layout app's control over your math-art canvas.

Now that the first screenshots are out, look for weekly updates and posts on MathPaint progress! And of course, a continuing stream of art, including our Fractal Friday posts, all made by MathPaint.



Friday, January 10, 2020

Fractal Friday 2020.01.10

ICYMI, I'm currently writing an application that generates mathematical art. It's created in Swift, for Mac OS desktop systems. All the images on this blog are created from it, including the fractals posted every Fractal Friday.

This week I hooked up a full range of CoreImage effects to the app, and I'm having fun sending fractals through tiling effects to create some really cool repeating patterns.

For the first one I used a small 320x320 source image of an edge-rendered Julia set section

I played around with this image using the Twelvefold Reflected Tile and Eightfold Reflected Tile filters to get these:




I used a more psychedlic-looking color-banded Mandelbrot section for the next set:


Friday, January 3, 2020

Fractal Friday 2020.01.03

The noise renderer has gotten more sophisticated in the past week, and it's being put to work in this week's set of fractals. Each image includes a generated noise-texture, with various approaches to transparency in the fractal permitting the texture to show through.


The Julia set image above has a semi-transparent purple in the color mapping which permits a fabric-like texture to show through giving the rendering the feeling of a woven fabric or paper fiber texture.

This bold, edge-drawn mandelbrot set view is a bit more stark against its chiseled, black-and-gray noise surface:


An N-cubed mandlebrot section gets a bit subtler treatment with a horizontal grain texture, which shows through most clearly in the dark 'maxed-out' section:


A bit crazier are the curve-and-line-segment generated scribbles showing through this Julia set segment's color cycle, with transparency in each color band:


While it's only the beginning of January, this 5th-degree Julia set floral image looks forward to spring, especially with the tangled green bezier-noise suggesting foliage, showing through the transparent lower-iteration values around the floral center:


All of these images were created with the Mathaesthetics flagship software, a desktop app for Mac OS X which has now been in development for two months. The first beta will be released early this year, with a full release coming before summer. If you like these images and are interested in creating your own with this software, or just seeing more as the software evolves, make sure to follow Mathaesthetics on Twitter, Instagram, Facebook - and we're also now on Pinterest!

Friday, December 27, 2019

Fractal Friday 2019.12.27

It's the last Fractal Friday of the year, time for some recursive magic!

 This week we're exploring the Mandelbrot set, using two features of the Mathaesthetics prototype software: deep color mapping, and a new helpful zoom feature.

Here's where we start:
In this image, there's a color mapping with 10 different colors at various levels of iteration-result, from 1 to 300. This is both a more diverse color mapping and deeper-iteration delve than I've done before, although you can't tell yet from the image above. Here's a screenshot of the prototype app, showing the higher-end of the color mapping assignments and other settings:



The colors at 1 and 300 are the same (a deep dark blue), and you mostly just see gradations to the orange color set for iteration level 20 above. We have to zoom in to start seeing the other iteration levels, especially those that take over 100 or 200 iterations to hit the breakout threshold of 10.0.

Fortunately I hooked up a new UI feature this week, a click-and-drag zoom feature that lets me zoom to a tiny (but still aspect-ratio-preserving) part of the image.

Series A zooms toward (-1.075885, 0.2433465)




Zoom series B ends up around (-0.766362, 0.1001006)



Zoom series C ends up in the region of (-1.94310614143, 0.001727529425)






More images PLUS a software release to come in 2020! Happy new year. You can follow Mathaesthetics on Twitter, Facebook, and Instagram.

Monday, December 23, 2019

Dev notebook: an enum alternative to GKState / GKStateMachine

I worked on my first GameplayKit project earlier this year and there were things I liked about the lightweight, general state-machine model provided by the GKState and GKStateMachine classes. However I also found a few odd patterns in these classes: their implementation without using enumeration values for states, the inelegant (StateClass).class.self syntax model required by the state machine enterState() method, and the update() interface which I found extra and somewhat orthogonal to the pure function of the state machine (I keep time-based concerns in entities and components).

In my current project, which is not a game, I wanted to use a pattern similar to GKStateMachine for various UI and model states, but decided to implement a simple framework that addressed these issues rather than use GKStateMachine.

The basic pattern is provided by a protocol that *could* be implemented by any class, but the interface strongly suggests that a state will be an enum : Int type:


protocol MPState {
    var rawEnumValue : Int { get }
    var validNextStates : [Int] { get }
    
    func didEnter(from prevState: MPState?, with machine: MPStateMachine)
    func willExit(to nextState: MPState?, with machine: MPStateMachine)
}


Obviously the rawEnumValue will be very easy to implement as a wrapper on rawValue if the state is implemented as an enum : Int rather than some other type of struct or class. Also, the required validNextStates computed property is expected to return values that can be compared with rawEnumValue for inclusion/exclusion, and this logic is made explicit in an extension to the protocol (which also implements didEnter and willExit as no-ops to make them optional):


extension MPState {
    func isValidNextState(_ nextState : MPState
                          with machine: MPStateMachine) -> Bool {

        return self.validNextStates.contains(nextState.rawEnumValue)
    }
    
    func didEnter(from prevState: MPState?, with machine: MPStateMachine) {
        // no-op, override to handle
    }
    
    func willExit(to nextState: MPState?, with machine: MPStateMachine) {
        // no-op, override to handle
    }
}


One thing this pattern precludes: the state object itself can't retain any persistent reference to either the state machine or any model object, since enumerations in swift can't have stored properties. This is handled by simply passing the machine object into the three relevant methods; the machine is a full-fledged class which also has an optional model property that can bring in more object context.


The state-machine class provides an interface like that of GKStateMachine, but instead of passing a class to the enter() method you can just pass your enumerated state value. It has a similar currentState read-only computed property (returning a private machineState value which can only be updated by successful enter). Here's the entire implementation:

class MPStateMachine : NSObject {
    var model: Any? = nil
    
    var currentState : MPState? {
        get {
            return self.machineState
        }
    }
    
    func canEnterState(_ nextState : MPState) -> Bool {
        if nil != self.machineState {
            return self.machineState!.isValidNextState(nextState, with: self)
        }
        return true // assume we can enter any state from nil
    }
    
    func enter(_ state: MPState) -> Bool {
        var setState : Bool = false
        if self.machineState == nil {
            self.machineState = state
            state.didEnter(from: nil, with: self)
            setState = true
        } else if self.machineState!.isValidNextState(state, with: self) {
            let oldState = self.machineState!
            self.machineState?.willExit(to: state, with: self)
            self.machineState = state
            state.didEnter(from: oldState, with: self)
            setState = true
        }
        return setState
    }
    
    fileprivate var machineState : MPState? = nil

}

The model property in the state machine is up to the client code to define; it will typically be the model object whose state is being managed, i.e. the domain-specific owner of the state machine instance.

As a sample implementation I created an MPApplicationState which tracks the app states of starting, running, terminating, owned by my AppDelegate class. This demonstrates the pattern of how valid next-states can be handled by a simple switch statement for most state collections, but you could always add helper methods for various state-transition contexts for more complex cases that need to inspect the model:

enum MPApplicationState : Int, MPState {

    case starting
    case running
    case terminating
    
    var rawEnumValue: Int {
        get {
            return self.rawValue
        }
    }
    
    var validNextStates: [Int] {
        get {
            var nextStates : [Int] = []
            switch self {
                case .starting:
                    nextStates.append(MPApplicationState.running.rawValue)
                    nextStates.append(MPApplicationState.terminating.rawValue)
                case .running:
                    nextStates.append(MPApplicationState.terminating.rawValue)
                case .terminating:
                    nextStates.removeAll()
            }
            return nextStates
        }
    }
    
    func didEnter(from prevState: MPState?, with machine: MPStateMachine) {
        print ("*** MPApplicationState *** did enter state: \(String(describing:self)) from \(String(describing:prevState))")
    }
    
    func willExit(to nextState: MPState, with machine: MPStateMachine) {
        print ("*** MPApplicationState *** will exit state: \(String(describing:self)) to state: \(String(describing:nextState))")
    }

}

Just to show the functionality (not really because it's useful) I created an MPStateMachine property on my AppDelegate (allocated at the declaration), and transition states in the following method overrides:

func applicationWillFinishLaunching(_ notification: Notification) {
    _ = self.stateMachine.enter(MPApplicationState.starting)

}


func applicationDidFinishLaunching(_ aNotification: Notification) {
    _ = self.stateMachine.enter(MPApplicationState.running)
    // etc...
}

func applicationWillTerminate(_ aNotification: Notification) {

    _ = self.stateMachine.enter(MPApplicationState.terminating)
}

I'm not bothering to check the output values for these simple cases but the idea is that more involved state transitions could do so, and/or pre-check the ability of the state machine to transition with a call a like:


   self.stateMachine.canEnterState(MPApplicationState.running)

And now checking the current application state looks a bit nicer than it would with GKStateMachine:

    if appDelegate.stateMachine.currentState != MPApplicationState.terminating {

        // do something...

That's it!

Friday, December 20, 2019

Fractal Friday 2019.12.20

The fractal renderer used to draw this week's graphics has a new feature - rendering in 'edge' mode. Rather than filling the value regions with different colors, edge-mode detects the change in output values and draws a line at the boundary between them. Here's the classic Mandelbrot set rendered this way:

Here's a simple black-and-white rendering of a Julia set region:

Edge rendering of fractals emphasizes different structures within the shapes, and also produces different aesthetic effects, especially when different pen and background colors are used:




Coming soon: images created with the new geometry renderer! The Mathaesthetics flagship app that produces all these images will be released in 2020. You can follow Mathaesthetics on Twitter, Facebook, and Instagram.

Tuesday, December 17, 2019

Scalar fields for gradients and other graphic patterns

The Mathaesthetics flagship app will support a number of modes of mathematical image creation. I spent most of yesterday working on and improving the scalar field renderer.

In a scalar field, a function f(x, y) produces a value for each point. This scalar value is then mapped to a color gradient. I'm exploring both different modes of color assignment and different function definitions and the results they yield.

Here's a simple example, of the function f(x, y) = x • y. The color scale is white-to-black, and here I'm only allowing 16 different distinct shades:

Here's the same function with the color mapping changed to orange-to-blue:

And again, but with the discrete shading limit removed so we get a smooth gradient:

Producing gradients that aren't simply linear or radial is one potential graphic application of scalar fields with algebraic functions. For example, a logarithmic gradient...

Friday, December 13, 2019

Fractal Friday 2019.12.13

It's Friday already! This week I've been jamming on this application UI development, including a brand-new feature to support fractals: the color mapping control:
For fractal rendering the integers below each color correspond to the output value (escape iterations) to which the color is assigned. The linear-gradient mapping mode means that colors between these values will be interpolated evenly between them. Here's the image that is using these control settings, with the dark-red background color of the canvas showing through for values above 30:


There are non-gradient coloration modes supported by the control. A color cycle is easy to set up with this control - all colors are used, and they just repeat for each successive band of output. This one's a little different in that some of the colors are assigned to be transparent, letting the deep blue background color show through at those levels:




Thursday, December 12, 2019

Dev notebook: Converting scale & position of circular NSSlider for degrees

The standard Cocoa control NSSlider comes in a circular variety that resembles a rotating knob with an indicator point. Among the ideal applications for such a control is representing a circular angle.



In the application I'm developing I wanted to use this to control the angle of the brush image used for drawing. I began by setting the range of the control from 100 and using the value as a percentage (a pretty common approach for sliders), converting to the angle (which I'm using in radians in my drawing code)

Functionally it was okay, but there were some user-feedback issues. For one, the circular slider by default increases in the clockwise direction, but in my mathematics-centered application I felt it made much more sense for angle to be treated as it is on the unit circle, increasing in the counter-clockwise direction. (Since my drawing code was written this way, it also meant that the position of the knob did not visually follow the rotation of the brush image). A related issue: the unit circle typically puts the angle zero at "3 o'clock", whereas the NSSlider defaults to position 0 at noon.

One other usability issue involved precise setting, which is somewhat a limitation of the size of the control. A text field displaying the control setting could help the user a bit; however displaying values in radians would require a lot of decimal spaces and perhaps not be as intuitive, so I decided at this point to convert the control to work with degrees, and display this value in a text field.

To sum up, the needs are: 1) make the control increase counter-clockwise instead of clockwise, 2) make the control set 0 to the 3 o'clock knob position instead of noon; 3) map the range from 0 to 360 degrees and display that value in a text field.