/* ********************************************************************************** * * Project : Imagine * File : Bezier.c * Version : $Id$ * Author : Patrick LECOANET * Created On : Thu Mar 23 21:59:43 1995 * Last Modified By: Patrick Lecoanet * Last Modified On: Thu Mar 23 23:10:45 1995 * Update Count : 21 * Purpose : implementation of Bezier arc item. * ********************************************************************************** */ /*---------------- Distribution and Copyright ------------------- * * This software is copyright by the CENA/DGAC/FRANCE * * All rights reserved. * * No part of the material protected by this copyright notice * may be reproduced or utilized for commercial use in any form * without written permission of the copyright owner. * * It may be reproduced or utilized for R&D use in Non Profit * Organization * *---------------------------------------------------------------*/ /*---------------- Disclaimer ----------------------------------- * * This software and its documentation are provided "AS IS" and * without any expressed or implied warranties whatsoever. * No warranties as to performance, merchantability, or fitness * for a particular purpose exist. * * Because of the diversity of conditions and hardware under * which this software may be used, no warranty of fitness for * a particular purpose is offered. The user is advised to * test the software thoroughly before relying on it. The user * must assume the entire risk and liability of using this * software. * * In no event shall any person or organization of people be * held responsible for any direct, indirect, consequential * or inconsequential damages or lost profits. * *-----------------END-PROLOGUE----------------------------------*/ /* ********************************************************************************** * * Included files * ********************************************************************************** */ #include "ReliefStyConv.h" #include "RadarP.h" #include "ItemP.h" #include "GeoP.h" #include "DrawP.h" #include "ActionsP.h" /* ********************************************************************************** * * Constants. * ********************************************************************************** */ static char rcsid[] = "$Id$"; static char invalid_attribute[] = "RadarBezier : Invalid attribute."; static char invalid_pixmap[] = "RadarBezier : Pixmaps used in patterns must be of depth 1."; static char read_only_attribute[] = "This attribute is read only."; static RadarList smoothed_points = NULL; static RadarList control_points = NULL; /* ********************************************************************************** * * Specific Bezier item record * ********************************************************************************** */ typedef struct _BezierItemStruct { ItemHeader header; /* Public data */ int x1; int y1; int x2; int y2; int xc1; int yc1; int xc2; int yc2; unsigned char spline_steps; unsigned int line_width; Pixel line_foreground; Pixmap line_pattern; /* Private data */ } BezierItemStruct, *BezierItem; /* ********************************************************************************** * * Init -- * ********************************************************************************** */ static void Init(Widget rw, Item item ) { RadarPart *rp = &(((RadarWidget) rw)->radar); BezierItem bzr = (BezierItem) item; if (!smoothed_points) smoothed_points = RadarListNew(0, sizeof(XPoint)); if (!control_points) { control_points = RadarListNew(4, sizeof(XPoint)); RadarListAssertSize(control_points, 4); } /* Init attributes */ ITEM_COMMON_INIT(item, NULL, True, True, DEFAULT_BEZIER_PRIORITY); bzr->x1 = 0; bzr->y1 = 0; bzr->x2 = 0; bzr->y2 = 0; bzr->xc1 = 0; bzr->yc1 = 0; bzr->xc2 = 0; bzr->yc2 = 0; bzr->spline_steps = 10; bzr->line_width = 1; bzr->line_foreground = rp->foreground; bzr->line_pattern = XtUnspecifiedPixmap; } /* ********************************************************************************** * * Clone -- * ********************************************************************************** */ static void Clone(Widget rw, Item item ) { BezierItem bzr = (BezierItem) item; item->user_data = NULL; } /* ********************************************************************************** * * Remove -- * ********************************************************************************** */ static void Remove(Widget rw, Item item ) { BezierItem bzr = (BezierItem) item; } /* ********************************************************************************** * * Configure -- * ********************************************************************************** */ static void Configure(Widget rw, Item item, RadarList attrs, Boolean *draw_item, Boolean *draw_label, Boolean *compute_coord, Boolean init ) { RadarPart *radar = &(((RadarWidget) rw)->radar); BezierItem bzr = (BezierItem) item; Cardinal i, num_attrs; RadarAttr *attr; Boolean b_value; int value; Pixmap pattern; num_attrs = RadarListSize(attrs); for (i = 0; i < num_attrs; i++) { attr = (RadarAttr *) RadarListAt(attrs, i); switch (attr->name) { ITEM_COMMON_CONFIGURE; case RadarItemX: if ((int) attr->value != bzr->x1) { bzr->x1 = (int) attr->value; *draw_item = *compute_coord = True; } break; case RadarItemY: if ((int) attr->value != bzr->y1) { bzr->y1 = (int) attr->value; *draw_item = *compute_coord = True; } break; case RadarItemX2: if ((int) attr->value != bzr->xc1) { bzr->xc1 = (int) attr->value; *draw_item = *compute_coord = True; } break; case RadarItemY2: if ((int) attr->value != bzr->yc1) { bzr->yc1 = (int) attr->value; *draw_item = *compute_coord = True; } break; case RadarItemX3: if ((int) attr->value != bzr->xc2) { bzr->xc2 = (int) attr->value; *draw_item = *compute_coord = True; } break; case RadarItemY3: if ((int) attr->value != bzr->yc2) { bzr->yc2 = (int) attr->value; *draw_item = *compute_coord = True; } break; case RadarItemX4: if ((int) attr->value != bzr->x2) { bzr->x2 = (int) attr->value; *draw_item = *compute_coord = True; } break; case RadarItemY4: if ((int) attr->value != bzr->y2) { bzr->y2 = (int) attr->value; *draw_item = *compute_coord = True; } break; case RadarItemSplineSteps: value = (unsigned char) attr->value; if (value > 0 && value <= 100 && value != bzr->spline_steps) { bzr->spline_steps = value; *draw_item = True; } break; case RadarItemLineWidth: if (((unsigned int) attr->value) != bzr->line_width) { bzr->line_width = (unsigned int) attr->value; *draw_item = *compute_coord = True; } break; case RadarItemLineForeground: if ((Pixel) attr->value != bzr->line_foreground) { bzr->line_foreground = (Pixel) attr->value; *draw_item = True; } break; case RadarItemLinePattern: if (!DRAW.ValidBitmap(XtDisplay(rw), (Pixmap) attr->value, &pattern)) { XtAppWarning(radar->app_context, invalid_pixmap); continue; } if (pattern != bzr->line_pattern) { bzr->line_pattern = pattern; *draw_item = True; } break; default: XtAppWarning(radar->app_context, invalid_attribute); break; } } } /* ********************************************************************************** * * Query -- * ********************************************************************************** */ static void Query(Widget rw, Item item, RadarList attrs ) { RadarPart *radar = &(((RadarWidget) rw)->radar); BezierItem bzr = (BezierItem) item; Cardinal i, num_attrs; RadarAttr *attr; num_attrs = RadarListSize(attrs); for (i = 0; i < num_attrs; i++) { attr = (RadarAttr *) RadarListAt(attrs, i); switch (attr->name) { ITEM_COMMON_QUERY; case RadarItemX: *((int *) attr->value) = bzr->x1; break; case RadarItemY: *((int *) attr->value) = bzr->y1; break; case RadarItemX2: *((int *) attr->value) = bzr->xc1; break; case RadarItemY2: *((int *) attr->value) = bzr->yc1; break; case RadarItemX3: *((int *) attr->value) = bzr->xc2; break; case RadarItemY3: *((int *) attr->value) = bzr->yc2; break; case RadarItemX4: *((int *) attr->value) = bzr->x2; break; case RadarItemY4: *((int *) attr->value) = bzr->y2; break; case RadarItemSplineSteps: *((unsigned char *) attr->value) = bzr->spline_steps; break; case RadarItemLineWidth: *((unsigned int *) attr->value) = bzr->line_width; break; case RadarItemLineForeground: *((Pixel *) attr->value) = bzr->line_foreground; break; case RadarItemLinePattern: *((Pixmap *) attr->value) = bzr->line_pattern; break; default: XtAppWarning(radar->app_context, invalid_attribute); break; } } } /* ********************************************************************************** * * ComputeCoordinates -- * ********************************************************************************** */ static void ComputeCoordinates(Widget rw, Item item ) { RadarPart *rp = &(((RadarWidget) rw)->radar); BezierItem bzr = (BezierItem) item; XPoint *points; int i, len; Dimension dev_line_width; ResetBBox(&item->item_bounding_box); if (!bzr->line_width) return; points = (XPoint *) RadarListArray(control_points); points[0].x = X_TO_DEVICE(rp, bzr->x1); points[0].y = Y_TO_DEVICE(rp, bzr->y1); points[1].x = X_TO_DEVICE(rp, bzr->xc1); points[1].y = Y_TO_DEVICE(rp, bzr->yc1); points[2].x = X_TO_DEVICE(rp, bzr->xc2); points[2].y = Y_TO_DEVICE(rp, bzr->yc2); points[3].x = X_TO_DEVICE(rp, bzr->x2); points[3].y = Y_TO_DEVICE(rp, bzr->y2); item->connection_dev = points[0]; if (bzr->line_width > 1) dev_line_width = MAX(1, LENGTH_TO_DEVICE(rp, bzr->line_width)); else dev_line_width = 1; RadarListEmpty(smoothed_points); DRAW.GetBezierPath(control_points, bzr->spline_steps, smoothed_points); len = RadarListSize(smoothed_points); points = (XPoint *) RadarListArray(smoothed_points); for (i = 0; i < len; i++) AddPointToBBox(&item->item_bounding_box, points[i].x, points[i].y); /* * For thick lines adjust the bounding box. Add the line width in * all directions, this overestimates the space but is fast. */ if (dev_line_width > 1) { item->item_bounding_box.x -= dev_line_width; item->item_bounding_box.y -= dev_line_width; item->item_bounding_box.width += dev_line_width*2; item->item_bounding_box.height += dev_line_width*2; } } /* ********************************************************************************** * * ToArea -- * Tell if the object is entirely outside (-1), * entirely inside (1) or in between (0). * ********************************************************************************** */ static int ToArea(Widget rw, Item item, XRectangle *area) { } /* ********************************************************************************** * * Draw -- * ********************************************************************************** */ static void Draw(Widget rw, Item item ) { RadarPart *radar = &(((RadarWidget) rw)->radar); BezierItem bzr = (BezierItem) item; XGCValues values; XPoint *points; int len, i; Dimension dev_line_width; if (bzr->line_width) { points = (XPoint *) RadarListArray(control_points); points[0].x = X_TO_DEVICE(radar, bzr->x1); points[0].y = Y_TO_DEVICE(radar, bzr->y1); points[1].x = X_TO_DEVICE(radar, bzr->xc1); points[1].y = Y_TO_DEVICE(radar, bzr->yc1); points[2].x = X_TO_DEVICE(radar, bzr->xc2); points[2].y = Y_TO_DEVICE(radar, bzr->yc2); points[3].x = X_TO_DEVICE(radar, bzr->x2); points[3].y = Y_TO_DEVICE(radar, bzr->y2); if (bzr->line_width > 1) dev_line_width = MAX(1, LENGTH_TO_DEVICE(radar, bzr->line_width)); else dev_line_width = 1; RadarListEmpty(smoothed_points); DRAW.GetBezierPath(control_points, bzr->spline_steps, smoothed_points); len = RadarListSize(smoothed_points); points = (XPoint *) RadarListArray(smoothed_points); values.foreground = bzr->line_foreground; values.line_width = (dev_line_width == 1) ? 0 : dev_line_width; if (bzr->line_pattern == XtUnspecifiedPixmap) { values.fill_style = FillSolid; XChangeGC(XtDisplay(rw), radar->gc, GCFillStyle | GCLineWidth | GCForeground, &values); } else { values.fill_style = FillStippled; values.stipple = bzr->line_pattern; XChangeGC(XtDisplay(rw), radar->gc, GCFillStyle | GCStipple | GCLineWidth | GCForeground, &values); } XDrawLines(XtDisplay(rw), radar->draw_buffer, radar->gc, points, len, CoordModeOrigin); } } /* ********************************************************************************** * * Pick -- * ********************************************************************************** */ static Boolean Pick(Widget rw, Item item, XPoint *p, Dimension aperture, Boolean closest, RadarList items) { RadarPart *rp = &(((RadarWidget) rw)->radar); BezierItem bzr = (BezierItem) item; double dist, new_dist; XPoint *points; int len, i; Dimension dev_line_width; points = (XPoint *) RadarListArray(control_points); points[0].x = X_TO_DEVICE(rp, bzr->x1); points[0].y = Y_TO_DEVICE(rp, bzr->y1); points[1].x = X_TO_DEVICE(rp, bzr->xc1); points[1].y = Y_TO_DEVICE(rp, bzr->yc1); points[2].x = X_TO_DEVICE(rp, bzr->xc2); points[2].y = Y_TO_DEVICE(rp, bzr->yc2); points[3].x = X_TO_DEVICE(rp, bzr->x2); points[3].y = Y_TO_DEVICE(rp, bzr->y2); if (bzr->line_width > 1) dev_line_width = MAX(1, LENGTH_TO_DEVICE(rp, bzr->line_width)); else dev_line_width = 1; RadarListEmpty(smoothed_points); DRAW.GetBezierPath(control_points, bzr->spline_steps, smoothed_points); len = RadarListSize(smoothed_points); points = (XPoint *) RadarListArray(smoothed_points); dist = 1.0e40; for (i = 0; i < len-1; i++) { new_dist = LineToPointDist(&points[i], &points[i+1], p); dist = MIN(dist, new_dist); } /* * Take the line width into account if it is meaningful. */ if (dist != 0 && dev_line_width > 1) dist = MAX(0.0, dist - (((double) dev_line_width)/2.0)); return ACTIONS.AddToPickedItems(items, item, RADAR_CURRENT_POSITION, dist, aperture, closest); } /* ********************************************************************************** * * PostScript -- * ********************************************************************************** */ static void PostScript(Widget rw, Item item, PostScriptInfo ps_info) { } /* ********************************************************************************** * * Exported functions struct -- * ********************************************************************************** */ static ItemClassStruct BEZIER_ITEM_CLASS = { sizeof(BezierItemStruct), False, 1, Init, Clone, Remove, Configure, Query, ComputeCoordinates, ToArea, Draw, Pick, PostScript }; RadarItemClassId RadarBezier = (RadarItemClassId) &BEZIER_ITEM_CLASS;