/* * 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 #include #include "gedit.h" #include 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; jnum_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; jnum_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; jnum_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); }