Logo Search packages:      
Sourcecode: randim version File versions  Download package

transmod.c

/* transmod.c: randim functions for modifying a set of transformations,
   either one-shot or in animation sequence. */

/* This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.  Please see the file "COPYING"
   for details.  If you have not received it along with this program,
   please write to the Free Software Foundation, Inc., 675 Mass. Ave.,
   Cambridge, MA 02139, USA. */

#include "randim.h"

/**********************************************/
      /* animation-related */

/* modify_trans() is called by animate() to generate a new shifted
   version of the image; it either re-adds the same perturbation
   we've been adding (continuing a persistent motion) or jumps to
   a new motion */
void
modify_trans()
{
  ModSet    *ms;
  float           *mod_a;
  int       i;

  /* if have finished a "motion", switch transformations */
  if (modcount == animpersist) {
    if (++mod[atmodn].cur == n_mods*2) {
      shuffle(mod[atmodn].modn,n_mods*2); /* reshuffle */
      mod[atmodn].cur = 0;
      }
    atmodn = nrand(n_trans);
    modcount = 0;
    }

  /* add modification to transformation */
  ms = &(mod[atmodn]), mod_a = a[atmodn];
  for (i=0;i<nparams(dimension);i++, mod_a++)
    *mod_a += ms->m[ms->modn[ms->cur]][i];
  modcount++;

  /* update its representation window */
  plot_transrep(atmodn);

}

/* init_mods() sets up a set of 2*n_mods perturbations for each active
   transform, half of which are random combinations of building blocks
   scaled to make a change of anim_step size in the image generated by
   the original, and half of which are their opposites.  A random order
   of these modifications is placed into the array modn[], and if each
   one is added to the original transforms the same number of times,
   the result will again be the original. */
void
init_mods()
{
  int       t,mi,i,r;
  int       given_up = 0;

  for (t=0;t<n_trans;t++) {
    /* set modifications */
    for (mi=0;mi<n_mods;mi++) {
      given_up += set_mod(t,mod[t].m[2*mi]);
      for (i=0;i<nparams(dimension);i++)
      mod[t].m[2*mi+1][i] = -mod[t].m[2*mi][i];
      }
    shuffle(mod[t].modn,n_mods*2);    /* shuffle order */
    mod[t].cur = 0;
    }

  /* set initial state for perturbations */
  modcount = 0;
  atmodn = nrand(n_trans);
  printf("\nCouldn't construct %d of %d modifications.\n",
       given_up,n_mods*n_trans);

}

/* set_mod() finds a suitable perturbation to a transformation by repeatedly
   constructing composites of the building blocks and attempting to scale
   them to generate a perturbation of the right size to the original image */
int
set_mod(int tr, float *m)
{
  char            wsize;
  int       ctries,
            stries;
  int             i;

#define MAXTRIES 20

  wsize = 1, ctries = 0;
  while (wsize && (ctries < MAXTRIES)) {
    construct_mod(m);
    stries = 0;
    do {
      wsize = check_mod(tr,m);
      if (wsize > 0)    /* perturbation too large */
      for (i=0;i<nparams(dimension);i++)
        m[i] /= 2;
      else if (wsize < 0)
      for (i=0;i<nparams(dimension);i++)
        m[i] *= 2;
      stries++;
      } while (wsize && (stries < 5));
    ctries++;
    }

  if (wsize) {    /* never succeeded, so just add or take away trans itself */
    for (i=0;i<nparams(dimension);i++)
      m[i] = a[tr][i];
    return 1;
    }
  else
    return 0;

}

/* construct_mod() builds a random transformation perturbation (to be used
   for animation) out of a combination of six basic building blocks,
   leaving it in m[] */
void
construct_mod(float *m)
{
  int       addfn;
  float           ang;
  char            hasnonzero;
  int       i,j;

  for (i=0;i<nparams(dimension);i++) m[i] = 0;
  for (i=0; i < nrand(3) + 1; i++) { /* add from 1 to 3 */
    addfn = nrand(N_ADDFNS);
    if (dimension == 2)
      for (j=0;j<6;j++)
      m[j] += posneg() * bb2[addfn][j] / 100; /* 100 is arbitrary */
    else
      for (j=0;j<12;j++)
      m[j] += posneg() * bb3[addfn][j] / 100;
    }
  /* if we made all zeros, do again */
  hasnonzero = 0;
  for (i=0;i<nparams(dimension);i++)
    if (m[i] != 0) {
      hasnonzero = 1;
      break;
      }
  if (!hasnonzero) construct_mod(m);

}

/* check_mod() checks size of an animation perturbation by computing the
   distance between basis points transformed by the old and new transform;
   it returns positive if the distance is too great, negative if it is too
   small, and 0 if it is juuust right. */
char
check_mod(int tr, float *m)
{
  float           norm, distance, rmin, rmax;

  /* settle on a range based on animstep; this is pretty much guesswork */
  /*  rmin = 0.1 + (animstep / 15) - 0.025;
  rmax = rmin + 0.05; */
  rmin = animstep/100 - (animstep/500);
  rmax = rmin + (animstep/250);

  /* compute avg. distance on basis (not really basis since trans nonlinear) */
  if (dimension == 2)
    distance = (cm_dist(tr,m,1,0,0) + cm_dist(tr,m,0,1,0)) / 2.0;
  else
    distance=(cm_dist(tr,m,1,0,0)+cm_dist(tr,m,0,1,0)+cm_dist(tr,m,0,0,1))/3.0;

  /*  norm = (hsize + vsize) / 2.0;
  distance *= norm;
  rmin *= norm, rmax *= norm; */

  /*  printf("Check: d= %f\trange = (%f,%f); norm = %f\n",distance,rmin,rmax,norm); */

  /* judgment time */
  if (distance < rmin) return -1;
  else if (distance > rmax) return 1;
  else return 0;

}

/* cm_dist() returns the distance between the normal and perturbed (by m)
   transform (tr) of the point x,y,z in screen terms */
float
cm_dist(int tr, float *m, float x, float y, float z)
{
  float           spx, spy;
  int       i;

  gz = x, gy = y, gz = z;
  for (i=0;i<n_trans;i++)
    apply_ftrans(i);
  spx = vx, spy = vy;
  for (i=0;i<nparams(dimension);i++)  /* perturb the transformation */
    a[tr][i] += m[i];
  gz = x, gy = y, gz = z;
  for (i=0;i<n_trans;i++)
    apply_ftrans(i);
  for (i=0;i<nparams(dimension);i++)    /* unperturb trans */
    a[tr][i] -= m[i];
  return sqrt(sqr((vx-spx)*(xscale/hsize)) + sqr((vy-spy)*(yscale/vsize)));

}

/*******************************************************/
      /* transrep selection-related */

/*Change transformation #tmodn to a new random trans.*/
void
add_a()
{
  int i;

  halt_draw();    /*stop drawing while we do this*/

  for (i=0;i<nparams(dimension);i++) /* set up new trans */
    a[tmodn][i] = dr() - 0.5;

  add_trans();    /*take care of setting up for new picture, etc.*/
}

/*Change transformation #tmodn to a new rotational trans.*/
void
add_r()
{
  float           angle, angle2,
            r, r2;

  halt_draw();    /*stop drawing while we do this*/

  /*generate transformation*/
  if (dimension == 2) {
    angle = 2.0 * M_PI * dr(), r = dr() - 0.5;
    a[tmodn][0] = a[tmodn][4] = r * cos(angle);
    a[tmodn][3] = r * sin(angle);
    a[tmodn][1] = r * -a[tmodn][3];
    a[tmodn][2] = dr() - 0.5;
    a[tmodn][5] = dr() - 0.5;
    }
  else {    /*dimension = 3*/
    angle = 2.0 * M_PI * dr(), angle2 = 2.0 * M_PI * dr(),
      r = dr() - 0.5; r2 = dr() - 0.5;
    a[tmodn][0] = r * cos(angle);
    a[tmodn][1] = r * r2 * -sin(angle) * cos(angle2);
    a[tmodn][2] = r * r2 * -sin(angle) * sin(angle2);
    a[tmodn][4] = r * r2 * sin(angle) * cos(angle2);
    a[tmodn][5] = r * r2 * cos(angle) * cos(angle2);
    a[tmodn][6] = r * r2 * cos(angle) * sin(angle2);
    a[tmodn][8] = r * r2 * sin(angle) * sin(angle2);
    a[tmodn][9] = r * r2 * cos(angle) * sin(angle2);
    a[tmodn][10]= r2 * cos(angle2);
    a[tmodn][3] = dr(); a[tmodn][7] = dr() - 0.5;
    a[tmodn][11] = dr() - 0.5;
    }

  add_trans();    /*take care of setting up for new picture, etc.*/
}

/*edit_rep() allows user to specify transformation #tmodn graphically;
 code in win_events.c*/

/******************************************************/
      /* other modification-related */

/* addI() is called when we plot the affine system as competing linear
   differential equations rather than conventionally.  In this case we
   should add the result to x and y at each juncture.  This is done by
   adding I2 (or I3) to the linear part of A.*/
void
addI(int t)
{
  int i;

  if (dimension == 2) {
    for (i=0;i<6;i++)
      a[t][i] *= 0.001;
    a[t][0] += 1.0;
    a[t][4] += 1.0;
      }
  else {    /*dimension = 3*/
    for (i=0;i<9;i++)
      a[t][i] *= 0.001;
    a[t][0] += 1.0;
    a[t][5] += 1.0;
    a[t][10] += 1.0;
      }

}

Generated by  Doxygen 1.6.0   Back to index