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

gutil.c

/*
 *  Copyright (c) 1994, Riley Rainey,  riley@netcon.com
 *
 *  Permission to use, copy, modify and distribute (without charge) this
 *  software, documentation, images, etc. is granted, provided that this 
 *  comment and the author's name is retained.
 *
 *  This software is provided by the author as is, and without any expressed
 *  or implied warranties, including, but not limited to, the implied
 *  warranties of merchantability and fitness for a particular purpose.  In no
 *  event shall the author be liable for any direct, indirect, incidental, or
 *  consequential damages arising in any way out of the use of this software.
 */

#include <X11/Intrinsic.h>
#include <Xm/DrawingA.h>
#include "gedit.h"
#include <math.h>

extern void DrawPolygon(), WorldToWidget(), DrawWidget(), PointToXYZ();
void  SelectObject();

/*
 *  Once we have three points entered, we can compute the equation associated
 *  with the plane defined by them.  The general equation looks like this:
 *
 *                a x + b y + c z + d = 0
 *
 *  Where the normal vector is N=[a, b, c] and d = - a x0 - b y0 - c z0;
 *  the origin is O=[x0, y0, z0].
 *
 *  Once the plane equation is computed, it's a trivial task to determine
 *  the xyz coordinates of any subsequent points entered for this polygon
 *  -- since all points on the polygon are, by our definition, coplanar.
 */

#define mag(v)    sqrt( v.x * v.x + v.y * v.y + v.z * v.z )

void
ComputePlaneEquation (p)
polygon_t   *p;
{

      VPoint            a, b;
      register double   length;

      VSetPoint (a,
            p->point[0].point.x - p->point[1].point.x,
            p->point[0].point.y - p->point[1].point.y,
            p->point[0].point.z - p->point[1].point.z);

      VSetPoint (b,
            p->point[2].point.x - p->point[1].point.x,
            p->point[2].point.y - p->point[1].point.y,
            p->point[2].point.z - p->point[1].point.z);

      VCrossProd (&a, &b, &(p->normal));

      length = mag(p->normal);
      p->normal.x /= length;
      p->normal.y /= length;
      p->normal.z /= length;

      p->d = - VDotProd (&p->normal, &p->point[1].point);
      p->origin = p->point[1].point;
}

void
DisplayPoint(p)
point_t     *p;
{
      char  value[64];

      sprintf (value, "%f", p->point.x);
      XmTextFieldSetString (x_field, value);
      sprintf (value, "%f", p->point.y);
      XmTextFieldSetString (y_field, value);
      sprintf (value, "%f", p->point.z);
      XmTextFieldSetString (z_field, value);
}

polygon_t *
AllocPolygon ()
{
      register int i, n;
      register polygon_t *tmp;

      for (i=0; i < polygon_max; ++i) {
            if (polygon_list[i].num_points == 0) {
                  polygon_list[i].next = -1;
                  return &polygon_list[i];
            }
      }

      n = polygon_max * 2;

      if ((tmp = (polygon_t *) malloc (n * sizeof (polygon_t))) == NULL)
            return (polygon_t *) NULL;

      bcopy ((char *) polygon_list, (char *) tmp,
            polygon_max * sizeof (polygon_t));

      for (i = polygon_max; i < n; ++i) {
            tmp[i].next = tmp[i].num_points = 0;
            tmp[i].id = i;
      }

      polygon_max = n;
      free ((char *) polygon_list);
      polygon_list = tmp;
}

void
FreePolygon (p)
polygon_t *p;
{
      p->num_points = 0;
      if (p->point != tmp_point)
            free ((char *) p->point);
}

polygon_t *
BeginPolygon ()
{

      register polygon_t *p;

      if ((p = AllocPolygon()) == (polygon_t *) NULL) {
            fprintf (stderr, "out of memory\n");
            exit (1);
      }

      p->num_points = 0;
      p->point = tmp_point;
      cur_polygon = p;

      return p;
}

void PointXY (w, p, x, y, q)
Widget            w;
view_info_t *p;
int         x, y;
point_t           *q;
{
      switch (p->layout) {

      case VL_NXZ:
            q->x = x;
            q->y = p->other_view->origin_y;
            q->z = y;
            q->point.x = - (x - p->origin_x) * pixel_scale;
            q->point.y = 0.0;
            q->point.z = (y - p->origin_y) * pixel_scale;
            break;

      case VL_NXNY:
            q->x = x;
            q->y = y;
            q->z = p->other_view->origin_y;
            q->point.x = - (x - p->origin_x) * pixel_scale;
            q->point.y = - (y - p->origin_y) * pixel_scale;
            q->point.z = 0.0;
            break;

      case VL_NYZ:      
            q->x = p->other_view->origin_y;
            q->y = x;
            q->z = y;
            q->point.x = 0.0;
            q->point.y = - (x - p->origin_x) * pixel_scale;
            q->point.z = (y - p->origin_y) * pixel_scale;
            break;

      case VL_NYX:
            q->x = y;
            q->y = x;
            q->z = p->other_view->origin_y;
            q->point.x = (y - p->origin_y) * pixel_scale;
            q->point.y = -(x - p->origin_x) * pixel_scale;
            q->point.z = 0.0;
            break;

      default:
            printf ("oops\n");
      }

}

int
PinPoint (w, p, poly, x, y, pt, opt)
Widget      w;
view_info_t *p;
polygon_t   *poly;
int         x, y;
XPoint            *pt, *opt;
{

      view_info_t *p1;
      point_t           *q, *oq;
      int         z;
      Boolean           plane_established;

      if (poly->num_points == 0)
            oq = (point_t *) NULL;
      else
            oq = &poly->point[poly->num_points-1];

      q = &poly->point[poly->num_points++];

      plane_established = (poly->num_points > 3) ? True : False;

      switch (p->layout) {

      case VL_NXZ:
            if (oq != (point_t *) NULL) {
                  pt->x = opt->x = oq->x;
                  pt->y = oq->z;
                  opt->y = oq->y;
                  q->y = oq->y;
            }
            else {
                  q->y = p->other_view->origin_y;
            }
                  
            q->x = x;
            q->z = y;
            z = q->y;
            q->point.x = - (x - p->origin_x) * pixel_scale;
            q->point.z = (y - p->origin_y) * pixel_scale;

            switch (p->other_view->layout) {

            case VL_NXNY:
                  if (plane_established) {
                        q->point.y = - (poly->normal.x * q->point.x +
                              poly->normal.z * q->point.z + poly->d) /
                              poly->normal.y;
                        z = q->y = - q->point.y / pixel_scale +
                              p->other_view->origin_y;
                  }
                  else 
                        q->point.y = - (q->y - p->other_view->origin_y)*
                              pixel_scale;
                  break;

            case VL_NXY:
                  if (plane_established) {
                        q->point.y = - (poly->normal.x * q->point.x +
                              poly->normal.z * q->point.z + poly->d) /
                              poly->normal.y;
                        z = q->y = q->point.y / pixel_scale +
                              p->other_view->origin_y;
                  }
                  else
                        q->point.y = (q->y - p->other_view->origin_y) *
                              pixel_scale;
                  break;
            }

            break;

      case VL_NXNY:
            if (oq != (point_t *) NULL) {
                  pt->x = opt->x = oq->x;
                  pt->y = oq->y;
                  opt->y = oq->z;
                  q->z = oq->z;
            }
            else {
                  q->z = p->other_view->origin_y;
            }

            q->x = x;
            q->y = y;
            z = q->z;
            q->point.x = - (x - p->origin_x) * pixel_scale;
            q->point.y = - (y - p->origin_y) * pixel_scale;

            switch (p->other_view->layout) {

            case VL_NXNZ:
                  if (plane_established) {
                        q->point.z = - (poly->normal.x * q->point.x +
                              poly->normal.y * q->point.y + poly->d) /
                              poly->normal.z;
                        z = q->z = q->point.z / pixel_scale +
                              p->other_view->origin_y;
                  }
                  else
                        q->point.z = - (q->z - p->other_view->origin_y)*
                              pixel_scale;
                  break;

            case VL_NXZ:
                  if (plane_established) {
                        q->point.z = - (poly->normal.x * q->point.x +
                              poly->normal.y * q->point.y + poly->d) /
                              poly->normal.z;
                        z = q->z = q->point.z / pixel_scale +
                              p->other_view->origin_y;
                  }
                  else 
                        q->point.z = (q->z - p->other_view->origin_y) *
                              pixel_scale;
                  break;
            }

            break;

      case VL_NYZ:
            if (oq != (point_t *) NULL) {
                  pt->x = opt->x = oq->y;
                  pt->y = oq->z;
                  opt->y = oq->x;
                  q->x = oq->x;
            }
            else {
                  q->x = p->other_view->origin_y;
            }

            q->y = x;
            q->z = y;
            z = q->x;
            q->point.y = - (x - p->origin_x) * pixel_scale;
            q->point.z = (y - p->origin_y) * pixel_scale;

            switch (p->other_view->layout) {

            case VL_NYX:
                  if (plane_established) {
                        q->point.x = - (poly->normal.y * q->point.y +
                              poly->normal.z * q->point.z + poly->d) /
                              poly->normal.x;
                        z = q->x = q->point.x / pixel_scale +
                              p->other_view->origin_y;
                  }
                  else 
                        q->point.x = (q->x - p->other_view->origin_y) *
                              pixel_scale;
                  break;

            case VL_NYNX:
                  if (plane_established) {
                        q->point.x = - (poly->normal.y * q->point.y +
                              poly->normal.z * q->point.z + poly->d) /
                              poly->normal.x;
                        z = q->x = - q->point.x / pixel_scale +
                              p->other_view->origin_y;
                  }
                  else
                        q->point.x = -(q->x - p->other_view->origin_y)*
                              pixel_scale;
                  break;
            }

            break;

      case VL_NYX:
            if (oq != (point_t *) NULL) {
                  pt->x = opt->x = oq->y;
                  pt->y = oq->x;
                  opt->y = oq->z;
                  q->z = oq->z;
            }
            else {
                  q->z = p->other_view->origin_y;
            }
                  
            q->x = y;
            q->y = x;
            z = q->z;
            q->point.x = - (y - p->origin_x) * pixel_scale;
            q->point.y = (x - p->origin_y) * pixel_scale;

            switch (p->other_view->layout) {

            case VL_NYZ:
                  if (plane_established) {
                        q->point.z = - (poly->normal.x * q->point.x +
                              poly->normal.y * q->point.y + poly->d) /
                              poly->normal.z;
                        z = q->z = q->point.z / pixel_scale +
                              p->other_view->origin_y;
                  }
                  else 
                        q->point.z = (q->z - p->other_view->origin_y)*
                              pixel_scale;
                  break;

            case VL_NYNZ:
                  if (plane_established) {
                        q->point.z = - (poly->normal.x * q->point.x +
                              poly->normal.y * q->point.y + poly->d) /
                              poly->normal.z;
                        z = q->z = - q->point.z / pixel_scale +
                              p->other_view->origin_y;
                  }
                  else
                        q->point.z = - (q->z - p->other_view->origin_y)*
                              pixel_scale;
                  break;
            }

            break;
      }

      DisplayPoint (q);

      return z;
      
}

int
DragPoint (w, p, poly, delta, pt, opt)
Widget      w;
view_info_t *p;
polygon_t   *poly;
int         delta;
XPoint            *pt, *opt;
{

      view_info_t *p1;
      point_t           *q, *oq;
      int         z;

      if (poly->num_points == 1)
            oq = (point_t *) NULL;
      else
            oq = &poly->point[poly->num_points-2];

      q = &poly->point[poly->num_points-1];

      switch (p->layout) {

      case VL_NXZ:
            if (oq != (point_t *) NULL) {
                  pt->x = opt->x = oq->x;
                  pt->y = oq->z;
                  opt->y = oq->y;
            }

            switch (p->other_view->layout) {

            case VL_NXNY:
                  q->y = drag_origin.y + delta;
                  q->point.y = - (q->y - p->other_view->origin_y) *
                        pixel_scale;
                  break;

            case VL_NXY:
                  q->y = drag_origin.y + delta;
                  q->point.y = (q->y - p->other_view->origin_y) *
                        pixel_scale;
                  break;
            }

            z = q->y;

            break;

      case VL_NXNY:
            if (oq != (point_t *) NULL) {
                  pt->x = opt->x = oq->x;
                  pt->y = oq->y;
                  opt->y = oq->z;
            }

            switch (p->other_view->layout) {

            case VL_NXNZ:
                  q->z = drag_origin.y + delta;
                  q->point.z = - (q->z - p->other_view->origin_y) *
                        pixel_scale;
                  break;

            case VL_NXZ:
                  q->z = drag_origin.y + delta;
                  q->point.z = (q->z - p->other_view->origin_y) *
                        pixel_scale;
                  break;
            }

            z = q->z;

            break;

      case VL_NYX:
            if (oq != (point_t *) NULL) {
                  pt->x = opt->x = oq->y;
                  pt->y = oq->x;
                  opt->y = oq->z;
            }

            switch (p->other_view->layout) {

            case VL_NYNZ:
                  q->z = drag_origin.y + delta;
                  q->point.z = - (q->z - p->other_view->origin_y) *
                        pixel_scale;
                  break;

            case VL_NYZ:
                  q->z = drag_origin.y + delta;
                  q->point.x = (q->z - p->other_view->origin_y) *
                        pixel_scale;
                  break;
            }

            z = q->z;

            break;

      case VL_NYZ:
            if (oq != (point_t *) NULL) {
                  pt->x = opt->x = oq->y;
                  pt->y = oq->z;
                  opt->y = oq->x;
            }

            switch (p->other_view->layout) {

            case VL_NYNX:
                  q->x = drag_origin.y + delta;
                  q->point.x = - (q->x - p->other_view->origin_y) *
                        pixel_scale;
                  break;

            case VL_NYX:
                  q->x = drag_origin.y + delta;
                  q->point.x = (q->x - p->other_view->origin_y) *
                        pixel_scale;
                  break;
            }

            z = q->x;

            break;
      }

      DisplayPoint (q);

      return z;
      
}

void
BeginPolygonPoint (w, p, x, y)
Widget       w;
view_info_t *p;
int   x, y;
{

      int         z;
      Display           *dpy;
      Drawable    w1, w2;
      XPoint            last, last_other;
      polygon_t   *poly;

      dpy = XtDisplay (w);
      w1 = XtWindow (w);
      w2 = XtWindow (p->other_widget);

      if (cur_polygon == NULL)
            BeginPolygon ();

      poly = cur_polygon;

      drag_origin.x = x;
      drag_origin.y = y;
      XSetFunction (dpy, p->gc, GXxor);
      XSetForeground (dpy, p->gc, app_data.select_pixel);
      XSetLineAttributes (dpy, p->gc, app_data.selection_thickness, LineSolid,
            CapButt, JoinMiter);

      XFillRectangle (dpy, w1, p->gc,
            x + app_data.box_offset, y + app_data.box_offset,
            app_data.box_size, app_data.box_size);
      z = PinPoint (w, p, poly, x, y, &last, &last_other);
      XFillRectangle (dpy, w2, p->gc,
            x + app_data.box_offset, z + app_data.box_offset,
            app_data.box_size, app_data.box_size);

      if (poly->num_points > 1) {
            XDrawLine (dpy, w1, p->gc, last.x, last.y, x, y);
            XDrawLine (dpy, w2, p->gc, last_other.x, last_other.y, x, z);
            rubber_lines[0].x1 = last.x;
            rubber_lines[0].y1 = last.y;
            rubber_lines[0].x2 = x;
            rubber_lines[0].y2 = y;
            rubber_lines[1].x1 = last_other.x;
            rubber_lines[1].y1 = last_other.y;
      }
      rubber_lines[1].x2 = x;
      rubber_lines[1].y2 = z;
      XSetFunction (dpy, p->gc, GXcopy);

}

void
DragPolygonPoint(w, p, x, y)
Widget       w;
view_info_t *p;
int   x, y;
{
      int         z, nx, delta;
      Display           *dpy;
      Drawable    w1, w2;
      XPoint            last, last_other;
      polygon_t   *poly;

      dpy = XtDisplay (w);
      w1 = XtWindow (w);
      w2 = XtWindow (p->other_widget);

      poly = cur_polygon;

/*
 *  We don't drag points once the polygon's plane is determined.
 */

      if (poly->num_points > 3)
            return;

/*
 *  Erase old stuff
 */
      XSetFunction (dpy, p->other_view->gc, GXxor);
      XFillRectangle (dpy, w2, p->other_view->gc,
            rubber_lines[1].x2 + app_data.box_offset,
            rubber_lines[1].y2 + app_data.box_offset,
            app_data.box_size, app_data.box_size);
      if (poly->num_points > 1) {
            XDrawSegments (dpy, w2, p->other_view->gc,
                  &rubber_lines[1], 1);
      }

/*
 *  Draw new line/point
 */

      delta = y - drag_origin.y;
      nx = rubber_lines[1].x2;
      z = DragPoint (w, p, poly, delta, &last, &last_other);
      XFillRectangle (dpy, w2, p->other_view->gc,
            nx + app_data.box_offset, z + app_data.box_offset,
            app_data.box_size, app_data.box_size);

      if (poly->num_points > 1) {
            XDrawLine (dpy, w2, p->other_view->gc,
                  last_other.x, last_other.y, nx, z);
      }
      rubber_lines[1].y2 = z;
      
      XSetFunction (dpy, p->other_view->gc, GXcopy);
}

void
CompletePolygonPoint(w, p, x, y)
Widget       w;
view_info_t *p;
int   x, y;
{
      if (cur_polygon)
            if (cur_polygon->num_points == 3)
                  ComputePlaneEquation (cur_polygon);
}

void
CompletePolygon (w, p)
Widget            w;
polygon_t   *p;
{

      register point_t *points;
      view_info_t *q;

      XtVaGetValues (w,
            XmNuserData,      &q,
            NULL);

      if (p == (polygon_t *) NULL)
            return;

      if (p->num_points < 3) {
            p->num_points = 0;
            return;
      }

      points = (point_t *) malloc (p->num_points * sizeof(point_t));

      bcopy ((char *) tmp_point, (char *) points,
            p->num_points * sizeof (point_t));

      p->point = points;

/*
 *  Add this polygon to the selected list.
 */

      p->next = sel_polygon;
      sel_polygon = p->id;
      cur_polygon = (polygon_t *) NULL;

#ifdef notdef
      DrawPolygon (w, p, True);
      DrawPolygon (q->other_widget, p, True);
#endif
      DrawWidget (w, False);
      DrawWidget (q->other_widget, False);

}

int
PolygonProximity (p, poly, x, y)
view_info_t *p;
polygon_t   *poly;
int         x, y; {

      register long     i, min_distance, d;
      int         xp, yp;

      min_distance = 0x3fffffff;

      for (i=0; i < poly->num_points; ++ i) {
            WorldToWidget (p, &poly->point[i], &xp, &yp);
            xp -= x;
            yp -= y;
            d = (int) sqrt ((double) (xp * xp + yp * yp));
            if (d < min_distance) {
                  min_distance = d;
            }
      }

      return min_distance;
}

int
PickObject (p, x, y)
view_info_t *p;
int         x, y; {

      register int      i, dist, d, id = -1;

      dist = 0x3fffffff;

      for (i=0; i < polygon_max; ++i) {
            if (polygon_list[i].num_points == 0)
                  continue;
            if ((d = PolygonProximity (p, &polygon_list[i], x, y)) < dist) {
                  dist = d;
                  id = i;
            }
      }

      if (dist < app_data.pick_sensitivity)
            return id;
      else
            return -1;
}

void
CompleteMarker(w, p, x, y)
Widget       w;
view_info_t *p;
int   x, y;
{
      if (cur_polygon) {
            marker_list[current_marker].defined = True;
            marker_list[current_marker].location = cur_polygon->point[0];
            cur_polygon = NULL;
            DrawWidget (w, False);
            DrawWidget (p->other_widget, False);
      }
}

void
BeginPick (w, p, x, y, extend)
Widget             w;
view_info_t *p;
int         x, y;
Boolean           extend;
{

      register int      id, last, i;

      id = PickObject (p, x, y);

      if (extend) {
            if (id >= 0) {
                  SelectObject (id);
            }
      }
      else {
            if (id == -1) { 
                if (sel_polygon >= 0) {
                  for (i=sel_polygon; i >= 0; i = polygon_list[i].next)
                        last = i;
                  polygon_list[last].next = unsel_polygon;
                  unsel_polygon = sel_polygon;
                  sel_polygon = -1;
                }
            }
            else if (sel_polygon >= 0) {
                  drag_origin.x = x;
                  drag_origin.y = y;
                  drag_mode = True;
            }
            else {
                  SelectObject (id);
            }
      }

      DrawWidget (w, False);
      DrawWidget (p->other_widget, False);
}

void
DragSelection (w, p, x, y)
Widget      w;
view_info_t *p;
int         x, y;
{
      register int      dx, dy, i, j;
      point_t           q;
      polygon_t   *poly;

      dx = x - drag_origin.x + p->origin_x;
      dy = y - drag_origin.y + p->origin_y;
      drag_origin.x = x;
      drag_origin.y = y;

      PointXY (w, p, dx, dy, &q);

      for (i=sel_polygon; i >= 0; i = polygon_list[i].next)
            DrawSelectedPolygon (w, &polygon_list[i], True, True);

      for (i=sel_polygon; i >= 0; i = polygon_list[i].next) {
            poly = &polygon_list[i];
            for (j=0; j<poly->num_points; ++j) {
                  poly->point[j].point.x += q.point.x;
                  poly->point[j].point.y += q.point.y;
                  poly->point[j].point.z += q.point.z;
                  PointToXYZ (p, &poly->point[j]);
            }
            DrawSelectedPolygon (w, poly, True, False);
      }

}

void
CompleteDrag (w, p, x, y)
Widget      w;
view_info_t *p;
int         x, y;
{
      drag_mode = False;
      DrawWidget (w, False);
      DrawWidget (p->other_widget, False);
}

void
SelectObject (id)
int   id;
{
      register int      i, last;

      if (unsel_polygon == -1) {
            polygon_list[id].next = sel_polygon;
            sel_polygon = id;
            return;
      }

      if (unsel_polygon == id) {
            unsel_polygon = polygon_list[id].next;
            polygon_list[id].next = sel_polygon;
            sel_polygon = id;
            return;
      }

      last = unsel_polygon;   
      for (i=polygon_list[unsel_polygon].next; i >= 0;
            i = polygon_list[i].next) {
            if (i == id) {
                  polygon_list[last].next = polygon_list[id].next;
                  polygon_list[id].next = sel_polygon;
                  sel_polygon = id;
                  return;
            }
            last = i;
      }
            
}

void
DetermineObjectExtent (extent)
VPoint *extent;
{

      VPoint min, max;
      register int i, j;
      polygon_t *poly;

      min.x = min.y = min.z =  10000000.0;
      max.x = max.y = max.z = -10000000.0;

      for (i=0; i < polygon_max; ++i) {
            if (polygon_list[i].num_points == 0)
                  continue;
            poly = &polygon_list[i];
            for (j=0; j<poly->num_points; ++j) {
                  if (poly->point[j].point.x > max.x)
                        max.x = poly->point[j].point.x;
                  if (poly->point[j].point.y > max.y)
                        max.y = poly->point[j].point.y;
                  if (poly->point[j].point.z > max.z)
                        max.z = poly->point[j].point.z;
                  if (poly->point[j].point.x < min.x)
                        min.x = poly->point[j].point.x;
                  if (poly->point[j].point.y < min.y)
                        min.y = poly->point[j].point.y;
                  if (poly->point[j].point.z < min.z)
                        min.z = poly->point[j].point.z;
            }
      }

      extent->x = max.x - min.x;
      extent->y = max.y - min.y;
      extent->z = max.z - min.z;
}

void
RescaleObject (factor)
double factor;
{

      register int      i, j;
      polygon_t   *poly;

      for (i=0; i < polygon_max; ++i) {
            if (polygon_list[i].num_points == 0)
                  continue;
            poly = &polygon_list[i];
            for (j=0; j<poly->num_points; ++j) {
                  poly->point[j].point.x *= factor;
                  poly->point[j].point.y *= factor;
                  poly->point[j].point.z *= factor;
            }
      }

      for (i=0; i < marker_count; ++i) {
            if (marker_list[i].defined) {
                  marker_list[i].location.point.x *= factor;
                  marker_list[i].location.point.y *= factor;
                  marker_list[i].location.point.z *= factor;
            }
      }

      RescaleView (twindow, 1.0);
}

Generated by  Doxygen 1.6.0   Back to index