Move to cmake
This commit is contained in:
1161
src/atomorph.cpp
Normal file
1161
src/atomorph.cpp
Normal file
File diff suppressed because it is too large
Load Diff
390
src/atomorph.h
Normal file
390
src/atomorph.h
Normal file
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
* AtoMorph - Simple Library for Morphing 2D Particle Clouds
|
||||
* See Copyright Notice at the end of this file.
|
||||
*/
|
||||
|
||||
#ifndef _ATOMORPH_H_
|
||||
#define _ATOMORPH_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <future>
|
||||
#include <random>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <limits>
|
||||
#include <assert.h>
|
||||
#include <cstdint>
|
||||
|
||||
#ifdef ATOMORPH_OPENCV
|
||||
#include <opencv/cv.h>
|
||||
#endif
|
||||
|
||||
#include "spline.h"
|
||||
#include "perlin.h"
|
||||
#include "fluidmodel.h"
|
||||
#include "color.h"
|
||||
|
||||
#ifdef ATOMORPH_DEPRECATED
|
||||
#define AM_NONE 0
|
||||
#define AM_LINEAR 1
|
||||
#define AM_COSINE 2
|
||||
#define AM_PERLIN 3
|
||||
#define AM_SPLINE 4
|
||||
|
||||
#define AM_WARN_POINTER_SIZE 1 // Set when sizeof(void *) is less than 64 bits.
|
||||
#define AM_WARN_ATOM_SIZE 2 // Set when sizeof(AM_ATOM) is more than 64 bits.
|
||||
|
||||
typedef struct AM_COLOR {
|
||||
unsigned char r;
|
||||
unsigned char g;
|
||||
unsigned char b;
|
||||
unsigned char a;
|
||||
} AM_COLOR;
|
||||
|
||||
typedef struct AM_ATOM {
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
unsigned char r;
|
||||
unsigned char g;
|
||||
unsigned char b;
|
||||
unsigned char a;
|
||||
} AM_ATOM;
|
||||
|
||||
class AM_SCENE {
|
||||
public:
|
||||
AM_SCENE();
|
||||
~AM_SCENE();
|
||||
|
||||
void clear();
|
||||
bool init(size_t atoms, size_t frames);
|
||||
bool push_atom(size_t frame, AM_ATOM atom);
|
||||
void renew_splines();
|
||||
double get_certainty(double t) const;
|
||||
void get_xy (size_t atom, double t, double *x, double *y, unsigned method) const;
|
||||
AM_COLOR get_rgba(size_t atom, double t, double lag, double slope, unsigned interpolation) const;
|
||||
double get_current_path_length(size_t atom, double t) const;
|
||||
AM_ATOM get_atom(size_t atom, size_t frame) const;
|
||||
size_t atom_count() const {return atoms;}
|
||||
size_t frame_count() const {return frames;}
|
||||
size_t get_sorted_atom_at(size_t position);
|
||||
size_t get_current_frame(double t) const;
|
||||
bool copy_map_from(const AM_SCENE *scene);
|
||||
bool copy_candidates_from(const AM_SCENE *scene);
|
||||
void shuffle();
|
||||
void sort_atoms();
|
||||
double get_cost() const;
|
||||
double get_path_length(size_t atom) const;
|
||||
double get_path_color(size_t atom) const;
|
||||
bool elect_atoms();
|
||||
bool swap_atoms(size_t frame, size_t atom1, size_t atom2);
|
||||
const std::vector<AM_ATOM> *get_candidates(size_t frame) const;
|
||||
|
||||
private:
|
||||
size_t atoms;
|
||||
size_t frames;
|
||||
|
||||
std::vector<size_t> sorted_atoms;
|
||||
std::vector<AM_ATOM> *candidates;
|
||||
glnemo::CRSpline *splines;
|
||||
|
||||
AM_ATOM **map;
|
||||
};
|
||||
|
||||
class AM_THREAD {
|
||||
public:
|
||||
AM_THREAD();
|
||||
~AM_THREAD();
|
||||
|
||||
bool clear();
|
||||
bool init(const AM_SCENE *scene);
|
||||
|
||||
void set_seed(unsigned seed);
|
||||
void set_step_size(int step_size);
|
||||
void set_gradient_importance(double weight);
|
||||
void set_magic_exponent(double exponent);
|
||||
|
||||
bool is_running() const {return running;}
|
||||
bool is_paused() const {return paused;}
|
||||
|
||||
void stop() { signal_stop = true; while(running) std::this_thread::sleep_for(std::chrono::milliseconds(0)); step_thread.join();}
|
||||
void start() { running = true; step_thread = std::thread(&AM_THREAD::run, this);}
|
||||
void pause() { signal_pause = true; while(!paused) std::this_thread::sleep_for(std::chrono::milliseconds(0)); signal_pause = false;}
|
||||
void resume() { paused = false;}
|
||||
|
||||
double get_cost() const {return cost;}
|
||||
bool fetch_scene(AM_SCENE *target) const;
|
||||
|
||||
private:
|
||||
void run();
|
||||
void step();
|
||||
double chain_length(AM_ATOM a1, AM_ATOM a2, AM_ATOM a3);
|
||||
double chain_gradient(AM_ATOM a1, AM_ATOM a2, AM_ATOM a3);
|
||||
AM_SCENE scene;
|
||||
double *subcost;
|
||||
double cost;
|
||||
std::default_random_engine e1;
|
||||
int step_size;
|
||||
double magic_exponent;
|
||||
double gradient_importance;
|
||||
|
||||
std::atomic<bool> signal_stop;
|
||||
std::atomic<bool> running;
|
||||
std::atomic<bool> signal_pause;
|
||||
std::atomic<bool> paused;
|
||||
std::thread step_thread;
|
||||
};
|
||||
|
||||
class AM_IMAGE {
|
||||
public:
|
||||
AM_IMAGE();
|
||||
~AM_IMAGE();
|
||||
|
||||
bool set_scene(const AM_SCENE *scene);
|
||||
bool set_resolution(size_t width, size_t height);
|
||||
bool set_time(double time);
|
||||
bool set_seed(unsigned seed);
|
||||
bool set_color_interpolation(unsigned method);
|
||||
bool set_path_interpolation(unsigned method);
|
||||
|
||||
bool is_running() const {return running;}
|
||||
bool is_paused() const {return paused;}
|
||||
size_t pixel_count() const {return atoms.size();}
|
||||
|
||||
bool get_xy (size_t pixel, int *x, int *y) const;
|
||||
bool get_rgba(size_t pixel, unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *a) const;
|
||||
size_t get_pixel_count() const {return atoms.size();}
|
||||
|
||||
bool fetch_pixels(std::vector<AM_ATOM> *to) const;
|
||||
|
||||
void stop() { signal_stop = true; while(running) std::this_thread::sleep_for(std::chrono::milliseconds(0)); step_thread.join();}
|
||||
void start() { running = true; step_thread = std::thread(&AM_IMAGE::run, this);}
|
||||
void pause() { signal_pause = true; while(!paused) std::this_thread::sleep_for(std::chrono::milliseconds(0)); signal_pause = false;}
|
||||
void resume() { paused = false;}
|
||||
|
||||
private:
|
||||
void run();
|
||||
void render();
|
||||
std::vector<AM_ATOM> atoms;
|
||||
size_t w;
|
||||
size_t h;
|
||||
double t;
|
||||
AM_SCENE scene;
|
||||
bool done;
|
||||
unsigned seed;
|
||||
unsigned color_interpolation;
|
||||
unsigned path_interpolation;
|
||||
PerlinNoise lag_map;
|
||||
PerlinNoise slope_map;
|
||||
|
||||
std::atomic<bool> signal_stop;
|
||||
std::atomic<bool> running;
|
||||
std::atomic<bool> signal_pause;
|
||||
std::atomic<bool> paused;
|
||||
std::thread step_thread;
|
||||
};
|
||||
|
||||
class AM_BLENDER {
|
||||
public:
|
||||
AM_BLENDER();
|
||||
~AM_BLENDER();
|
||||
|
||||
bool set_resolution(size_t width, size_t height);
|
||||
bool set_median_combining(bool value);
|
||||
bool clear();
|
||||
bool add_image(const AM_IMAGE *img);
|
||||
|
||||
bool get_xy (size_t pixel, int *x, int *y) const;
|
||||
bool get_rgba(size_t pixel, unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *a) const;
|
||||
size_t pixel_count() const {return atoms.size();}
|
||||
|
||||
bool is_running() const {return running;}
|
||||
bool is_paused() const {return paused;}
|
||||
|
||||
void stop() { signal_stop = true; while(running) std::this_thread::sleep_for(std::chrono::milliseconds(0)); step_thread.join();}
|
||||
void start() { running = true; step_thread = std::thread(&AM_BLENDER::run, this);}
|
||||
void pause() { signal_pause = true; while(!paused) std::this_thread::sleep_for(std::chrono::milliseconds(0)); signal_pause = false;}
|
||||
void resume() { paused = false;}
|
||||
|
||||
private:
|
||||
void run();
|
||||
void render();
|
||||
std::vector<AM_ATOM> atoms;
|
||||
std::vector<size_t> layers;
|
||||
size_t w;
|
||||
size_t h;
|
||||
bool done;
|
||||
bool median_combining;
|
||||
|
||||
std::atomic<bool> signal_stop;
|
||||
std::atomic<bool> running;
|
||||
std::atomic<bool> signal_pause;
|
||||
std::atomic<bool> paused;
|
||||
std::thread step_thread;
|
||||
};
|
||||
|
||||
AM_ATOM am_create_atom(double x, double y, unsigned char r, unsigned char g, unsigned char b, unsigned char a);
|
||||
double am_atom_distance(AM_ATOM a1, AM_ATOM a2);
|
||||
double am_atom_gradient(AM_ATOM a1, AM_ATOM a2);
|
||||
const char * am_get_version();
|
||||
size_t am_get_warning();
|
||||
#endif
|
||||
|
||||
namespace am {
|
||||
|
||||
const unsigned RGB = 0; // Don't change the color space.
|
||||
const unsigned HSP = 1; // Convert from RGB to HSP.
|
||||
const unsigned NONE = 2; // Color/motion interpolation is off.
|
||||
const unsigned LINEAR = 3; // Uses linear interpolation.
|
||||
const unsigned SPLINE = 4; // Spline interpolation (motion only).
|
||||
const unsigned COSINE = 5; // Cosine interpolation (colors only).
|
||||
const unsigned PERLIN = 6; // Perlin noise dependent interpolation (colors only).
|
||||
const unsigned STATE_BLOB_DETECTION = 0;
|
||||
const unsigned STATE_BLOB_UNIFICATION = 1;
|
||||
const unsigned STATE_BLOB_MATCHING = 2;
|
||||
const unsigned STATE_ATOM_MORPHING = 3;
|
||||
const unsigned STATE_DONE = 4;
|
||||
const unsigned char HAS_PIXEL = 1;
|
||||
const unsigned char HAS_FLUID = 2;
|
||||
typedef struct pixel {
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
|
||||
color c;
|
||||
} pixel;
|
||||
|
||||
typedef struct blob {
|
||||
size_t index; // Position in the nest vector.
|
||||
std::set<size_t> surface; // Pixel positions for surface.
|
||||
std::set<size_t> border; // Pixel positions around surface.
|
||||
size_t group =0;
|
||||
bool unified=false;
|
||||
double x,y,r,g,b,a;
|
||||
} blob;
|
||||
|
||||
typedef struct key_frame {
|
||||
std::vector<blob*> blobs; // Vector of blobs.
|
||||
std::map<size_t, pixel> pixels; // Map of pixels by position.
|
||||
std::map<size_t, blob*> owners; // Map of blobs by position.
|
||||
double x,y,r,g,b,a;
|
||||
size_t index =0; // Position in the nest container.
|
||||
size_t first_expansion=0; // Blobs before this index cannot expand.
|
||||
size_t first_dust =0; // First under-sized blob to be unified.
|
||||
} frame;
|
||||
|
||||
typedef union key_point {
|
||||
struct {
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
uint8_t x_fract;
|
||||
uint8_t y_fract;
|
||||
uint8_t flags;
|
||||
} s;
|
||||
uint64_t word;
|
||||
} point;
|
||||
|
||||
typedef struct blob_chain {
|
||||
size_t width =0;
|
||||
size_t height=0;
|
||||
point **points=nullptr;
|
||||
size_t **places=nullptr;
|
||||
double energy=0.0;
|
||||
size_t max_surface=0;
|
||||
glnemo::CRSpline *splines=nullptr;
|
||||
#ifdef ATOMORPH_OPENCV
|
||||
void **kdtrees=nullptr;
|
||||
void **feature=nullptr;
|
||||
#endif
|
||||
} chain;
|
||||
|
||||
const size_t WARN_POINTER_SIZE = 1; // Set when sizeof(void *) is less than 64 bits.
|
||||
const size_t WARN_PIXEL_SIZE = 2; // Set when sizeof(pixel) is more than 64 bits.
|
||||
const size_t WARN_POINT_SIZE = 3; // Set when sizeof(point) is more than 64 bits.
|
||||
|
||||
const unsigned TEXTURE = 0;
|
||||
const unsigned AVERAGE = 1;
|
||||
const unsigned DISTINCT = 2;
|
||||
|
||||
void clear_chain(chain *c);
|
||||
bool renew_chain(chain *c, size_t width, size_t height);
|
||||
|
||||
pixel create_pixel(uint16_t x, uint16_t y, unsigned char r, unsigned char g, unsigned char b, unsigned char a);
|
||||
pixel create_pixel(uint16_t x, uint16_t y, color c);
|
||||
inline size_t xy2pos (uint16_t x, uint16_t y) {return (y*(UINT16_MAX+1)+x);}
|
||||
|
||||
inline void point2xy(point pt, float *x, float *y) {
|
||||
*x = pt.s.x + pt.s.x_fract/float(UINT8_MAX+1);
|
||||
*y = pt.s.y + pt.s.y_fract/float(UINT8_MAX+1);
|
||||
}
|
||||
|
||||
inline uint32_t pixel_distance (pixel p1, pixel p2 ) {
|
||||
int32_t xd = p1.x-p2.x;
|
||||
int32_t yd = p1.y-p2.y;
|
||||
|
||||
return xd*xd+yd*yd;
|
||||
}
|
||||
|
||||
inline uint32_t approx_point_distance (point p1, point p2) {
|
||||
int32_t xd = p1.s.x-p2.s.x;
|
||||
int32_t yd = p1.s.y-p2.s.y;
|
||||
|
||||
return xd*xd + yd*yd;
|
||||
}
|
||||
|
||||
inline uint64_t point_distance (point p1, point p2) {
|
||||
uint64_t xd = std::abs(((UINT8_MAX+1)*p1.s.x+p1.s.x_fract) - ((UINT8_MAX+1)*p2.s.x+p2.s.x_fract));
|
||||
uint64_t yd = std::abs(((UINT8_MAX+1)*p1.s.y+p1.s.y_fract) - ((UINT8_MAX+1)*p2.s.y+p2.s.y_fract));
|
||||
|
||||
return (xd*xd + yd*yd);
|
||||
}
|
||||
|
||||
inline double distance(double x1, double y1, double x2, double y2) {
|
||||
double xd = x1-x2;
|
||||
double yd = y1-y2;
|
||||
|
||||
return xd*xd+yd*yd;
|
||||
}
|
||||
|
||||
inline bool point_has_pixel(point p) {
|
||||
return (p.s.flags & HAS_PIXEL);
|
||||
}
|
||||
|
||||
inline bool point_has_fluid(point p) {
|
||||
return (p.s.flags & HAS_FLUID);
|
||||
}
|
||||
|
||||
const char * get_version();
|
||||
size_t get_warning();
|
||||
bool uses_opencv();
|
||||
|
||||
}
|
||||
|
||||
#include "thread.h"
|
||||
#include "morph.h"
|
||||
|
||||
#endif
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2014 Erich Erstu
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
181
src/color.cpp
Normal file
181
src/color.cpp
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* See Copyright Notice in atomorph.h
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include "color.h"
|
||||
|
||||
namespace am {
|
||||
|
||||
color create_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a) {
|
||||
color c;
|
||||
c.r = r;
|
||||
c.g = g;
|
||||
c.b = b;
|
||||
c.a = a;
|
||||
return c;
|
||||
}
|
||||
|
||||
color create_color(double r, double g, double b, double a) {
|
||||
color c;
|
||||
c.r = std::round(r*255.0);
|
||||
c.g = std::round(g*255.0);
|
||||
c.b = std::round(b*255.0);
|
||||
c.a = std::round(a*255.0);
|
||||
return c;
|
||||
}
|
||||
|
||||
color rgb_to_hsp(color c) {
|
||||
color hsp = c;
|
||||
|
||||
double r,g,b,h,s,p;
|
||||
r = c.r/255.0;
|
||||
g = c.g/255.0;
|
||||
b = c.b/255.0;
|
||||
RGBtoHSP(r,g,b,&h,&s,&p);
|
||||
hsp.r = std::round(h*255.0);
|
||||
hsp.g = std::round(s*255.0);
|
||||
hsp.b = std::round(p*255.0);
|
||||
|
||||
return hsp;
|
||||
}
|
||||
|
||||
color hsp_to_rgb(color c) {
|
||||
color rgb = c;
|
||||
|
||||
double r,g,b,h,s,p;
|
||||
h = c.r/255.0;
|
||||
s = c.g/255.0;
|
||||
p = c.b/255.0;
|
||||
HSPtoRGB(h,s,p,&r,&g,&b);
|
||||
rgb.r = std::min(std::round(r*255.0), 255.0);
|
||||
rgb.g = std::min(std::round(g*255.0), 255.0);
|
||||
rgb.b = std::min(std::round(b*255.0), 255.0);
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
const double Pr = 0.299;
|
||||
const double Pg = 0.587;
|
||||
const double Pb = 0.114;
|
||||
|
||||
// public domain function by Darel Rex Finley, 2006
|
||||
//
|
||||
// This function expects the passed-in values to be on a scale
|
||||
// of 0 to 1, and uses that same scale for the return values.
|
||||
//
|
||||
// See description/examples at alienryderflex.com/hsp.html
|
||||
void RGBtoHSP(double R, double G, double B, double *H, double *S, double *P) {
|
||||
// Calculate the Perceived brightness.
|
||||
*P=sqrt(R*R*Pr+G*G*Pg+B*B*Pb);
|
||||
|
||||
// Calculate the Hue and Saturation. (This part works
|
||||
// the same way as in the HSV/B and HSL systems???.)
|
||||
if (R==G && R==B) {
|
||||
*H=0.;
|
||||
*S=0.;
|
||||
return;
|
||||
}
|
||||
|
||||
if (R>=G && R>=B) {// R is largest
|
||||
if (B>=G) {
|
||||
*H=6./6.-1./6.*(B-G)/(R-G);
|
||||
*S=1.-G/R;
|
||||
}
|
||||
else {
|
||||
*H=0./6.+1./6.*(G-B)/(R-B);
|
||||
*S=1.-B/R;
|
||||
}
|
||||
}
|
||||
else if (G>=R && G>=B) {// G is largest
|
||||
if (R>=B) {
|
||||
*H=2./6.-1./6.*(R-B)/(G-B); *S=1.-B/G;
|
||||
}
|
||||
else {
|
||||
*H=2./6.+1./6.*(B-R)/(G-R); *S=1.-R/G;
|
||||
}
|
||||
}
|
||||
else {// B is largest
|
||||
if (G>=R) {
|
||||
*H=4./6.-1./6.*(G-R)/(B-R); *S=1.-R/B;
|
||||
}
|
||||
else {
|
||||
*H=4./6.+1./6.*(R-G)/(B-G); *S=1.-G/B;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// public domain function by Darel Rex Finley, 2006
|
||||
//
|
||||
// This function expects the passed-in values to be on a scale
|
||||
// of 0 to 1, and uses that same scale for the return values.
|
||||
//
|
||||
// Note that some combinations of HSP, even if in the scale
|
||||
// 0-1, may return RGB values that exceed a value of 1. For
|
||||
// example, if you pass in the HSP color 0,1,1, the result
|
||||
// will be the RGB color 2.037,0,0.
|
||||
//
|
||||
// See description/examples at alienryderflex.com/hsp.html
|
||||
void HSPtoRGB(double H, double S, double P, double *R, double *G, double *B) {
|
||||
double part, minOverMax=1.-S ;
|
||||
|
||||
if (minOverMax>0.) {
|
||||
if ( H<1./6.) { // R>G>B
|
||||
H= 6.*( H-0./6.); part=1.+H*(1./minOverMax-1.);
|
||||
*B=P/sqrt(Pr/minOverMax/minOverMax+Pg*part*part+Pb);
|
||||
*R=(*B)/minOverMax; *G=(*B)+H*((*R)-(*B));
|
||||
}
|
||||
else if ( H<2./6.) { // G>R>B
|
||||
H= 6.*(-H+2./6.); part=1.+H*(1./minOverMax-1.);
|
||||
*B=P/sqrt(Pg/minOverMax/minOverMax+Pr*part*part+Pb);
|
||||
*G=(*B)/minOverMax; *R=(*B)+H*((*G)-(*B));
|
||||
}
|
||||
else if ( H<3./6.) { // G>B>R
|
||||
H= 6.*( H-2./6.); part=1.+H*(1./minOverMax-1.);
|
||||
*R=P/sqrt(Pg/minOverMax/minOverMax+Pb*part*part+Pr);
|
||||
*G=(*R)/minOverMax; *B=(*R)+H*((*G)-(*R));
|
||||
}
|
||||
else if ( H<4./6.) { // B>G>R
|
||||
H= 6.*(-H+4./6.); part=1.+H*(1./minOverMax-1.);
|
||||
*R=P/sqrt(Pb/minOverMax/minOverMax+Pg*part*part+Pr);
|
||||
*B=(*R)/minOverMax; *G=(*R)+H*((*B)-(*R));
|
||||
}
|
||||
else if ( H<5./6.) { // B>R>G
|
||||
H= 6.*( H-4./6.); part=1.+H*(1./minOverMax-1.);
|
||||
*G=P/sqrt(Pb/minOverMax/minOverMax+Pr*part*part+Pg);
|
||||
*B=(*G)/minOverMax; *R=(*G)+H*((*B)-(*G)); }
|
||||
else { // R>B>G
|
||||
H= 6.*(-H+6./6.); part=1.+H*(1./minOverMax-1.);
|
||||
*G=P/sqrt(Pr/minOverMax/minOverMax+Pb*part*part+Pg);
|
||||
*R=(*G)/minOverMax; *B=(*G)+H*((*R)-(*G));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( H<1./6.) { // R>G>B
|
||||
H= 6.*( H-0./6.); *R=sqrt(P*P/(Pr+Pg*H*H)); *G=(*R)*H; *B=0.;
|
||||
}
|
||||
else if ( H<2./6.) { // G>R>B
|
||||
H= 6.*(-H+2./6.); *G=sqrt(P*P/(Pg+Pr*H*H)); *R=(*G)*H; *B=0.;
|
||||
}
|
||||
else if ( H<3./6.) { // G>B>R
|
||||
H= 6.*( H-2./6.); *G=sqrt(P*P/(Pg+Pb*H*H)); *B=(*G)*H; *R=0.;
|
||||
}
|
||||
else if ( H<4./6.) { // B>G>R
|
||||
H= 6.*(-H+4./6.); *B=sqrt(P*P/(Pb+Pg*H*H)); *G=(*B)*H; *R=0.;
|
||||
}
|
||||
else if ( H<5./6.) { // B>R>G
|
||||
H= 6.*( H-4./6.); *B=sqrt(P*P/(Pb+Pr*H*H)); *R=(*B)*H; *G=0.;
|
||||
}
|
||||
else { // R>B>G
|
||||
H= 6.*(-H+6./6.); *R=sqrt(P*P/(Pr+Pb*H*H)); *B=(*R)*H; *G=0.;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
35
src/color.h
Normal file
35
src/color.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* See Copyright Notice in atomorph.h
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace am {
|
||||
|
||||
typedef struct color {
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
uint8_t a;
|
||||
} color;
|
||||
|
||||
color create_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
|
||||
color create_color(double r, double g, double b, double a);
|
||||
|
||||
inline double color_distance(color c1, color c2) {
|
||||
int16_t rd = c1.r-c2.r;
|
||||
int16_t gd = c1.g-c2.g;
|
||||
int16_t bd = c1.b-c2.b;
|
||||
int16_t ad = c1.a-c2.a;
|
||||
|
||||
return sqrt(rd*rd+gd*gd+bd*bd+ad*ad)/510.0;
|
||||
}
|
||||
|
||||
color rgb_to_hsp(color c);
|
||||
color hsp_to_rgb(color c);
|
||||
|
||||
void RGBtoHSP(double R, double G, double B, double *H, double *S, double *P);
|
||||
void HSPtoRGB(double H, double S, double P, double *R, double *G, double *B);
|
||||
|
||||
}
|
||||
|
||||
602
src/fluidmodel.cpp
Normal file
602
src/fluidmodel.cpp
Normal file
@@ -0,0 +1,602 @@
|
||||
/*
|
||||
* See Copyright Notice in fluidmodel.h
|
||||
* See Copyright Notice in atomorph.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
|
||||
#include "fluidmodel.h"
|
||||
|
||||
Material::Material(double m_,
|
||||
double rd_,
|
||||
double k_,
|
||||
double v_,
|
||||
double d_,
|
||||
double g_)
|
||||
:m(m_),
|
||||
rd(rd_),
|
||||
k(k_),
|
||||
v(v_),
|
||||
d(d_),
|
||||
g(g_) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
Particle::Particle() {
|
||||
|
||||
}
|
||||
|
||||
Particle::Particle(Material *mat_,
|
||||
double x_,
|
||||
double y_,
|
||||
double u_,
|
||||
double v_)
|
||||
:mat(mat_),
|
||||
x(x_),
|
||||
y(y_),
|
||||
u(u_),
|
||||
v(v_),
|
||||
dudx(0.0),
|
||||
dudy(0.0),
|
||||
dvdx(0.0),
|
||||
dvdy(0.0),
|
||||
cx(0.0),
|
||||
cy(0.0) {
|
||||
|
||||
std::fill(px, px + 3, 0.0);
|
||||
std::fill(gx, gx + 3, 0.0);
|
||||
std::fill(py, py + 3, 0.0);
|
||||
std::fill(gy, gy + 3, 0.0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
Node::Node()
|
||||
:m(0.0),
|
||||
d(0.0),
|
||||
gx(0.0),
|
||||
gy(0.0),
|
||||
u(0.0),
|
||||
v(0.0),
|
||||
ax(0.0),
|
||||
ay(0.0),
|
||||
active(false) {
|
||||
|
||||
}
|
||||
|
||||
void Node::clear() {
|
||||
m = d = gx = gy = u = v = ax = ay = 0.0;
|
||||
r = 0.0;
|
||||
g = 0.0;
|
||||
b = 0.0;
|
||||
a = 0.0;
|
||||
weight = 0.0;
|
||||
active = false;
|
||||
}
|
||||
|
||||
void Particle::clear() {
|
||||
u = 0.0;
|
||||
v = 0.0;
|
||||
dudx = 0.0;
|
||||
dudy = 0.0;
|
||||
dvdx = 0.0;
|
||||
dvdy = 0.0;
|
||||
cx = 0.0;
|
||||
cy = 0.0;
|
||||
strength = 1.0;
|
||||
std::fill(px, px + 3, 0.0);
|
||||
std::fill(gx, gx + 3, 0.0);
|
||||
std::fill(py, py + 3, 0.0);
|
||||
std::fill(gy, gy + 3, 0.0);
|
||||
source_owner = false;
|
||||
}
|
||||
|
||||
void Particle::copy_from(Particle *p) {
|
||||
x = p->x;
|
||||
y = p->y;
|
||||
gravity_x = p->gravity_x;
|
||||
gravity_y = p->gravity_y;
|
||||
freedom_r = p->freedom_r;
|
||||
R = p->R; G = p->G; B = p->B; A = p->A;
|
||||
r = p->r; g = p->g; b = p->b; a = p->a;
|
||||
}
|
||||
|
||||
FluidModel::FluidModel(unsigned gsizeX_,
|
||||
unsigned gsizeY_,
|
||||
unsigned particle_count_)
|
||||
:particles(NULL),
|
||||
gsizeX(gsizeX_),
|
||||
gsizeY(gsizeY_),
|
||||
particle_count(particle_count_),
|
||||
active(NULL),
|
||||
activeCount(0),
|
||||
water(1.0, 1.0, 1.0, 1.0, 1.0, 1.0),
|
||||
pressed(false),
|
||||
pressedprev(false),
|
||||
mx(0.0),
|
||||
my(0.0),
|
||||
mxprev(0.0),
|
||||
myprev(0.0),
|
||||
grid(NULL),
|
||||
lines(NULL) {
|
||||
|
||||
grid = new Node *[gsizeX];
|
||||
for (unsigned i = 0; i < gsizeX; ++i) {
|
||||
grid[i] = new Node[gsizeY];
|
||||
}
|
||||
for (size_t j=0; j<gsizeY; ++j) {
|
||||
for (size_t i=0; i<gsizeX; ++i) {
|
||||
grid[i][j].pos = (j * gsizeX)+i;
|
||||
}
|
||||
}
|
||||
|
||||
active = new Node*[gsizeX * gsizeY];
|
||||
|
||||
particles = new Particle[particle_count];
|
||||
|
||||
for (size_t i=0; i< particle_count; i++) {
|
||||
particles[i] = Particle(&water, gsizeX/2,
|
||||
gsizeY/2,
|
||||
0.0,
|
||||
0.0);
|
||||
}
|
||||
|
||||
lines = new Line[particle_count];
|
||||
}
|
||||
|
||||
|
||||
FluidModel::~FluidModel() {
|
||||
for (unsigned i = 0; i < gsizeX; ++i) {
|
||||
delete [] grid[i];
|
||||
}
|
||||
delete [] grid;
|
||||
|
||||
delete [] active;
|
||||
|
||||
delete [] particles;
|
||||
|
||||
delete [] lines;
|
||||
}
|
||||
|
||||
|
||||
void FluidModel::step(size_t steps_left, double freedom_radius, [[maybe_unused]]double morph_time) {
|
||||
bool drag = false;
|
||||
double mdx = 0.0, mdy = 0.0;
|
||||
|
||||
if (pressed and pressedprev) {
|
||||
drag = true;
|
||||
mdx = (mx - mxprev);
|
||||
mdy = (my - myprev);
|
||||
}
|
||||
|
||||
pressedprev = pressed;
|
||||
mxprev = mx;
|
||||
myprev = my;
|
||||
|
||||
for (unsigned i = 0; i < activeCount; ++i) {
|
||||
active[i]->clear();
|
||||
}
|
||||
activeCount = 0;
|
||||
|
||||
double phi;
|
||||
double x, y;
|
||||
double fx = 0.0, fy = 0.0;
|
||||
|
||||
Particle *p;
|
||||
Node *n;
|
||||
|
||||
for (unsigned i = 0; i < particle_count; ++i) {
|
||||
p = particles + i;
|
||||
if (p->active == false) continue; // CUSTOMIZATION
|
||||
|
||||
p->cx = static_cast<int>(p->x - 0.5);
|
||||
p->cy = static_cast<int>(p->y - 0.5);
|
||||
|
||||
x = p->cx - p->x;
|
||||
|
||||
p->px[0] = (0.5 * x * x + 1.5 * x + 1.125);
|
||||
p->gx[0] = (x + 1.5);
|
||||
x += 1.0;
|
||||
p->px[1] = (-x * x + 0.75);
|
||||
p->gx[1] = (-2.0 * x);
|
||||
x += 1.0;
|
||||
p->px[2] = (0.5 * x * x - 1.5 * x + 1.125);
|
||||
p->gx[2] = (x - 1.5);
|
||||
|
||||
y = p->cy - p->y;
|
||||
|
||||
p->py[0] = (0.5 * y * y + 1.5 * y + 1.125);
|
||||
p->gy[0] = (y + 1.5);
|
||||
y += 1.0;
|
||||
p->py[1] = (-y * y + 0.75);
|
||||
p->gy[1] = (-2.0 * y);
|
||||
y += 1.0;
|
||||
p->py[2] = (0.5 * y * y - 1.5 * y + 1.125);
|
||||
p->gy[2] = (y - 1.5);
|
||||
|
||||
for (unsigned i = 0; i < 3; ++i) {
|
||||
for (unsigned j = 0; j < 3; ++j) {
|
||||
n = grid[p->cx + i] + p->cy + j;
|
||||
if (not n->active) {
|
||||
active[activeCount++] = n;
|
||||
n->active = true;
|
||||
}
|
||||
|
||||
phi = p->px[i] * p->py[j];
|
||||
n->m += phi * p->mat->m;
|
||||
n->d += phi;
|
||||
n->gx += p->gx[i] * p->py[j];
|
||||
n->gy += p->px[i] * p->gy[j];
|
||||
|
||||
// CUSTOM:
|
||||
if (p->mature && p->strength > 0.0) {
|
||||
double new_w = p->strength;
|
||||
double old_w = n->weight;
|
||||
double sum_w = new_w + old_w;
|
||||
n->r = (old_w * n->r + new_w * p->r)/sum_w;
|
||||
n->g = (old_w * n->g + new_w * p->g)/sum_w;
|
||||
n->b = (old_w * n->b + new_w * p->b)/sum_w;
|
||||
n->a = (old_w * n->a + new_w * p->a)/sum_w;
|
||||
n->weight = sum_w;
|
||||
}
|
||||
// END OF CUSTOM
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
unsigned cx, cy;
|
||||
unsigned cxi, cyi;
|
||||
|
||||
double pdx, pdy;
|
||||
double C20, C02, C30, C03;
|
||||
double C21, C31, C12, C13, C11;
|
||||
|
||||
double csum1, csum2;
|
||||
|
||||
double u, u2, u3;
|
||||
double v, v2, v3;
|
||||
|
||||
double vx, vy;
|
||||
|
||||
double density;
|
||||
double pressure;
|
||||
double weight;
|
||||
|
||||
Node *n01, *n02, *n11, *n12;
|
||||
|
||||
for (unsigned i = 0; i < particle_count; ++i) {
|
||||
p = particles + i;
|
||||
if (p->active == false) continue; // CUSTOMIZATION
|
||||
|
||||
cx = static_cast<int>(p->x);
|
||||
cy = static_cast<int>(p->y);
|
||||
cxi = cx + 1;
|
||||
cyi = cy + 1;
|
||||
|
||||
n01 = grid[cx] + cy;
|
||||
n02 = grid[cx] + cyi;
|
||||
n11 = grid[cxi] + cy;
|
||||
n12 = grid[cxi] + cyi;
|
||||
|
||||
pdx = n11->d - n01->d;
|
||||
pdy = n02->d - n01->d;
|
||||
C20 = 3.0 * pdx - n11->gx - 2.0 * n01->gx;
|
||||
C02 = 3.0 * pdy - n02->gy - 2.0 * n01->gy;
|
||||
C30 = -2.0 * pdx + n11->gx + n01->gx;
|
||||
C03 = -2.0 * pdy + n02->gy + n01->gy;
|
||||
|
||||
csum1 = n01->d + n01->gy + C02 + C03;
|
||||
csum2 = n01->d + n01->gx + C20 + C30;
|
||||
|
||||
C21 = 3.0 * n12->d - 2.0 * n02->gx - n12->gx -
|
||||
3.0 * csum1 - C20;
|
||||
C31 = -2.0 * n12->d + n02->gx + n12->gx +
|
||||
2.0 * csum1 - C30;
|
||||
C12 = 3.0 * n12->d - 2.0 * n11->gy - n12->gy -
|
||||
3.0 * csum2 - C02;
|
||||
C13 = -2.0 * n12->d + n11->gy + n12->gy +
|
||||
2.0 * csum2 - C03;
|
||||
C11 = n02->gx - C13 - C12 - n01->gx;
|
||||
|
||||
u = p->x - cx;
|
||||
u2 = u * u;
|
||||
u3 = u * u2;
|
||||
v = p->y - cy;
|
||||
v2 = v * v;
|
||||
v3 = v * v2;
|
||||
|
||||
density = n01->d + n01->gx * u +
|
||||
n01->gy * v + C20 * u2 +
|
||||
C02 * v2 + C30 * u3 +
|
||||
C03 * v3 + C21 * u2 * v +
|
||||
C31 * u3 * v + C12 * u * v2 +
|
||||
C13 * u * v3 + C11 * u * v;
|
||||
|
||||
pressure = density - 1.0;
|
||||
if (pressure > 2.0) {
|
||||
pressure = 2.0;
|
||||
}
|
||||
|
||||
fx = fy = 0.0;
|
||||
|
||||
if (p->x < 4.0) {
|
||||
fx += p->mat->m * (4.0 - p->x);
|
||||
} else if (p->x > gsizeX - 5) {
|
||||
fx += p->mat->m * (gsizeX - 5 - p->x);
|
||||
}
|
||||
|
||||
if (p->y < 4.0) {
|
||||
fy += p->mat->m * (4.0 - p->y);
|
||||
} else if (p->y > gsizeY - 5) {
|
||||
fy += p->mat->m * (gsizeY - 5 - p->y);
|
||||
}
|
||||
|
||||
if (drag) {
|
||||
vx = fabs(p->x - mx);
|
||||
vy = fabs(p->y - my);
|
||||
if (vx < 10.0 and vy < 10.0) {
|
||||
weight = p->mat->m * (1.0 - vx * 0.1) *
|
||||
(1.0 - vy * 0.1);
|
||||
fx += weight * (mdx - p->u);
|
||||
fy += weight * (mdy - p->v);
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < 3; ++i) {
|
||||
for (unsigned j = 0; j < 3; ++j) {
|
||||
n = grid[p->cx + i] + p->cy + j;
|
||||
phi = p->px[i] * p->py[j];
|
||||
n->ax += -((p->gx[i] * p->py[j]) * pressure) + fx * phi;
|
||||
n->ay += -((p->px[i] * p->gy[j]) * pressure) + fy * phi;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < activeCount; ++i) {
|
||||
n = active[i];
|
||||
if (n->m > 0.0) {
|
||||
n->ax /= n->m;
|
||||
n->ay /= n->m;
|
||||
|
||||
//ORIGINALLY GRAVITY WAS INDICATED BY THESE:
|
||||
//n->ay += 0.03;
|
||||
//n->ax += 0.03;
|
||||
}
|
||||
}
|
||||
|
||||
double mu, mv;
|
||||
|
||||
for (unsigned pi = 0; pi < particle_count; ++pi) {
|
||||
p = particles + pi;
|
||||
if (p->active == false) continue; // CUSTOMIZATION
|
||||
|
||||
for (unsigned i = 0; i < 3; ++i) {
|
||||
for (unsigned j = 0; j < 3; ++j) {
|
||||
n = grid[p->cx + i] + p->cy + j;
|
||||
phi = p->px[i] * p->py[j];
|
||||
|
||||
/* CUSTOM STUFF */
|
||||
double custom_ax=0.0;
|
||||
double custom_ay=0.0;
|
||||
{
|
||||
double x1 = p->x;
|
||||
double y1 = p->y;
|
||||
double x2 = p->gravity_x;
|
||||
double y2 = p->gravity_y;
|
||||
double a = 0.03;
|
||||
|
||||
// Gravitate towards (x2, y2).
|
||||
double A = std::abs(y1 - y2);
|
||||
double B = std::abs(x1 - x2);
|
||||
double C = std::sqrt(A*A + B*B);
|
||||
|
||||
if (a >= C) a = C;
|
||||
|
||||
if (B <= 0.0) {
|
||||
if (y2 <= y1) custom_ay -= a;
|
||||
else custom_ay += a;
|
||||
}
|
||||
else if (C > 0.0) {
|
||||
double dx = (a * B) / C;
|
||||
double dy = (A *dx) / B;
|
||||
|
||||
if (x1 <= x2) custom_ax += dx;
|
||||
else custom_ax -= dx;
|
||||
|
||||
if (y1 <= y2) custom_ay += dy;
|
||||
else custom_ay -= dy;
|
||||
}
|
||||
}
|
||||
/* END OF CUSTOM STUFF */
|
||||
|
||||
p->u += phi * (n->ax+custom_ax);
|
||||
p->v += phi * (n->ay+custom_ay);
|
||||
|
||||
}
|
||||
}
|
||||
mu = p->mat->m * p->u;
|
||||
mv = p->mat->m * p->v;
|
||||
if (p->mature == false) {
|
||||
mu *= 0.0;
|
||||
mv *= 0.0;
|
||||
}
|
||||
for (unsigned i = 0; i < 3; ++i) {
|
||||
for (unsigned j = 0; j < 3; ++j) {
|
||||
n = grid[p->cx + i] + p->cy + j;
|
||||
phi = p->px[i] * p->py[j];
|
||||
n->u += phi * mu;
|
||||
n->v += phi * mv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < activeCount; ++i) {
|
||||
n = active[i];
|
||||
if (n->m > 0.0) {
|
||||
n->u /= n->m;
|
||||
n->v /= n->m;
|
||||
}
|
||||
}
|
||||
|
||||
double gu, gv;
|
||||
|
||||
for (unsigned i = 0; i < particle_count; ++i) {
|
||||
p = particles + i;
|
||||
|
||||
// CUSTOMIZATION:
|
||||
if (p->active == false) continue;
|
||||
double nR = 0.0, nG = 0.0, nB = 0.0, nA = 0.0;
|
||||
double weight = 0.0;
|
||||
// END OF CUSTOMIZATION
|
||||
|
||||
gu = 0.0;
|
||||
gv = 0.0;
|
||||
for (unsigned ii = 0; ii < 3; ++ii) {
|
||||
for (unsigned j = 0; j < 3; ++j) {
|
||||
n = grid[p->cx + ii] + p->cy + j;
|
||||
phi = p->px[ii] * p->py[j];
|
||||
gu += phi * n->u;
|
||||
gv += phi * n->v;
|
||||
|
||||
if (n->weight > 0.0) {
|
||||
weight += n->weight;
|
||||
nR += n->r * n->weight;
|
||||
nG += n->g * n->weight;
|
||||
nB += n->b * n->weight;
|
||||
nA += n->a * n->weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CUSTOMIZATION:
|
||||
if (weight > 0.0) {
|
||||
double wr = 1.0;
|
||||
double wg = 1.0;
|
||||
double wb = 1.0;
|
||||
double wa = 1.0;
|
||||
nR /= weight; wr = std::abs(nR - p->R);
|
||||
nG /= weight; wg = std::abs(nG - p->G);
|
||||
nB /= weight; wb = std::abs(nB - p->B);
|
||||
nA /= weight; wa = std::abs(nA - p->A);
|
||||
|
||||
if (p->mature == false) {
|
||||
p->r = nR;
|
||||
p->g = nG;
|
||||
p->b = nB;
|
||||
p->a = nA;
|
||||
}
|
||||
else {
|
||||
p->r = (1.0 - wr) * p->r + wr * nR;
|
||||
p->g = (1.0 - wg) * p->g + wg * nG;
|
||||
p->b = (1.0 - wb) * p->b + wb * nB;
|
||||
p->a = (1.0 - wa) * p->a + wa * nA;
|
||||
}
|
||||
}
|
||||
// END OF CUSTOMIZATION
|
||||
|
||||
p->x += gu;
|
||||
p->y += gv;
|
||||
|
||||
/* CUSTOM STUFF */
|
||||
{
|
||||
double x1 = p->x;
|
||||
double y1 = p->y;
|
||||
double x2 = p->gravity_x;
|
||||
double y2 = p->gravity_y;
|
||||
|
||||
// Gravitate towards (x2, y2) if the distance
|
||||
// is greater than freedom radius.
|
||||
double A = std::abs(y1 - y2);
|
||||
double B = std::abs(x1 - x2);
|
||||
double C = std::sqrt(A*A + B*B);
|
||||
|
||||
double r = freedom_radius * p->freedom_r;
|
||||
if (C > r) {
|
||||
double mx = 0.0;
|
||||
double my = 0.0;
|
||||
|
||||
double a = C - r;
|
||||
if (a >= C) a = C;
|
||||
|
||||
if (B <= 0.0) {
|
||||
if (y2 <= y1) my -= a;
|
||||
else my += a;
|
||||
}
|
||||
else if (C > 0.0) {
|
||||
double dx = (a * B) / C;
|
||||
double dy = (A *dx) / B;
|
||||
|
||||
if (x1 <= x2) mx += dx;
|
||||
else mx -= dx;
|
||||
|
||||
if (y1 <= y2) my += dy;
|
||||
else my -= dy;
|
||||
}
|
||||
|
||||
double w = 1.0 / (steps_left + 1);
|
||||
|
||||
mx *= w;
|
||||
my *= w;
|
||||
|
||||
p->x += mx;
|
||||
p->y += my;
|
||||
}
|
||||
}
|
||||
/* END OF CUSTOM STUFF */
|
||||
|
||||
p->u += gu - p->u;
|
||||
p->v += gv - p->v;
|
||||
if (p->x < 1.0) {
|
||||
p->x = 1.0 + static_cast<double>(rand()) / RAND_MAX * 0.01;
|
||||
p->u = 0.0;
|
||||
} else if (p->x > gsizeX - 2) {
|
||||
p->x = gsizeX - 2 - static_cast<double>(rand()) / RAND_MAX * 0.01;
|
||||
p->u = 0.0;
|
||||
}
|
||||
if (p->y < 1.0) {
|
||||
p->y = 1.0 + static_cast<double>(rand()) / RAND_MAX * 0.01;
|
||||
p->v = 0.0;
|
||||
} else if (p->y > gsizeY - 2) {
|
||||
p->y = gsizeY - 2 - static_cast<double>(rand()) / RAND_MAX * 0.01;
|
||||
p->v = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
// ORIGINALLY THIS PIECE OF CODE WAS HERE
|
||||
// BUT FOR FLUID MORPHING IT IS NOT NEEDED:
|
||||
/*for (unsigned i = 0; i < particle_count; ++i) {
|
||||
p = particles + i;
|
||||
if (p->inactive) continue; // CUSTOMIZATION
|
||||
|
||||
lines[i].x1 = p->x;
|
||||
lines[i].y1 = p->y;
|
||||
lines[i].x2 = p->x - p->u;
|
||||
lines[i].y2 = p->y - p->v;
|
||||
}*/
|
||||
}
|
||||
|
||||
void FluidModel::setPressed(bool b) {
|
||||
pressed = b;
|
||||
}
|
||||
|
||||
void FluidModel::setMovePos(double x, double y) {
|
||||
mx = x;
|
||||
my = y;
|
||||
}
|
||||
|
||||
const Line * FluidModel::getLines() {
|
||||
return lines;
|
||||
}
|
||||
|
||||
Particle * FluidModel::getParticles() {
|
||||
return particles;
|
||||
}
|
||||
|
||||
Material * FluidModel::getMaterial() {
|
||||
return &water;
|
||||
}
|
||||
|
||||
169
src/fluidmodel.h
Normal file
169
src/fluidmodel.h
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* See Copyright Notice at the end of this file.
|
||||
*/
|
||||
|
||||
#ifndef FLUIDMODEL_H
|
||||
#define FLUIDMODEL_H
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
struct Line {
|
||||
double x1, y1;
|
||||
double x2, y2;
|
||||
};
|
||||
|
||||
struct Material {
|
||||
|
||||
Material(double m_,
|
||||
double rd_,
|
||||
double k_,
|
||||
double v_,
|
||||
double d_,
|
||||
double g_);
|
||||
|
||||
double m; //mass
|
||||
double rd;
|
||||
double k;
|
||||
double v;
|
||||
double d;
|
||||
double g;
|
||||
};
|
||||
|
||||
|
||||
struct Particle {
|
||||
|
||||
Particle();
|
||||
Particle(Material *mat_,
|
||||
double x_,
|
||||
double y_,
|
||||
double u_,
|
||||
double v_);
|
||||
|
||||
void clear();
|
||||
void copy_from(Particle *p);
|
||||
|
||||
Material *mat;
|
||||
|
||||
double x;
|
||||
double y;
|
||||
double u;
|
||||
double v;
|
||||
|
||||
double dudx;
|
||||
double dudy;
|
||||
double dvdx;
|
||||
double dvdy;
|
||||
unsigned cx;
|
||||
unsigned cy;
|
||||
|
||||
double px[3];
|
||||
double py[3];
|
||||
double gx[3];
|
||||
double gy[3];
|
||||
|
||||
// CUSTOM VARIABLES:
|
||||
double gravity_x;
|
||||
double gravity_y;
|
||||
double freedom_r; // freedom radius multiplier
|
||||
bool active;
|
||||
bool mature;
|
||||
double R,G,B,A; // ideal color (does not blend)
|
||||
double r,g,b,a; // current color (blends over time)
|
||||
size_t destination_pos;
|
||||
size_t source_pos;
|
||||
size_t frame_key;
|
||||
double strength; // how easily it regains its color
|
||||
bool hack;
|
||||
bool source_owner; // true when it was first one to occupy the source location.
|
||||
// END OF CUSTOM VARIABLES
|
||||
};
|
||||
|
||||
|
||||
struct Node {
|
||||
|
||||
Node();
|
||||
|
||||
void clear();
|
||||
|
||||
double m;
|
||||
double d;
|
||||
double gx;
|
||||
double gy;
|
||||
double u;
|
||||
double v;
|
||||
double ax;
|
||||
double ay;
|
||||
bool active;
|
||||
size_t pos;
|
||||
double r,g,b,a;
|
||||
double weight;
|
||||
};
|
||||
|
||||
|
||||
class FluidModel {
|
||||
|
||||
public:
|
||||
|
||||
FluidModel(unsigned gsizeX_,
|
||||
unsigned gsizeY_,
|
||||
unsigned particle_count);
|
||||
~FluidModel();
|
||||
|
||||
void setPressed(bool b);
|
||||
void setMovePos(double x, double y);
|
||||
|
||||
void step(size_t steps_left, double freedom_radius, double t);
|
||||
const Line * getLines();
|
||||
Material * getMaterial();
|
||||
Particle * getParticles();
|
||||
|
||||
unsigned get_particle_count(void) {return particle_count;}
|
||||
private:
|
||||
|
||||
Particle * particles;
|
||||
unsigned gsizeX;
|
||||
unsigned gsizeY;
|
||||
unsigned particle_count;
|
||||
Node ** active;
|
||||
unsigned activeCount;
|
||||
Material water;
|
||||
|
||||
bool pressed;
|
||||
bool pressedprev;
|
||||
|
||||
double mx;
|
||||
double my;
|
||||
double mxprev;
|
||||
double myprev;
|
||||
|
||||
Node ** grid;
|
||||
|
||||
Line * lines;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* This version:
|
||||
* Copyright Xueqiao Xu ( http://code.google.com/p/mycodeplayground )
|
||||
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
|
||||
* Download from: http://code.google.com/p/mycodeplayground
|
||||
|
||||
* Python version:
|
||||
* Copyright Xueqiao Xu ( http://code.google.com/p/mycodeplayground )
|
||||
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
|
||||
* Download from: http://code.google.com/p/mycodeplayground
|
||||
|
||||
* Javascript version:
|
||||
* Copyright Stephen Sinclair (radarsat1) ( http://www.music.mcgill.ca/~sinclair )
|
||||
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
|
||||
* Download from: http://www.music.mcgill.ca/~sinclair/blog
|
||||
|
||||
* Flash version:
|
||||
* Copyright iunpin ( http://wonderfl.net/user/iunpin )
|
||||
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
|
||||
* Download from: http://wonderfl.net/c/6eu4
|
||||
|
||||
* Original Java version:
|
||||
* http://grantkot.com/MPM/Liquid.html
|
||||
*/
|
||||
|
||||
1573
src/morph.cpp
Normal file
1573
src/morph.cpp
Normal file
File diff suppressed because it is too large
Load Diff
147
src/morph.h
Normal file
147
src/morph.h
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* See Copyright Notice in atomorph.h
|
||||
*/
|
||||
|
||||
#include "atomorph.h"
|
||||
|
||||
namespace am {
|
||||
|
||||
class morph {
|
||||
public:
|
||||
morph();
|
||||
~morph();
|
||||
|
||||
void clear ();
|
||||
bool add_pixel (size_t frame, pixel px);
|
||||
bool add_frame (size_t frame);
|
||||
size_t get_pixel_count (size_t frame);
|
||||
size_t get_frame_key (double t);
|
||||
size_t get_blob_count (size_t frame);
|
||||
size_t get_blob_count ();
|
||||
pixel get_average_pixel (size_t frame);
|
||||
pixel get_average_pixel (size_t frame, size_t blob);
|
||||
pixel get_pixel (size_t frame, size_t position);
|
||||
color get_background (uint16_t x, uint16_t y, double t);
|
||||
point interpolate (point pt1, point pt2, double pt1_weight);
|
||||
pixel interpolate (pixel px1, pixel px2, double px1_weight);
|
||||
color interpolate (color c1, color c2, double c1_weight);
|
||||
color interpolate (color c1, color c2, double lag, double slope, double c1_weight);
|
||||
const blob* get_pixels (size_t blob, double t, std::vector<pixel> *to);
|
||||
void get_pixels (double t, std::vector<pixel> *to);
|
||||
void set_seed (unsigned seed);
|
||||
double get_time (size_t current_frame, size_t total_frames);
|
||||
double normalize_time (double t);
|
||||
|
||||
uint16_t get_width () {return width;}
|
||||
uint16_t get_height () {return height;}
|
||||
size_t get_frame_count () {return frames.size();}
|
||||
unsigned get_state () {return state;}
|
||||
void next_state () {skip_state = true;}
|
||||
const blob* get_blob (size_t f, size_t b) {return (has_blob(f, b) ? ((const blob*) frames[f].blobs[b]) : nullptr);}
|
||||
double get_energy () {return energy;}
|
||||
pixel blob2pixel (const blob *bl);
|
||||
void compute (); // If not busy yet, sets worker thread to run indefinitely.
|
||||
void iterate (size_t iterations); // If not busy yet, sets worker thread to run the defined number of iterations.
|
||||
void compute (double seconds); // If not busy yet, sets worker thread to run for the defined number of seconds.
|
||||
void suspend (); // Blocks the calling thread until morph is no longer busy. Returns when worker is paused.
|
||||
bool suspend (double timeout); // Blocks the calling thread for timeout seconds at maximum. Returns false on timeout.
|
||||
bool is_busy () const {return (worker.is_running() && !worker.is_paused());}
|
||||
|
||||
bool synchronize (); // Synchronizes data with the worker thread. Returns false when worker is busy at the moment.
|
||||
|
||||
void set_blob_delimiter (unsigned char d) {blob_delimiter = d;} // Color distance formula.
|
||||
void set_blob_threshold (double t) {blob_threshold = t;} // Color difference toleration.
|
||||
void set_blob_max_size (size_t s) {blob_max_size = s;} // Maximum size of a blob.
|
||||
void set_blob_min_size (size_t s) {blob_min_size = s;} // Minimum size of a blob.
|
||||
void set_blob_box_grip (uint16_t g) {blob_box_grip = g;} // Defines the bounding box.
|
||||
void set_blob_box_samples(size_t s) {blob_box_samples=s;} // Number of dust samples.
|
||||
void set_blob_number (size_t n) {blob_number = n;} // Preferred number of blobs.
|
||||
void set_blob_rgba_weight(unsigned char w) {blob_rgba_weight=w;} // Blob RGBA weight.
|
||||
void set_blob_size_weight(unsigned char w) {blob_size_weight=w;} // Blob size weight.
|
||||
void set_blob_xy_weight (unsigned char w) {blob_xy_weight =w;} // Blob location weight.
|
||||
void set_degeneration (size_t d) {degeneration =d;} // Solution degeneration period.
|
||||
void set_motion (unsigned char m) {motion =m;} // How to interpolate movement.
|
||||
void set_fading (unsigned char f) {fading =f;} // How to interpolate colors.
|
||||
void set_threads (size_t t) {threads =t;} // How many threads the worker thread can spawn.
|
||||
void set_cycle_length (size_t c) {cycle_length =c;} // How many times to morph per iteration.
|
||||
void set_feather (size_t f) {feather =f;} // Blob outer layers to fade out.
|
||||
void set_keep_background (bool k) {keep_background =k;} // Background is kept and cross-dissolved.
|
||||
void set_finite (bool f) {finite =f;} // Morph will not repeat itself.
|
||||
void set_show_blobs (unsigned b) {show_blobs =b;} // Determines how blobs are drawn.
|
||||
|
||||
// These change identifier, causing the morph to restart:
|
||||
void set_fluid (unsigned f); // Steps of fluid simulation per frame.
|
||||
void set_density (uint16_t d); // Key points per pixel.
|
||||
|
||||
void set_resolution (uint16_t w, uint16_t h);
|
||||
|
||||
private:
|
||||
inline bool has_pixel (size_t f, size_t pos) {return (has_frame(f) && frames[f].pixels.find(pos) != frames[f].pixels.end());}
|
||||
inline bool has_frame (size_t f ) const {return (frames.find(f) != frames.end());}
|
||||
inline bool has_blob (size_t f, size_t b ) {return (has_frame(f) && frames[f].blobs.size() > b);}
|
||||
void refresh_frames();
|
||||
|
||||
blob * find_blob_by_group(size_t frame_key, size_t group);
|
||||
|
||||
void draw_atoms(double t, std::vector<pixel> *image);
|
||||
void draw_fluid(double t, std::vector<pixel> *image);
|
||||
void step_fluid(size_t frame_key, double t, double time);
|
||||
|
||||
void update_particle (Particle *p, const blob * blob_before, const blob * blob_after, point **points,
|
||||
std::map<size_t, size_t>& src, std::map<size_t, size_t>& dest, double t, size_t y,
|
||||
size_t y_next, size_t frame_key, size_t next_frame_key, size_t chain_key, double time);
|
||||
|
||||
std::map<size_t, frame> frames;
|
||||
std::map<size_t, chain> chains; // Key is the blob's group.
|
||||
|
||||
unsigned char fading = PERLIN; // Color interpolation.
|
||||
unsigned char motion = SPLINE; // Trajectory interpolation.
|
||||
unsigned char blob_delimiter = HSP;
|
||||
double blob_threshold = 1.0;
|
||||
size_t blob_number = 1;
|
||||
size_t blob_max_size = SIZE_MAX;
|
||||
size_t blob_min_size = 1;
|
||||
size_t blob_box_samples = 10;
|
||||
uint16_t blob_box_grip = UINT16_MAX;
|
||||
unsigned char blob_rgba_weight = 1;
|
||||
unsigned char blob_size_weight = 1;
|
||||
unsigned char blob_xy_weight = 1;
|
||||
size_t degeneration = 0;
|
||||
uint16_t density = 1;
|
||||
size_t threads = 0;
|
||||
size_t cycle_length = 1000;
|
||||
size_t feather = 0;
|
||||
bool keep_background = false;
|
||||
bool blend_blobs = false;
|
||||
bool finite = false;
|
||||
unsigned fluidsteps = 0;
|
||||
unsigned show_blobs = TEXTURE;
|
||||
unsigned seed;
|
||||
|
||||
// Minimum Bounding Box that fits all pixels of all frames:
|
||||
uint16_t bbox_x1 = UINT16_MAX;
|
||||
uint16_t bbox_y1 = UINT16_MAX;
|
||||
uint16_t bbox_x2 = 0;
|
||||
uint16_t bbox_y2 = 0;
|
||||
|
||||
uint16_t width = 0;
|
||||
uint16_t height = 0;
|
||||
|
||||
size_t identifier=0; // Changed when anything changes in the key frames.
|
||||
unsigned state =STATE_BLOB_DETECTION;
|
||||
bool skip_state=false;
|
||||
|
||||
thread worker;
|
||||
double energy=0.0;
|
||||
|
||||
PerlinNoise lag_map;
|
||||
PerlinNoise slope_map;
|
||||
|
||||
FluidModel *fluid = nullptr;
|
||||
unsigned sparseness = 1;
|
||||
|
||||
std::default_random_engine e1;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
90
src/perlin.cpp
Normal file
90
src/perlin.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* See Copyright Notice in perlin.h
|
||||
*/
|
||||
#include <cmath>
|
||||
#include <array>
|
||||
#include <numeric>
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
#include "perlin.h"
|
||||
|
||||
PerlinNoise::PerlinNoise( unsigned seed ) {
|
||||
if(seed==0) seed = std::mt19937::default_seed;
|
||||
// p[0]..p[255] contains all numbers in [0..255] in random order
|
||||
std::iota(std::begin(p),std::begin(p)+256,0);
|
||||
std::shuffle(std::begin(p),std::begin(p)+256,std::mt19937(seed));
|
||||
for(int i=0; i<256; ++i) p[256+i] = p[i];
|
||||
}
|
||||
|
||||
double PerlinNoise::noise( double x, double y, double z ) const {
|
||||
const int X = static_cast<int>(::floor(x)) & 255;
|
||||
const int Y = static_cast<int>(::floor(y)) & 255;
|
||||
const int Z = static_cast<int>(::floor(z)) & 255;
|
||||
|
||||
x -= ::floor(x);
|
||||
y -= ::floor(y);
|
||||
z -= ::floor(z);
|
||||
|
||||
const double u = fade(x);
|
||||
const double v = fade(y);
|
||||
const double w = fade(z);
|
||||
|
||||
const int A = p[X ]+Y, AA = p[A]+Z, AB = p[A+1]+Z;
|
||||
const int B = p[X+1]+Y, BA = p[B]+Z, BB = p[B+1]+Z;
|
||||
|
||||
return lerp(w, lerp(v, lerp(u, grad(p[AA ], x , y , z ),
|
||||
grad(p[BA ], x-1, y , z )),
|
||||
lerp(u, grad(p[AB ], x , y-1, z ),
|
||||
grad(p[BB ], x-1, y-1, z ))),
|
||||
lerp(v, lerp(u, grad(p[AA+1], x , y , z-1 ),
|
||||
grad(p[BA+1], x-1, y , z-1 )),
|
||||
lerp(u, grad(p[AB+1], x , y-1, z-1 ),
|
||||
grad(p[BB+1], x-1, y-1, z-1 ))));
|
||||
}
|
||||
|
||||
double PerlinNoise::octaveNoise( double x, int octaves ) const {
|
||||
double result = 0.0;
|
||||
double amp = 1.0;
|
||||
|
||||
for(int i=0; i<octaves; ++i) {
|
||||
result += noise(x) * amp;
|
||||
x *= 2.0;
|
||||
amp *= 0.5;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
double PerlinNoise::octaveNoise( double x, double y, int octaves ) const {
|
||||
double result = 0.0;
|
||||
double amp = 1.0;
|
||||
|
||||
for(int i=0; i<octaves; ++i) {
|
||||
result += noise(x,y) * amp;
|
||||
x *= 2.0;
|
||||
y *= 2.0;
|
||||
amp *= 0.5;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
double PerlinNoise::octaveNoise( double x, double y, double z, int octaves ) const {
|
||||
double result = 0.0;
|
||||
double amp = 1.0;
|
||||
|
||||
for(int i=0; i<octaves; ++i) {
|
||||
result += noise(x,y,z) * amp;
|
||||
x *= 2.0;
|
||||
y *= 2.0;
|
||||
z *= 2.0;
|
||||
amp *= 0.5;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
double PerlinNoise::grad( int hash, double x, double y, double z ) const {
|
||||
const int h = hash & 15;
|
||||
const double u = h<8 ? x : y, v = h<4 ? y : h==12||h==14 ? x : z;
|
||||
return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v);
|
||||
}
|
||||
|
||||
48
src/perlin.h
Normal file
48
src/perlin.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* See Copyright Notice at the end of this file.
|
||||
*/
|
||||
|
||||
class PerlinNoise {
|
||||
public:
|
||||
PerlinNoise( unsigned seed = 1 );
|
||||
|
||||
double noise( double x ) const { return noise(x,0.0,0.0); }
|
||||
double noise( double x, double y ) const { return noise(x,y,0.0); }
|
||||
|
||||
double noise( double x, double y, double z ) const;
|
||||
double octaveNoise( double x, int octaves ) const;
|
||||
double octaveNoise( double x, double y, int octaves ) const;
|
||||
double octaveNoise( double x, double y, double z, int octaves ) const;
|
||||
|
||||
private:
|
||||
double fade( double t ) const { return t*t*t*(t*(t*6-15)+10); }
|
||||
double lerp( double t, double a, double b ) const { return a + t * (b - a); }
|
||||
|
||||
double grad( int hash, double x, double y, double z ) const;
|
||||
int p[512];
|
||||
};
|
||||
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Reputeless
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
68
src/spline.cpp
Normal file
68
src/spline.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
// ============================================================================
|
||||
// Copyright Jean-Charles LAMBERT - 2007-2013
|
||||
// e-mail: Jean-Charles.Lambert@oamp.fr
|
||||
// address: Dynamique des galaxies
|
||||
// Laboratoire d'Astrophysique de Marseille
|
||||
// Pôle de l'Etoile, site de Château-Gombert
|
||||
// 38, rue Frédéric Joliot-Curie
|
||||
// 13388 Marseille cedex 13 France
|
||||
// CNRS U.M.R 7326
|
||||
// ============================================================================
|
||||
// See the complete license in LICENSE and/or "http://www.cecill.info".
|
||||
// ============================================================================
|
||||
#include "spline.h"
|
||||
|
||||
namespace glnemo {
|
||||
|
||||
CRSpline::CRSpline() : vp(), delta_t(0.0) {}
|
||||
|
||||
CRSpline::CRSpline(const CRSpline& s) {
|
||||
for (int i = 0; i < (int)s.vp.size(); i++)
|
||||
vp.push_back(s.vp[i]);
|
||||
|
||||
delta_t = s.delta_t;
|
||||
}
|
||||
|
||||
CRSpline::~CRSpline() {}
|
||||
|
||||
// Solve the Catmull-Rom parametric equation for a given time(t) and vector quadruple (p1,p2,p3,p4)
|
||||
Vec3D CRSpline::Eq(double t, const Vec3D& p1, const Vec3D& p2, const Vec3D& p3, const Vec3D& p4) {
|
||||
double t2 = t * t;
|
||||
double t3 = t2 * t;
|
||||
double b1 = 0.5 * ( -t3 + 2.0*t2 - t);
|
||||
double b2 = 0.5 * ( 3.0*t3 - 5.0*t2 + 2.0);
|
||||
double b3 = 0.5 * (-3.0*t3 + 4.0*t2 + t);
|
||||
double b4 = 0.5 * ( t3 - t2 );
|
||||
|
||||
return (p1*b1 + p2*b2 + p3*b3 + p4*b4);
|
||||
}
|
||||
|
||||
void CRSpline::AddSplinePoint(const Vec3D& v) {
|
||||
vp.push_back(v);
|
||||
delta_t = 1.0 / vp.size();
|
||||
}
|
||||
|
||||
Vec3D CRSpline::GetInterpolatedSplinePoint(double t) {
|
||||
// Find out in which interval we are on the spline
|
||||
int p = (int)(t / delta_t);
|
||||
// Compute local control point indices
|
||||
int p0 = p - 1; p0 = (p0 < 0 ? vp.size()-1 : (p0 >= (int)vp.size() ? p0 - (int)vp.size() : p0));
|
||||
int p1 = p; p1 = (p1 < 0 ? vp.size()-1 : (p1 >= (int)vp.size() ? p1 - (int)vp.size() : p1));
|
||||
int p2 = p + 1; p2 = (p2 < 0 ? vp.size()-1 : (p2 >= (int)vp.size() ? p2 - (int)vp.size() : p2));
|
||||
int p3 = p + 2; p3 = (p3 < 0 ? vp.size()-1 : (p3 >= (int)vp.size() ? p3 - (int)vp.size() : p3));
|
||||
// Relative (local) time
|
||||
double lt = (t - delta_t*(double)p) / delta_t;
|
||||
// Interpolate
|
||||
return CRSpline::Eq(lt, vp[p0], vp[p1], vp[p2], vp[p3]);
|
||||
}
|
||||
|
||||
int CRSpline::GetNumPoints() {
|
||||
return vp.size();
|
||||
}
|
||||
|
||||
Vec3D& CRSpline::GetNthPoint(int n) {
|
||||
return vp[n];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
45
src/spline.h
Normal file
45
src/spline.h
Normal file
@@ -0,0 +1,45 @@
|
||||
// ============================================================================
|
||||
// Copyright Jean-Charles LAMBERT - 2007-2013
|
||||
// e-mail: Jean-Charles.Lambert@oamp.fr
|
||||
// address: Dynamique des galaxies
|
||||
// Laboratoire d'Astrophysique de Marseille
|
||||
// Pôle de l'Etoile, site de Château-Gombert
|
||||
// 38, rue Frédéric Joliot-Curie
|
||||
// 13388 Marseille cedex 13 France
|
||||
// CNRS U.M.R 7326
|
||||
// ============================================================================
|
||||
// See the complete license in LICENSE and/or "http://www.cecill.info".
|
||||
// ============================================================================
|
||||
#ifndef CATMULL_ROM_SPLINE_H
|
||||
#define CATMULL_ROM_SPLINE_H
|
||||
#include "vec3d.h"
|
||||
#include <vector>
|
||||
|
||||
namespace glnemo {
|
||||
|
||||
class CRSpline
|
||||
{
|
||||
public:
|
||||
CRSpline();
|
||||
CRSpline(const CRSpline&);
|
||||
~CRSpline();
|
||||
|
||||
void AddSplinePoint(const Vec3D& v);
|
||||
Vec3D GetInterpolatedSplinePoint(double t); // t = 0...1; 0=vp[0] ... 1=vp[max]
|
||||
int GetNumPoints();
|
||||
Vec3D& GetNthPoint(int n);
|
||||
|
||||
// Static method for computing the Catmull-Rom parametric equation
|
||||
// given a time (t) and a vector quadruple (p1,p2,p3,p4).
|
||||
static Vec3D Eq(double t, const Vec3D& p1, const Vec3D& p2, const Vec3D& p3, const Vec3D& p4);
|
||||
|
||||
// Clear ctrl points
|
||||
void clearCPoints() { vp.clear();}
|
||||
|
||||
private:
|
||||
std::vector<Vec3D> vp;
|
||||
double delta_t;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
1236
src/thread.cpp
Normal file
1236
src/thread.cpp
Normal file
File diff suppressed because it is too large
Load Diff
135
src/thread.h
Normal file
135
src/thread.h
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* See Copyright Notice in atomorph.h
|
||||
*/
|
||||
|
||||
#include <thread>
|
||||
#include "atomorph.h"
|
||||
|
||||
namespace am {
|
||||
|
||||
class thread {
|
||||
public:
|
||||
thread();
|
||||
~thread();
|
||||
|
||||
void next_state() {skip_state = true;}
|
||||
unsigned get_state() {return state;}
|
||||
size_t get_identifier() {return identifier;}
|
||||
void set_identifier(size_t id) {if (paused) identifier = id;}
|
||||
frame *get_frame(size_t nr) {return (has_frame(nr) ? &(frames[nr]) : nullptr);}
|
||||
const std::map<size_t, chain> *get_chains() {return (const std::map<size_t, chain> *) &chains;}
|
||||
unsigned get_seed() {return seed;}
|
||||
double get_energy();
|
||||
void set_frame(size_t nr, frame* f);
|
||||
size_t get_blob_count(size_t frame);
|
||||
size_t get_blob_count();
|
||||
void set_bbox(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);
|
||||
void set_blob_weights(unsigned char rgba, unsigned char size, unsigned char xy);
|
||||
|
||||
bool clear();
|
||||
void set_seed(unsigned seed);
|
||||
void set_blob_delimiter(unsigned char d) {if (paused) blob_delimiter = d;} // Color distance formula.
|
||||
void set_blob_threshold(double t) {if (paused) blob_threshold = t;} // Color difference toleration.
|
||||
void set_blob_max_size (size_t s) {if (paused) blob_max_size = s;} // Maximum size of a blob.
|
||||
void set_blob_min_size (size_t s) {if (paused) blob_min_size = s;} // Minimum size of a blob.
|
||||
void set_blob_box_grip (uint16_t g) {if (paused) blob_box_grip = g;} // Defines the bounding box.
|
||||
void set_blob_box_samples(size_t s) {if (paused) blob_box_samples=s;} // Number of dust samples.
|
||||
void set_blob_number (size_t n) {if (paused) blob_number = n;} // Preferred number of blobs.
|
||||
void set_degeneration (size_t d) {if (paused) degenerate = d;} // Degeneration period.
|
||||
void set_density (uint16_t d) {if (paused) point_density = d;} // Key points per pixel.
|
||||
void set_threads (size_t n) {if (paused) thread_count = n;} // Number of threads to spawn.
|
||||
void set_cycle_length (size_t l) {if (paused) cycle_length = l;} // Steps per iteration to repeat.
|
||||
|
||||
bool is_running() const {return running;}
|
||||
bool is_paused() const {return paused;}
|
||||
|
||||
void stop() { signal_stop = true; while(running) std::this_thread::sleep_for(std::chrono::milliseconds(0)); step_thread.join();}
|
||||
void start() { running = true; step_thread = std::thread(&thread::run, this);}
|
||||
void pause() { signal_pause = true; }
|
||||
void resume() { paused = false;}
|
||||
|
||||
void start (size_t iterations);
|
||||
void resume(size_t iterations);
|
||||
void start (double seconds);
|
||||
void resume(double seconds);
|
||||
|
||||
private:
|
||||
double blob_distance(const blob *b1, const blob *b2);
|
||||
pixel get_pixel(size_t frame, size_t position);
|
||||
|
||||
bool blobify ();
|
||||
bool unify ();
|
||||
bool match ();
|
||||
bool morph ();
|
||||
bool blobify_frame (size_t f);
|
||||
bool unify_frame (size_t f);
|
||||
bool init_morph ();
|
||||
double get_energy (struct blob ***map);
|
||||
double get_energy (chain *ch);
|
||||
void fix_volatiles (std::vector<blob *> *to_be_fixed);
|
||||
inline bool has_frame (size_t f ) const {return (frames.find(f) != frames.end());}
|
||||
inline bool has_pixel (size_t f, size_t pos) {return (has_frame(f) && frames[f].pixels.find(pos) != frames[f].pixels.end());}
|
||||
inline bool has_blob (size_t f, size_t b ) {return (has_frame(f) && frames[f].blobs.size() > b);}
|
||||
inline bool can_expand (size_t frame, size_t from_pos, size_t to_pos);
|
||||
|
||||
void run();
|
||||
void step();
|
||||
|
||||
std::map<size_t, frame> frames;
|
||||
std::map<size_t, chain> chains; // Key is the blob's group.
|
||||
|
||||
uint16_t point_density = 1; // How many key points to create per pixel at minimum.
|
||||
|
||||
struct blob *** blob_map;
|
||||
size_t blob_map_w; // Number of blobs per key frame.
|
||||
size_t blob_map_h; // Number of key frames.
|
||||
double blob_map_e; // Energy of the current blob map.
|
||||
double best_blob_map_e;
|
||||
|
||||
double chain_map_e;
|
||||
|
||||
// Minimum Bounding Box that fits all pixels of all frames:
|
||||
uint16_t bbox_x1 = UINT16_MAX;
|
||||
uint16_t bbox_y1 = UINT16_MAX;
|
||||
uint16_t bbox_x2 = 0;
|
||||
uint16_t bbox_y2 = 0;
|
||||
uint32_t bbox_d = 0; // Squared diagonal length.
|
||||
|
||||
unsigned char blob_delimiter = HSP;
|
||||
double blob_threshold = 1.0;
|
||||
size_t blob_max_size = SIZE_MAX;
|
||||
size_t blob_min_size = 1;
|
||||
uint16_t blob_box_grip = UINT16_MAX;
|
||||
size_t blob_box_samples = 10;
|
||||
size_t blob_number = 1;
|
||||
size_t thread_count = 0;
|
||||
size_t cycle_length = 1;
|
||||
|
||||
double blob_rgba_weight = 0.33;
|
||||
double blob_size_weight = 0.33;
|
||||
double blob_xy_weight = 0.34;
|
||||
|
||||
size_t identifier = SIZE_MAX;
|
||||
unsigned state = STATE_BLOB_DETECTION;
|
||||
unsigned seed = 0;
|
||||
bool skip_state = false;
|
||||
size_t degenerate = 0;
|
||||
size_t counter = 0;
|
||||
double best_e;
|
||||
bool deviant; // True when a bad solution has been accepted lately.
|
||||
|
||||
std::default_random_engine e1;
|
||||
|
||||
std::atomic<size_t> iterations;
|
||||
std::atomic<double> seconds;
|
||||
|
||||
std::atomic<bool> signal_stop;
|
||||
std::atomic<bool> signal_pause;
|
||||
std::atomic<bool> running;
|
||||
std::atomic<bool> paused;
|
||||
std::thread step_thread;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
88
src/vec3d.h
Normal file
88
src/vec3d.h
Normal file
@@ -0,0 +1,88 @@
|
||||
// ============================================================================
|
||||
// Copyright Jean-Charles LAMBERT - 2007-2013
|
||||
// e-mail: Jean-Charles.Lambert@oamp.fr
|
||||
// address: Dynamique des galaxies
|
||||
// Laboratoire d'Astrophysique de Marseille
|
||||
// Pôle de l'Etoile, site de Château-Gombert
|
||||
// 38, rue Frédéric Joliot-Curie
|
||||
// 13388 Marseille cedex 13 France
|
||||
// CNRS U.M.R 7326
|
||||
// ============================================================================
|
||||
// See the complete license in LICENSE and/or "http://www.cecill.info".
|
||||
// ============================================================================
|
||||
#ifndef GLNEMOVEC3D_H
|
||||
#define GLNEMOVEC3D_H
|
||||
#include <math.h>
|
||||
#include <iostream>
|
||||
/**
|
||||
@author Jean-Charles Lambert <jean-charles.lambert@oamp.fr>
|
||||
*/
|
||||
namespace glnemo {
|
||||
|
||||
class Vec3D{
|
||||
public:
|
||||
~Vec3D() {};
|
||||
|
||||
double x, y, z;
|
||||
Vec3D( double InX, double InY, double InZ ) : x( InX ), y( InY ), z( InZ ) {}
|
||||
Vec3D( const Vec3D& V) : x( V.x ), y( V.y ), z( V.z ) {}
|
||||
Vec3D( ) : x(0), y(0), z(0) {}
|
||||
|
||||
inline void set( const double InX, const double InY, const double InZ ) {
|
||||
x = InX; y = InY; z = InZ;
|
||||
}
|
||||
|
||||
inline bool operator== (const Vec3D& V2) const { return (x == V2.x && y == V2.y && z == V2.z); }
|
||||
inline Vec3D operator+ (const Vec3D& V2) const { return Vec3D( x + V2.x, y + V2.y, z + V2.z);}
|
||||
inline Vec3D operator- (const Vec3D& V2) const { return Vec3D( x - V2.x, y - V2.y, z - V2.z);}
|
||||
inline Vec3D operator- ( ) const { return Vec3D(-x, -y, -z); }
|
||||
inline Vec3D operator/ (const Vec3D& V2) const { return Vec3D (x / V2.x, y / V2.y, z / V2.z);}
|
||||
inline Vec3D operator* (const Vec3D& V2) const { return Vec3D (x * V2.x, y * V2.y, z * V2.z);}
|
||||
inline Vec3D operator* (double S ) const { return Vec3D (x * S, y * S, z * S); }
|
||||
inline Vec3D operator/ (double S ) const { double f=1.0/S; return Vec3D(x*f,y*f,z*f); }
|
||||
inline double operator[] (int i ) { return (i == 0 ? x : (i == 1 ? y : z)); }
|
||||
inline Vec3D& operator= (const Vec3D& V2) { x=V2.x; y=V2.y; z=V2.z; return *this; }
|
||||
inline void operator+= (const Vec3D& V2) { x += V2.x; y += V2.y; z += V2.z; }
|
||||
inline void operator-= (const Vec3D& V2) { x -= V2.x; y -= V2.y; z -= V2.z; }
|
||||
|
||||
inline double Dot( const Vec3D &V1 ) const {
|
||||
return V1.x*x + V1.y*y + V1.z*z;
|
||||
}
|
||||
|
||||
inline Vec3D CrossProduct( const Vec3D &V2 ) const {
|
||||
return Vec3D( y * V2.z - z * V2.y,
|
||||
z * V2.x - x * V2.z,
|
||||
x * V2.y - y * V2.x );
|
||||
}
|
||||
|
||||
Vec3D RotByMatrix( const double m[16] ) const {
|
||||
return Vec3D( x*m[0] + y*m[4] + z*m[8],
|
||||
x*m[1] + y*m[5] + z*m[9],
|
||||
x*m[2] + y*m[6] + z*m[10] );
|
||||
}
|
||||
|
||||
// These require math.h for the sqrtf function
|
||||
inline double Magnitude( ) const {
|
||||
return sqrt( x*x + y*y + z*z );
|
||||
}
|
||||
|
||||
inline double Distance( const Vec3D &V1 ) const {
|
||||
return ( *this - V1 ).Magnitude();
|
||||
}
|
||||
|
||||
inline void Normalize() {
|
||||
double fMag = ( x*x + y*y + z*z );
|
||||
if (fMag == 0) return;
|
||||
|
||||
double fMult = 1.0/sqrtf(fMag);
|
||||
x *= fMult;
|
||||
y *= fMult;
|
||||
z *= fMult;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user