joyhughes / Jen

Image processing, generative photography, cellular automata
https://discord.gg/GQQHUbkf
20 stars 20 forks source link

Kaleidoswirl Scene File #140

Open joyhughes opened 1 month ago

joyhughes commented 1 month ago

A scene with a choice of background images and possible warps including kaleidoscope, turbulence, and spiral vector fields.

Includes warp, melt, and hyperspace effects.

Elements included in the scene will be photographic collections in different themes such as flowers, seashells, leaves, stones, etc. A scene may include elements in one or more of these collections.

Clusters can be formed by elements advecting iteratively through any of these vector fields. Elements can spin, change tint, grow and shrink, possibly in waves through the cluster.

All of these possibilities can be controlled through the UI or randomly generated.

lassmara commented 1 month ago

please assign me this issue

DM-netizen commented 1 month ago

I want to work on this issue. Can you assign it to me?

DM-netizen commented 3 weeks ago

Let me know how to start off with the work

joyhughes commented 3 weeks ago

Yes I have started working on it. Look at the branch https://github.com/joyhughes/Jen/tree/Kaleido-stuff

I have the kaleidoscope working but we still need to make it swirl. So I think we can pass a function to vf_tools::kaleidoscope that modifies the angle based on the radius and call it just before switching back to Cartesian coordinates. Are you familiar with std::function?

DM-netizen commented 3 weeks ago

Looks interesting ! Yeah I know about std::function

joyhughes commented 3 weeks ago

Great - so in vf_tools::kaleidoscope pass a reference to a std::function that takes float as an argument and returns a float. Then before the call to Cartesian add to the y coordinate the function called with x coordinate as argument.

(At that point we're in polar coordinates, x is really r and y is really theta)


From: Disha Mukherjee @.> Sent: Thursday, June 13, 2024 10:25:41 AM To: joyhughes/Jen @.> Cc: Joy Hughes @.>; Author @.> Subject: Re: [joyhughes/Jen] Kaleidoswirl Scene File (Issue #140)

Looks interesting ! Yeah I know about std::function

— Reply to this email directly, view it on GitHubhttps://github.com/joyhughes/Jen/issues/140#issuecomment-2166388664, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AKBIGEBJT3AEZNJP6YVBVI3ZHHIZLAVCNFSM6AAAAABIGBLIW2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCNRWGM4DQNRWGQ. You are receiving this because you authored the thread.Message ID: @.***>

DM-netizen commented 3 weeks ago

Will it be like this?

void vf_tools::kaleidoscope(    const vec2f& center, 
                                float segments,                // Number of segments in kaleidoscope
                                float offset_angle,            // Beginning of first segment in degrees
                                float spin_angle,
                                bool reflect ) {               // Reflect alternate segments
    std::cout << "vf_tools::kaleidoscope: segments = " << segments << std::endl;
    std::function<float(float)> func= modify_angle;
    if( segments != 0.0f ) {
        position_fill();
        //std::cout << "vf_tools position_fill img.base " << img.base[0].x << " " << img.base[0].y << std::endl;
        radial();
        //std::cout << "vf_tools radial img.base " << img.base[0].x << " " << img.base[0].y << std::endl;
        if( reflect ) { for( auto& v : img.base ) { v.y = rmodf( v.y + spin_angle, 360.0f / segments ) + offset_angle; } }
        else          { for( auto& v : img.base ) { v.y = tmodf( v.y + spin_angle, 360.0f / segments ) + offset_angle; } }
        for( auto& v : img.base ) {v.y= v.y+ func(v.x);}
        cartesian();
        //std::cout << "vf_tools cartesian img.base " << img.base[0].x << " " << img.base[0].y << std::endl;
    }
}

If modify_angle() is the function that modifies the angle based on the radius

joyhughes commented 3 weeks ago

You need to pass the std::function as a parameter to kaleidoscope. Otherwise this is correct.

DM-netizen commented 3 weeks ago
void vf_tools::kaleidoscope(    const vec2f& center, 
                                float segments,                // Number of segments in kaleidoscope
                                float offset_angle,            // Beginning of first segment in degrees
                                float spin_angle,
                                bool reflect,                      // Reflect alternate segments
                                const std::function<float(float)>& func) {    
    std::cout << "vf_tools::kaleidoscope: segments = " << segments << std::endl;
    if( segments != 0.0f ) {
        position_fill();
        //std::cout << "vf_tools position_fill img.base " << img.base[0].x << " " << img.base[0].y << std::endl;
        radial();
        //std::cout << "vf_tools radial img.base " << img.base[0].x << " " << img.base[0].y << std::endl;
        if( reflect ) { for( auto& v : img.base ) { v.y = rmodf( v.y + spin_angle, 360.0f / segments ) + offset_angle; } }
        else          { for( auto& v : img.base ) { v.y = tmodf( v.y + spin_angle, 360.0f / segments ) + offset_angle; } }
        for( auto& v : img.base ) {v.y= v.y+ func(v.x);}
        cartesian();
        //std::cout << "vf_tools cartesian img.base " << img.base[0].x << " " << img.base[0].y << std::endl;
    }
}

Is this ok? What is the function that modifies the angle?

joyhughes commented 2 weeks ago

Yes this is correct.

The eff_kaleidoscope functor in effect.hpp will have a member field of type any_fn< float > (call it swirl_fn)

swirl_fn.fn is type std::function< float ( float&, element_context& ) > - use a lambda function to convert to the correct type and pass to vf_tools::kaleidoscope

DM-netizen commented 2 weeks ago

swirl_fn.fn is type std::function< float ( float&, element_context& ) > - use a lambda function to convert to the correct type and pass to vf_tools::kaleidoscope

Can you explain this a bit more?

joyhughes commented 2 weeks ago

swirl_fn.fn is type std::function< float ( float&, element_context& ) > - use a lambda function to convert to the correct type and pass to vf_tools::kaleidoscope

Can you explain this a bit more?

Here is the definition of any_fn< float >:

template<> struct any_fn< float > { 
    any_float_fn_ptr any_fn_ptr; 
    float_fn fn; std::string name; 
    float operator () ( float& val, element_context& context ) { return fn( val, context ); } 
    any_fn< float >() : name("identity_" "float" "_default") { 
        std::shared_ptr< identity_float > f( new identity_fn< float > ); 
        fn = std::ref( *f ); any_fn_ptr = f; 
        } 
    any_fn< float >( any_float_fn_ptr any_float_fn, float_fn fn, std::string name ) : any_fn_ptr( any_float_fn ), fn( fn ), name( name ) {}; 
};

float_fn is defined like this: typedef std::function< float ( float&, element_context& ) > float_fn;

We need a lambda function that calls this float_fn while holding element_context constant, as vf_tools doesn't know about element_context.

DM-netizen commented 2 weeks ago

Changes in effect.hpp :

template< class T > struct eff_kaleidoscope {
    harness< vec2f > center;
    harness< float > segments;
    harness< float > offset_angle;
    harness< float > spin_angle;
    harness< bool >  reflect;
    any_fn< float > swirl_fn;

    bool filled;

    void operator () ( any_buffer_pair_ptr& buf, element_context& context );

    eff_kaleidoscope( vec2f center_init = vec2f( 0.0f, 0.0f ), float segments_init = 6.0f, float offset_angle_init = 0.0f, float spin_angle_init = 0.0f, bool reflect_init = true ) : 
        center( center_init ), segments( segments_init ), offset_angle( offset_angle_init ), spin_angle( spin_angle_init ), reflect( reflect_init ), filled( false ) {}
};

Changes in effect.cpp:

template< class T > void eff_kaleidoscope< T >::operator () ( any_buffer_pair_ptr& buf, element_context& context )
{
    vec2f old_center=*center; float old_segments=*segments; float old_offset_angle = *offset_angle; float old_spin_angle = *spin_angle; bool old_reflect=*reflect;
    center(context); segments(context); offset_angle(context); spin_angle(context); reflect(context); 

    auto swirl_fn = [context](float x) -> float { return float_fn(x, context);};    

    if(*center!=old_center || *segments!=old_segments || *offset_angle!=old_offset_angle || *spin_angle!=old_spin_angle || *reflect!=old_reflect)
    filled=false;

    std::cout << "eff_kaleidoscope: filled = " << filled << std::endl;
    if(!filled)
    {
        filled =true;
        vf_tools tools( get_image< T >( buf ) );
        tools.kaleidoscope( *center, *segments, *offset_angle, *spin_angle, *reflect, swirl_fn);
    }  
}

Changes in vector_field.hpp:

 void kaleidoscope( const vec2f& center = { 0.0f, 0.0f }, 
                        float segments = 6.0,                // Number of segments in kaleidoscope
                        float offset_angle = 0.0f,           // Beginning of first segment in degrees
                        float spin_angle = 0.0f,
                        bool reflect = true,                  // Reflect alternate segments  
                        const std::function<float(float)>& func );

Will this work?

joyhughes commented 2 weeks ago

I think here you are redefining swirl_fn - the lambda should call swirl_fn and have a different name, or just be defined in the parentheses of the call to tools.kaleidoscope. swirl_fn should be initialized in eff_kaleidoscope's parameter list and default to identity_float_fn.

DM-netizen commented 1 week ago

What is the relation between swirl_fn and float_fn ? Isn't swirl_fn a type of float_fn?

And will identity_float_fn call float_fn in eff_kaleidoscope's parameter list?

joyhughes commented 1 week ago

float_fn is defined in next_element.hpp: typedef std::function< float ( float&, element_context& ) > float_fn;

swirl_fn is type any_fn< float > which is defined in any_function.hpp (via a macro, but I have supplied an example macro expansion within a comment):

template<> struct any_fn< float > { 
    any_float_fn_ptr any_fn_ptr; 
    float_fn fn; 
    std::string name; 
    float operator () ( float& val, element_context& context ) { return fn( val, context ); } 
    any_fn< float >() : name("identity_" "float" "_default") { 
        std::shared_ptr< identity_float > f( new identity_fn< float > ); 
        fn = std::ref( *f ); any_fn_ptr = f; 
        } 
    any_fn< float >( any_float_fn_ptr any_float_fn, float_fn fn, std::string name ) : any_fn_ptr( any_float_fn ), fn( fn ), name( name ) {}; 
};

So swirl_fn.fn is type float_fn

vftools is defined in vector_field.hpp, and does not know about float_fn, any_fn, or element_context, so we have to pass a std::function that is purely a function of float and does not include the context.

DM-netizen commented 1 week ago
template< class T > void eff_kaleidoscope< T >::operator () ( any_buffer_pair_ptr& buf, element_context& context )
{
    vec2f old_center=*center; float old_segments=*segments; float old_offset_angle = *offset_angle; float old_spin_angle = *spin_angle; bool old_reflect=*reflect;
    center(context); segments(context); offset_angle(context); spin_angle(context); reflect(context); 

    if(*center!=old_center || *segments!=old_segments || *offset_angle!=old_offset_angle || *spin_angle!=old_spin_angle || *reflect!=old_reflect)
    filled=false;

    std::cout << "eff_kaleidoscope: filled = " << filled << std::endl;
    if(!filled)
    {
        filled =true;
        vf_tools tools( get_image< T >( buf ) );
        tools.kaleidoscope( *center, *segments, *offset_angle, *spin_angle, *reflect, func=[context](float x) -> float { return swirl_fn(x, context);});
    }  
}
template< class T > struct eff_kaleidoscope {
    harness< vec2f > center;
    harness< float > segments;
    harness< float > offset_angle;
    harness< float > spin_angle;
    harness< bool >  reflect;
    any_fn< float > swirl_fn;

    bool filled;

    void operator () ( any_buffer_pair_ptr& buf, element_context& context );

    eff_kaleidoscope( vec2f center_init = vec2f( 0.0f, 0.0f ), float segments_init = 6.0f, float offset_angle_init = 0.0f, float spin_angle_init = 0.0f, bool reflect_init = true, swirl_fn=identity_float ) : 
        center( center_init ), segments( segments_init ), offset_angle( offset_angle_init ), spin_angle( spin_angle_init ), reflect( reflect_init ), filled( false )  {}
};

I am confused about how to do the initialization part

joyhughes commented 1 week ago

I took a look at it and I think we don't need to initialize swirl_fn - its default constructor will initialize it with identity function. scene_io.cpp will modify it when the scene is loaded, and the function will also be changed via the UI.

DM-netizen commented 1 week ago

Okk Are the other things ok? I will remove the initialisation part

DM-netizen commented 1 day ago

@joyhughes What are the updates on this issue?

joyhughes commented 1 day ago

Sorry I have been on holiday.

I think we need to test what you wrote. We also need to be able to load the function from the scene file. That's in scene_io.cpp where we can change the way the kaleidoscope effect is loaded.


From: Disha Mukherjee @.> Sent: Friday, July 5, 2024 9:42:37 AM To: joyhughes/Jen @.> Cc: Joy Hughes @.>; Mention @.> Subject: Re: [joyhughes/Jen] Kaleidoswirl Scene File (Issue #140)

@joyhugheshttps://github.com/joyhughes What are the updates on this issue?

— Reply to this email directly, view it on GitHubhttps://github.com/joyhughes/Jen/issues/140#issuecomment-2211155786, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AKBIGEDLAHBV4E7FM2QJ5FLZK3EH3AVCNFSM6AAAAABIGBLIW2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEMJRGE2TKNZYGY. You are receiving this because you were mentioned.Message ID: @.***>

DM-netizen commented 1 day ago

Yeah, no worries. I am ready to work on it any time you are free.