Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  ifs-compose-utils.c   Sprache: C

 

/* GIMP - The GNU Image Manipulation Program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * IfsCompose is a interface for creating IFS fractals by
 * direct manipulation.
 * Copyright (C) 1997 Owen Taylor
 *
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */


#include "config.h"

#include <stdlib.h>
#include <string.h>

#include <gdk/gdk.h>

#include <libgimp/gimp.h>

#include "ifs-compose.h"


typedef struct
{
  GdkPoint point;
  gdouble angle;
} SortPoint;


/* local functions */
static void     aff_element_compute_click_boundary (AffElement     *elem,
                                                    gint            num_elements,
                                                    gdouble        *points_x,
                                                    gdouble        *points_y);
static guchar * create_brush                       (IfsComposeVals *ifsvals,
                                                    gint           *brush_size,
                                                    gdouble        *brush_offset);


void
aff2_translate (Aff2    *naff,
                gdouble  x,
                gdouble  y)
{
  naff->a11 = 1.0;
  naff->a12 = 0;
  naff->a21 = 0;
  naff->a22 = 1.0;
  naff->b1 = x;
  naff->b2 = y;
}

void
aff2_rotate (Aff2    *naff,
             gdouble  theta)
{
  naff->a11 = cos(theta);
  naff->a12 = sin(theta);
  naff->a21 = -naff->a12;
  naff->a22 = naff->a11;
  naff->b1 = 0;
  naff->b2 = 0;
}

void
aff2_scale (Aff2    *naff,
            gdouble  s,
            gboolean flip)
{
  if (flip)
    naff->a11 = -s;
  else
    naff->a11 = s;

  naff->a12 = 0;
  naff->a21 = 0;
  naff->a22 = s;
  naff->b1 = 0;
  naff->b2 = 0;
}

/* Create a unitary transform with given x-y asymmetry and shear */
void
aff2_distort (Aff2    *naff,
              gdouble  asym,
              gdouble  shear)
{
  naff->a11 = asym;
  naff->a22 = 1/asym;
  naff->a12 = shear;
  naff->a21 = 0;
  naff->b1 = 0;
  naff->b2 = 0;
}

/* Find a pure stretch in some direction that brings xo,yo to xn,yn */
void
aff2_compute_stretch (Aff2    *naff,
                      gdouble  xo,
                      gdouble  yo,
                      gdouble  xn,
                      gdouble  yn)
{
  gdouble denom = xo*xn + yo*yn;

  if (denom == 0.0)     /* singular */
    {
      naff->a11 = 1.0;
      naff->a12 = 0.0;
      naff->a21 = 0.0;
      naff->a22 = 1.0;
    }
  else
    {
      naff->a11 = (SQR(xn) + SQR(yo)) / denom;
      naff->a22 = (SQR(xo) + SQR(yn)) / denom;
      naff->a12 = naff->a21 = (xn * yn - xo * yo) / denom;
    }

  naff->b1 = 0.0;
  naff->b2 = 0.0;
}

void
aff2_compose (Aff2 *naff,
              Aff2 *aff1,
              Aff2 *aff2)
{
  naff->a11 = aff1->a11 * aff2->a11 + aff1->a12 * aff2->a21;
  naff->a12 = aff1->a11 * aff2->a12 + aff1->a12 * aff2->a22;
  naff->b1  = aff1->a11 * aff2->b1  + aff1->a12 * aff2->b2 + aff1->b1;
  naff->a21 = aff1->a21 * aff2->a11 + aff1->a22 * aff2->a21;
  naff->a22 = aff1->a21 * aff2->a12 + aff1->a22 * aff2->a22;
  naff->b2  = aff1->a21 * aff2->b1  + aff1->a22 * aff2->b2 + aff1->b2;
}

/* Returns the identity matrix if the original matrix was singular */
void
aff2_invert (Aff2 *naff,
             Aff2 *aff)
{
  gdouble det = aff->a11 * aff->a22 - aff->a12 * aff->a21;

  if (det==0)
    {
      aff2_scale (naff, 1.0, 0);
    }
  else
    {
      naff->a11 = aff->a22 / det;
      naff->a22 = aff->a11 / det;
      naff->a21 = - aff->a21 / det;
      naff->a12 = - aff->a12 / det;
      naff->b1 = - naff->a11 * aff->b1 - naff->a12 * aff->b2;
      naff->b2 = - naff->a21 * aff->b1 - naff->a22 * aff->b2;
    }
}

void
aff2_apply (Aff2    *aff,
            gdouble  x,
            gdouble  y,
            gdouble *xf,
            gdouble *yf)
{
  gdouble xt = aff->a11 * x + aff->a12 * y + aff->b1;
  gdouble yt = aff->a21 * x + aff->a22 * y + aff->b2;

  *xf = xt;
  *yf = yt;
}

/* Find the fixed point of an affine transformation
   (Will return garbage for pure translations) */


void
aff2_fixed_point (Aff2    *aff,
                  gdouble *xf,
                  gdouble *yf)
{
  Aff2 t1,t2;

  t1.a11 = 1 - aff->a11;
  t1.a22 = 1 - aff->a22;
  t1.a12 = -aff->a12;
  t1.a21 = -aff->a21;
  t1.b1  = 0;
  t1.b2  = 0;

  aff2_invert (&t2, &t1);
  aff2_apply (&t2, aff->b1, aff->b2, xf, yf);
}

void
aff3_apply (Aff3    *t,
            gdouble  x,
            gdouble  y,
            gdouble  z,
            gdouble *xf,
            gdouble *yf,
            gdouble *zf)
{
  gdouble xt = (t->vals[0][0] * x +
                t->vals[0][1] * y +
                t->vals[0][2] * z + t->vals[0][3]);
  gdouble yt = (t->vals[1][0] * x +
                t->vals[1][1] * y +
                t->vals[1][2] * z + t->vals[1][3]);
  gdouble zt = (t->vals[2][0] * x +
                t->vals[2][1] * y +
                t->vals[2][2] * z + t->vals[2][3]);

  *xf = xt;
  *yf = yt;
  *zf = zt;
}

static int
ipolygon_sort_func (const void *a,
                    const void *b)
{
  if (((SortPoint *)a)->angle < ((SortPoint *)b)->angle)
    return -1;
  else if (((SortPoint *)a)->angle > ((SortPoint *)b)->angle)
    return 1;
  else
    return 0;
}

/* Return a newly-allocated polygon which is the convex hull
   of the given polygon.

   Uses the Graham scan. see
   http://www.cs.curtin.edu.au/units/cg201/notes/node77.html

   for a description
*/


IPolygon *
ipolygon_convex_hull (IPolygon *poly)
{
  gint       num_new     = poly->npoints;
  GdkPoint  *new_points  = g_new (GdkPoint, num_new);
  SortPoint *sort_points = g_new (SortPoint, num_new);
  IPolygon  *new_poly    = g_new (IPolygon, 1);

  gint       i, j;
  gint       x1, x2, y1, y2;
  gint       lowest;
  GdkPoint   lowest_pt;

  new_poly->points = new_points;
  if (num_new <= 3)
    {
      memcpy (new_points, poly->points, num_new * sizeof (GdkPoint));
      new_poly->npoints = num_new;
      g_free (sort_points);
      return new_poly;
    }

  /* scan for the lowest point */
  lowest_pt = poly->points[0];
  lowest = 0;

  for (i = 1; i < num_new; i++)
    if (poly->points[i].y < lowest_pt.y)
      {
        lowest_pt = poly->points[i];
        lowest = i;
      }

  /* sort by angle from lowest point */

  for (i = 0, j = 0; i < num_new; i++, j++)
    {
      if (i==lowest)
        j--;
      else
        {
          gdouble dy = poly->points[i].y - lowest_pt.y;
          gdouble dx = poly->points[i].x - lowest_pt.x;

          if (dy == 0 && dx == 0)
            {
              j--;
              num_new--;
              continue;
            }
          sort_points[j].point = poly->points[i];
          sort_points[j].angle = atan2 (dy, dx);
        }
    }

  qsort (sort_points, num_new - 1, sizeof (SortPoint), ipolygon_sort_func);

  /* now ensure that all turns as we trace the perimeter are
     counter-clockwise */


  new_points[0] = lowest_pt;
  new_points[1] = sort_points[0].point;
  x1 = new_points[1].x - new_points[0].x;
  y1 = new_points[1].y - new_points[0].y;

  for (i = 1, j = 2; j < num_new; i++, j++)
    {
      x2 = sort_points[i].point.x - new_points[j - 1].x;
      y2 = sort_points[i].point.y - new_points[j - 1].y;

      if (x2 == 0 && y2 == 0)
        {
          num_new--;
          j--;
          continue;
        }

      while (x1 * y2 - x2 * y1 < 0) /* clockwise rotation */
        {
          num_new--;
          j--;
          x1 = new_points[j - 1].x - new_points[j - 2].x;
          y1 = new_points[j - 1].y - new_points[j - 2].y;
          x2 = sort_points[i].point.x - new_points[j - 1].x;
          y2 = sort_points[i].point.y - new_points[j - 1].y;
        }
      new_points[j] = sort_points[i].point;
      x1 = x2;
      y1 = y2;
    }

  g_free (sort_points);

  new_poly->npoints = num_new;

  return new_poly;
}

/* Determines whether a specified point is in the given polygon.
   Based on

   inpoly.c by Bob Stein and Craig Yap.

   (Linux Journal, Issue 35 (March 1997), p 68)
   */


gint
ipolygon_contains (IPolygon *poly,
                   gint      xt,
                   gint      yt)
{
  gint xnew, ynew;
  gint xold, yold;
  gint x1,y1;
  gint x2,y2;

  gint i;
  gint inside = 0;

  if (poly->npoints < 3)
    return 0;

  xold=poly->points[poly->npoints - 1].x;
  yold=poly->points[poly->npoints - 1].y;
  for (i = 0; i < poly->npoints; i++)
    {
      xnew = poly->points[i].x;
      ynew = poly->points[i].y;
      if (xnew > xold)
        {
          x1 = xold;
          x2 = xnew;
          y1 = yold;
          y2 = ynew;
        }
      else
        {
          x1 = xnew;
          x2 = xold;
          y1 = ynew;
          y2 = yold;
        }
      if ((xnew < xt) == (xt <= xold) &&
          (yt - y1)*(x2 - x1) < (y2 - y1)*(xt - x1))
        inside = !inside;
      xold = xnew;
      yold = ynew;
    }
  return inside;
}

void
aff_element_compute_color_trans (AffElement *elem)
{
  gdouble red_rgb[3];
  gdouble green_rgb[3];
  gdouble blue_rgb[3];
  gdouble black_rgb[3];
  gdouble target_rgb[3];
  int     i, j;

  gegl_color_get_pixel (elem->v.red_color, babl_format ("R'G'B' double"), red_rgb);
  gegl_color_get_pixel (elem->v.green_color, babl_format ("R'G'B' double"), green_rgb);
  gegl_color_get_pixel (elem->v.blue_color, babl_format ("R'G'B' double"), blue_rgb);
  gegl_color_get_pixel (elem->v.black_color, babl_format ("R'G'B' double"), black_rgb);
  gegl_color_get_pixel (elem->v.target_color, babl_format ("R'G'B' double"), target_rgb);

  if (elem->v.simple_color)
    {
      gdouble mag2;

      mag2  = SQR (target_rgb[0]);
      mag2 += SQR (target_rgb[1]);
      mag2 += SQR (target_rgb[2]);

      /* For mag2 == 0, the transformation blows up in general
         but is well defined for hue_scale == value_scale, so
         we assume that special case. */

      if (mag2 == 0)
        for (i = 0; i < 3; i++)
          {
            for (j = 0; j < 4; j++)
              elem->color_trans.vals[i][j] = 0.0;

            elem->color_trans.vals[i][i] = elem->v.hue_scale;
          }
      else
        {
          /*  red  */
          for (j = 0; j < 3; j++)
            {
              elem->color_trans.vals[0][j] = target_rgb[0]
                / mag2 * (elem->v.value_scale - elem->v.hue_scale);
            }

          /*  green  */
          for (j = 0; j < 3; j++)
            {
              elem->color_trans.vals[1][j] = target_rgb[1]
                / mag2 * (elem->v.value_scale - elem->v.hue_scale);
            }

          /*  blue  */
          for (j = 0; j < 3; j++)
            {
              elem->color_trans.vals[2][j] = target_rgb[2]
                / mag2 * (elem->v.value_scale - elem->v.hue_scale);
            }

          elem->color_trans.vals[0][0] += elem->v.hue_scale;
          elem->color_trans.vals[1][1] += elem->v.hue_scale;
          elem->color_trans.vals[2][2] += elem->v.hue_scale;

          elem->color_trans.vals[0][3] =
            (1 - elem->v.value_scale) * target_rgb[0];
          elem->color_trans.vals[1][3] =
            (1 - elem->v.value_scale) * target_rgb[1];
          elem->color_trans.vals[2][3] =
            (1 - elem->v.value_scale) * target_rgb[2];

          }


      aff3_apply (&elem->color_trans, 1.0, 0.0, 0.0,
                  &red_rgb[0], &red_rgb[1], &red_rgb[2]);
      aff3_apply (&elem->color_trans, 0.0, 1.0, 0.0,
                  &green_rgb[0], &green_rgb[1], &green_rgb[2]);
      aff3_apply (&elem->color_trans, 0.0, 0.0, 1.0,
                  &blue_rgb[0], &blue_rgb[1], &blue_rgb[2]);
      aff3_apply (&elem->color_trans, 0.0, 0.0, 0.0,
                  &black_rgb[0], &black_rgb[1], &black_rgb[2]);

      gegl_color_set_pixel (elem->v.red_color, babl_format ("R'G'B' double"), red_rgb);
      gegl_color_set_pixel (elem->v.green_color, babl_format ("R'G'B' double"), green_rgb);
      gegl_color_set_pixel (elem->v.blue_color, babl_format ("R'G'B' double"), blue_rgb);
      gegl_color_set_pixel (elem->v.black_color, babl_format ("R'G'B' double"), black_rgb);
    }
  else
    {
      elem->color_trans.vals[0][0] = red_rgb[0] - black_rgb[0];
      elem->color_trans.vals[1][0] = red_rgb[1] - black_rgb[1];
      elem->color_trans.vals[2][0] = red_rgb[2] - black_rgb [2];

      elem->color_trans.vals[0][1] = green_rgb[0] - black_rgb[0];
      elem->color_trans.vals[1][1] = green_rgb[1] - black_rgb[1];
      elem->color_trans.vals[2][1] = green_rgb[2] - black_rgb[2];

      elem->color_trans.vals[0][2] = blue_rgb[0] - black_rgb[0];
      elem->color_trans.vals[1][2] = blue_rgb[1] - black_rgb[1];
      elem->color_trans.vals[2][2] = blue_rgb[2] - black_rgb[2];

      elem->color_trans.vals[0][3] = black_rgb[0];
      elem->color_trans.vals[1][3] = black_rgb[1];
      elem->color_trans.vals[2][3] = black_rgb[2];
    }
}

void
aff_element_compute_trans (AffElement *elem,
                           gdouble     width,
                           gdouble     height,
                           gdouble     center_x,
                           gdouble     center_y)
{
  Aff2 t1, t2, t3;

  /* create the rotation, scaling and shearing part of the transform */
  aff2_distort (&t1, elem->v.asym, elem->v.shear);
  aff2_scale (&t2, elem->v.scale, elem->v.flip);
  aff2_compose (&t3, &t2, &t1);
  aff2_rotate (&t2, elem->v.theta);
  aff2_compose (&t1, &t2, &t3);

  /* now create the translational part */
  aff2_translate (&t2, -center_x*width, -center_y*width);
  aff2_compose (&t3, &t1, &t2);
  aff2_translate (&t2, elem->v.x*width, elem->v.y*width);
  aff2_compose (&elem->trans, &t2, &t3);
}

void
aff_element_decompose_trans (AffElement *elem,
                             Aff2       *aff,
                             gdouble     width,
                             gdouble     height,
                             gdouble     center_x,
                             gdouble     center_y)
{
  Aff2    t1, t2;
  gdouble det, scale, sign;

  /* pull of the translational parts */
  aff2_translate (&t1,center_x * width, center_y * width);
  aff2_compose (&t2, aff, &t1);

  elem->v.x = t2.b1 / width;
  elem->v.y = t2.b2 / width;

  det = t2.a11 * t2.a22 - t2.a12 * t2.a21;

  if (det == 0.0)
    {
      elem->v.scale = 0.0;
      elem->v.theta = 0.0;
      elem->v.asym  = 1.0;
      elem->v.shear = 0.0;
      elem->v.flip  = 0;
    }
  else
    {
      if (det >= 0)
        {
          scale = elem->v.scale = sqrt (det);
          sign = 1;
          elem->v.flip = 0;
        }
      else
        {
          scale = elem->v.scale = sqrt (-det);
          sign = -1;
          elem->v.flip = 1;
        }

      elem->v.theta = atan2 (-t2.a21, t2.a11);

      if (cos (elem->v.theta) == 0.0)
        {
          elem->v.asym = - t2.a21 / scale / sin (elem->v.theta);
          elem->v.shear = - sign * t2.a22 / scale / sin (elem->v.theta);
        }
      else
        {
          elem->v.asym = sign * t2.a11 / scale / cos (elem->v.theta);
          elem->v.shear = sign *
            (t2.a12/scale - sin (elem->v.theta)/elem->v.asym)
            / cos (elem->v.theta);
        }
    }
}

static void
aff_element_compute_click_boundary (AffElement *elem,
                                    int         num_elements,
                                    gdouble    *points_x,
                                    gdouble    *points_y)
{
  gint    i;
  gdouble xtot = 0;
  gdouble ytot = 0;
  gdouble xc, yc;
  gdouble theta;
  gdouble sth, cth;              /* sin(theta), cos(theta) */
  gdouble axis1, axis2;
  gdouble axis1max, axis2max, axis1min, axis2min;

  /* compute the center of mass of the points */
  for (i = 0; i < num_elements; i++)
    {
      xtot += points_x[i];
      ytot += points_y[i];
    }
  xc = xtot / num_elements;
  yc = ytot / num_elements;

  /* compute the sum of the (x+iy)^2, and take half the the resulting
     angle (xtot+iytot = A*exp(2i*theta)), to get an average direction */


  xtot = 0;
  ytot = 0;
  for (i = 0; i < num_elements; i++)
    {
      xtot += SQR (points_x[i] - xc) - SQR (points_y[i] - yc);
      ytot += 2 * (points_x[i] - xc) * (points_y[i] - yc);
    }
  theta = 0.5 * atan2 (ytot, xtot);
  sth = sin (theta);
  cth = cos (theta);

  /* compute the minimum rectangle at angle theta that bounds the points,
     1/2 side lengths left in axis1, axis2, center in xc, yc */


  axis1max = axis1min = 0.0;
  axis2max = axis2min = 0.0;
  for (i = 0; i < num_elements; i++)
    {
      gdouble proj1 =  (points_x[i] - xc) * cth + (points_y[i] - yc) * sth;
      gdouble proj2 = -(points_x[i] - xc) * sth + (points_y[i] - yc) * cth;
      if (proj1 < axis1min)
        axis1min = proj1;
      if (proj1 > axis1max)
        axis1max = proj1;
      if (proj2 < axis2min)
        axis2min = proj2;
      if (proj2 > axis2max)
        axis2max = proj2;
    }
  axis1 = 0.5 * (axis1max - axis1min);
  axis2 = 0.5 * (axis2max - axis2min);
  xc += 0.5 * ((axis1max + axis1min) * cth - (axis2max + axis2min) * sth);
  yc += 0.5 * ((axis1max + axis1min) * sth + (axis2max + axis2min) * cth);

  /* if the the rectangle is less than 10 pixels in any dimension,
     make it click_boundary, otherwise set click_boundary = draw_boundary */


  if (axis1 < 8.0 || axis2 < 8.0)
    {
      GdkPoint *points = g_new (GdkPoint, 4);

      elem->click_boundary = g_new (IPolygon, 1);
      elem->click_boundary->points = points;
      elem->click_boundary->npoints = 4;

      if (axis1 < 8.0) axis1 = 8.0;
      if (axis2 < 8.0) axis2 = 8.0;

      points[0].x = xc + axis1 * cth - axis2 * sth;
      points[0].y = yc + axis1 * sth + axis2 * cth;
      points[1].x = xc - axis1 * cth - axis2 * sth;
      points[1].y = yc - axis1 * sth + axis2 * cth;
      points[2].x = xc - axis1 * cth + axis2 * sth;
      points[2].y = yc - axis1 * sth - axis2 * cth;
      points[3].x = xc + axis1 * cth + axis2 * sth;
      points[3].y = yc + axis1 * sth - axis2 * cth;
    }
  else
    {
      elem->click_boundary = elem->draw_boundary;
    }
}

void
aff_element_compute_boundary (AffElement  *elem,
                              gint         width,
                              gint         height,
                              AffElement **elements,
                              gint         num_elements)
{
  gint      i;
  IPolygon  tmp_poly;
  gdouble  *points_x;
  gdouble  *points_y;

  if (elem->click_boundary && elem->click_boundary != elem->draw_boundary)
    g_free (elem->click_boundary);
  if (elem->draw_boundary)
    g_free (elem->draw_boundary);

  tmp_poly.npoints = num_elements;
  tmp_poly.points  = g_new (GdkPoint, num_elements);
  points_x = g_new (gdouble, num_elements);
  points_y = g_new (gdouble, num_elements);

  for (i = 0; i < num_elements; i++)
    {
      aff2_apply (&elem->trans,
                  elements[i]->v.x * width, elements[i]->v.y * width,
                  &points_x[i],&points_y[i]);
      tmp_poly.points[i].x = (gint)points_x[i];
      tmp_poly.points[i].y = (gint)points_y[i];
    }

  elem->draw_boundary = ipolygon_convex_hull (&tmp_poly);
  aff_element_compute_click_boundary (elem, num_elements, points_x, points_y);

  g_free (tmp_poly.points);
}

void
aff_element_draw (AffElement  *elem,
                  gboolean     selected,
                  gint         width,
                  gint         height,
                  cairo_t     *cr,
                  GdkRGBA     *color,
                  PangoLayout *layout)
{
  PangoRectangle rect;
  gint           i;

  pango_layout_set_text (layout, elem->name, -1);
  pango_layout_get_pixel_extents (layout, NULL, &rect);

  gdk_cairo_set_source_rgba (cr, color);

  cairo_move_to (cr,
                 elem->v.x * width - rect.width  / 2,
                 elem->v.y * width + rect.height / 2);
  pango_cairo_show_layout (cr, layout);
  cairo_fill (cr);

  cairo_set_line_width (cr, 1.0);

  if (elem->click_boundary != elem->draw_boundary)
    {
      cairo_move_to (cr,
                     elem->click_boundary->points[0].x,
                     elem->click_boundary->points[0].y);

      for (i = 1; i < elem->click_boundary->npoints; i++)
        cairo_line_to (cr,
                       elem->click_boundary->points[i].x,
                       elem->click_boundary->points[i].y);

      cairo_close_path (cr);

      cairo_stroke (cr);
    }

  if (selected)
    cairo_set_line_width (cr, 3.0);

  cairo_move_to (cr,
                 elem->draw_boundary->points[0].x,
                 elem->draw_boundary->points[0].y);

  for (i = 1; i < elem->draw_boundary->npoints; i++)
    cairo_line_to (cr,
                   elem->draw_boundary->points[i].x,
                   elem->draw_boundary->points[i].y);

  cairo_close_path (cr);

  cairo_stroke (cr);
}

AffElement *
aff_element_new (gdouble    x,
                 gdouble    y,
                 GeglColor *color,
                 gint       count)
{
  AffElement *elem = g_new (AffElement, 1);
  gchar buffer[16];

  elem->v.x = x;
  elem->v.y = y;
  elem->v.theta = 0.0;
  elem->v.scale = 0.5;
  elem->v.asym = 1.0;
  elem->v.shear = 0.0;
  elem->v.flip = 0;

  elem->v.red_color   = gegl_color_duplicate (color);
  elem->v.blue_color  = gegl_color_duplicate (color);
  elem->v.green_color = gegl_color_duplicate (color);
  elem->v.black_color = gegl_color_duplicate (color);

  elem->v.target_color = gegl_color_duplicate (color);
  elem->v.hue_scale = 0.5;
  elem->v.value_scale = 0.5;

  elem->v.simple_color = TRUE;

  elem->draw_boundary = NULL;
  elem->click_boundary = NULL;

  aff_element_compute_color_trans (elem);

  elem->v.prob = 1.0;

  sprintf (buffer,"%d", count);
  elem->name = g_strdup (buffer);

  return elem;
}

void
aff_element_free (AffElement *elem)
{
  if (elem->click_boundary && elem->click_boundary != elem->draw_boundary)
    g_free (elem->click_boundary);

  g_clear_object (&elem->v.red_color);
  g_clear_object (&elem->v.blue_color);
  g_clear_object (&elem->v.green_color);
  g_clear_object (&elem->v.black_color);
  g_clear_object (&elem->v.target_color);

  g_free (elem->draw_boundary);
  g_free (elem);
}

#ifdef DEBUG_BRUSH
static brush_chars[] = {' ',':','*','@'};
#endif

static guchar *
create_brush (IfsComposeVals *ifsvals,
              gint           *brush_size,
              gdouble        *brush_offset)
{
  gint     i, j;
  gint     ii, jj;
  guchar  *brush;
#ifdef DEBUG_BRUSH
  gdouble  totpix = 0.0;
#endif

  gdouble radius = ifsvals->radius * ifsvals->subdivide;

  *brush_size = ceil (2 * radius);
  *brush_offset = 0.5 * (*brush_size - 1);

  brush = g_new (guchar, SQR (*brush_size));

  for (i = 0; i < *brush_size; i++)
    {
      for (j = 0; j < *brush_size; j++)
        {
          gdouble pixel = 0.0;
          gdouble d     = sqrt (SQR (i - *brush_offset) +
                                SQR (j - *brush_offset));

          if (d - 0.5 * G_SQRT2 > radius)
            pixel = 0.0;
          else if (d + 0.5 * G_SQRT2 < radius)
            pixel = 1.0;
          else
            for (ii = 0; ii < 10; ii++)
              for (jj = 0; jj < 10; jj++)
                {
                  d = sqrt (SQR (i - *brush_offset + ii * 0.1 - 0.45) +
                            SQR (j - *brush_offset + jj * 0.1 - 0.45));
                  pixel += (d < radius) / 100.0;
                }

          brush[i * *brush_size + j] = 255.999 * pixel;

#ifdef DEBUG_BRUSH
          putchar(brush_chars[(gint)(pixel * 3.999)]);
          totpix += pixel;
#endif /* DEBUG_BRUSH */
        }
#ifdef DEBUG_BRUSH
      putchar('\n');
#endif /* DEBUG_BRUSH */
    }
#ifdef DEBUG_BRUSH
  printf ("Brush total / area = %f\n", totpix / SQR (ifsvals->subdivide));
#endif /* DEBUG_BRUSH */
  return brush;
}

void
ifs_render (AffElement     **elements,
            gint             num_elements,
            gint             width,
            gint             height,
            gint             nsteps,
            IfsComposeVals  *vals,
            gint             band_y,
            gint             band_height,
            guchar          *data,
            guchar          *mask,
            guchar          *nhits,
            gboolean         preview)
{
  gint     i, k, n;
  gdouble  x, y;
  gdouble  r, g, b;
  gint     ri, gi, bi;
  guint32  p0, psum;
  gdouble  pt;
  guchar  *ptr;
  guint32 *prob;
  gdouble *fprob;
  gint     subdivide;
  guchar  *brush = NULL;
  gint     brush_size   = 1;
  gdouble  brush_offset = 0.0;

  if (preview)
    subdivide = 1;
  else
    subdivide = vals->subdivide;

  /* compute the probabilities and transforms */
  fprob = g_new (gdouble, num_elements);
  prob = g_new (guint32, num_elements);
  pt = 0.0;

  for (i = 0; i < num_elements; i++)
    {
      aff_element_compute_trans(elements[i],
                                width * subdivide,
                                height * subdivide,
                                vals->center_x,
                                vals->center_y);
      fprob[i] = fabs(
          elements[i]->trans.a11 * elements[i]->trans.a22
        - elements[i]->trans.a12 * elements[i]->trans.a21);

      /* As a heuristic, if the determinant is really small, it's
         probably a line element, so increase the probability so
         it gets rendered */


      /* FIXME: figure out what 0.01 really should be */
      if (fprob[i] < 0.01)
        fprob[i] = 0.01;

      fprob[i] *= elements[i]->v.prob;

      pt += fprob[i];
    }

  psum = 0;
  for (i = 0; i < num_elements; i++)
    {
      psum += (guint32) -1 * (fprob[i] / pt);
      prob[i] = psum;
    }

  prob[i - 1] = (guint32) -1;  /* make sure we don't get bitten by roundoff */

  /* create the brush */
  if (!preview)
    brush = create_brush (vals, &brush_size, &brush_offset);

  x = y = 0;
  r = g = b = 0;

  /* n is used to limit the number of progress updates */
  n = nsteps / 32;

  /* now run the iteration */
  for (i = 0; i < nsteps; i++)
    {
      if (!preview && ((i % n) == 0))
        gimp_progress_update ((gdouble) i / (gdouble) nsteps);

      p0 = g_random_int ();
      k = 0;

      while (p0 > prob[k])
        k++;

      aff2_apply (&elements[k]->trans, x, y, &x, &y);
      aff3_apply (&elements[k]->color_trans, r, g, b, &r, &g, &b);

      if (i < 50)
        continue;

      ri = (gint) (255.0 * r + 0.5);
      gi = (gint) (255.0 * g + 0.5);
      bi = (gint) (255.0 * b + 0.5);

      if ((ri < 0) || (ri > 255) ||
          (gi < 0) || (gi > 255) ||
          (bi < 0) || (bi > 255))
        continue;

      if (preview)
        {
          if ((x < width) && (y < (band_y + band_height)) &&
              (x >= 0) && (y >= band_y))
            {
              ptr = data + 3 * (((gint) (y - band_y)) * width + (gint) x);

              *ptr++ = ri;
              *ptr++ = gi;
              *ptr   = bi;
            }
        }
      else
        {
          if ((x < width * subdivide) && (y < height * subdivide) &&
              (x >= 0) && (y >= 0))
            {
              gint ii;
              gint jj;
              gint jj0   = floor (y - brush_offset - band_y * subdivide);
              gint ii0   = floor (x - brush_offset);
              gint jjmin = 0;
              gint iimin = 0;
              gint jjmax;
              gint iimax;

              if (ii0 < 0)
                iimin = - ii0;
              else
                iimin = 0;

              if (jj0 < 0)
                jjmin = - jj0;
              else
                jjmin = 0;

              if (jj0 + brush_size >= subdivide * band_height)
                jjmax = subdivide * band_height - jj0;
              else
                jjmax = brush_size;

              if (ii0 + brush_size >= subdivide * width)
                iimax = subdivide * width - ii0;
              else
                iimax = brush_size;

              for (jj = jjmin; jj < jjmax; jj++)
                for (ii = iimin; ii < iimax; ii++)
                  {
                    guint m_old;
                    guint m_new;
                    guint m_pix;
                    guint n_hits;
                    guint old_scale;
                    guint pix_scale;
                    gint  index = (jj0 + jj) * width * subdivide + ii0 + ii;

                    n_hits = nhits[index];
                    if (n_hits == 255)
                      continue;

                    m_pix = brush[jj * brush_size + ii];
                    if (!m_pix)
                      continue;

                    nhits[index] = ++n_hits;
                    m_old = mask[index];
                    m_new = m_old + m_pix - m_old * m_pix / 255;
                    mask[index] = m_new;

                    /* relative probability that old colored pixel is on top */
                    old_scale = m_old * (255 * n_hits - m_pix);

                    /* relative probability that new colored pixel is on top */
                    pix_scale = m_pix * ((255 - m_old) * n_hits + m_old);

                    ptr = data + 3 * index;

                    *ptr = ((old_scale * (*ptr) + pix_scale * ri) /
                            (old_scale + pix_scale));
                    ptr++;

                    *ptr = ((old_scale * (*ptr) + pix_scale * gi) /
                            (old_scale + pix_scale));
                    ptr++;

                    *ptr = ((old_scale * (*ptr) + pix_scale * bi) /
                            (old_scale + pix_scale));
                  }
            }
        }
    } /* main iteration */

  if (!preview )
    gimp_progress_update (1.0);

  g_free (brush);
  g_free (prob);
  g_free (fprob);
}

Messung
CHZG
82979892

¤ Dauer der Verarbeitung: 0.13 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104848
#Domains=416967