Move to cmake

This commit is contained in:
2021-07-13 18:29:35 +02:00
parent bea16cbf81
commit bde42f320f
30 changed files with 83 additions and 764 deletions

1161
src/atomorph.cpp Normal file

File diff suppressed because it is too large Load Diff

390
src/atomorph.h Normal file
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

147
src/morph.h Normal file
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

135
src/thread.h Normal file
View 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
View 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