diff options
-rw-r--r-- | generic/Track.c | 1771 |
1 files changed, 1771 insertions, 0 deletions
diff --git a/generic/Track.c b/generic/Track.c new file mode 100644 index 0000000..bcfdcf5 --- /dev/null +++ b/generic/Track.c @@ -0,0 +1,1771 @@ +/* + * Track.c -- Implementation of Track and WayPoint items. + * + * Authors : Patrick Lecoanet. + * Creation date : + * + * $Id$ + */ + +/* + * Copyright (c) 1993 - 1999 CENA, Patrick Lecoanet -- + * + * This code is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This code 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this code; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include "Track.h" +#include "Draw.h" +#include "Geo.h" +#include "Item.h" +#include "Types.h" +#include "WidgetInfo.h" + + +static const char rcsid[] = "$Id$"; +static const char compile_id[]="$Compile: " __FILE__ " " __DATE__ " " __TIME__ " $"; + + +#define SPEED_VECTOR_PICKING_THRESHOLD 5 /* In pixels */ + +#define MARKER_FILLED_BIT 1 << 0 +#define FILLED_HISTORY_BIT 1 << 1 +#define DOT_MIXED_HISTORY_BIT 1 << 2 +#define CIRCLE_HISTORY_BIT 1 << 3 +#define POLAR_BIT 1 << 5 +#define FROZEN_LABEL_BIT 1 << 6 + + +/* + ********************************************************************************** + * + * Specific Track item record + * + ********************************************************************************** + */ + +typedef struct { + RadarPoint world; /* world coord of pos */ + RadarPoint dev; /* dev coord of pos */ + RadarBool visible; +} HistoryStruct, *History; + +typedef struct _TrackItemStruct { + ItemStruct header; + + /* Public data */ + unsigned char flags; + Pixmap symbol; /* item symbol */ + RadarColor symbol_color; + int label_angle; /* Label angle from track. */ + int label_distance; /* Label distance from track. */ + int label_dx; /* Label dx/dy from track. */ + int label_dy; + RadarAnchor label_anchor; + LeaderAnchors leader_anchors; /* Spec of the leader attachment */ + RadarColor leader_color; /* leader color */ + LineStyle leader_style; + LineShape leader_shape; + LineEnd leader_first_end; + LineEnd leader_last_end; + int leader_width; + int marker_size; /* world size of error circle */ + RadarColor marker_color; /* error circle color */ + LineStyle marker_style; /* error circle style */ + Pixmap marker_fill_pattern; /* error circle fill pattern */ + RadarColor connection_color; /* connection color */ + LineStyle connection_style; + int connection_width; + RadarColor speed_vector_color; /* s. v. color */ + int visible_history_size; /* Number of visible positions */ + RadarPoint pos; /* item world coordinates */ + RadarPoint speed_vector; /* s. v. slope in world coord */ + + /* Private data */ + FieldSetStruct field_set; + RadarPoint dev; /* device coords of current pos */ + RadarPoint speed_vector_dev; /* s. v. end in device coord */ + RadarDim marker_size_dev; /* dev size of error circle */ + RadarList history; /* pos list */ + RadarList leader_points; +} TrackItemStruct, *TrackItem; + + +static RadarAttrConfig track_attrs[] = { + { RADAR_CONFIG_BOOL, "-circlehistory", NULL, + Tk_Offset(TrackItemStruct, flags), CIRCLE_HISTORY_BIT, RADAR_DRAW_FLAG, False }, + { RADAR_CONFIG_BOOL, "-composerotation", NULL, + Tk_Offset(TrackItemStruct, header.flags), COMPOSE_ROTATION_BIT, + RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_BOOL, "-composescale", NULL, + Tk_Offset(TrackItemStruct, header.flags), COMPOSE_SCALE_BIT, + RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_ITEM, "-connecteditem", NULL, + Tk_Offset(TrackItemStruct, header.connected_item), 0, + RADAR_COORDS_FLAG|RADAR_ITEM_FLAG, False }, + { RADAR_CONFIG_COLOR, "-connectioncolor", NULL, + Tk_Offset(TrackItemStruct, connection_color), 0, RADAR_DRAW_FLAG, False }, + { RADAR_CONFIG_BOOL, "-connectionsensitive", NULL, + Tk_Offset(TrackItemStruct, header.part_sensitive), PART_NUMBER_TO_BIT(RADAR_CONNECTION), + RADAR_REPICK_FLAG, False }, + { RADAR_CONFIG_LINE_STYLE, "-connectionstyle", NULL, + Tk_Offset(TrackItemStruct, connection_style), 0, RADAR_DRAW_FLAG, False }, + { RADAR_CONFIG_DIM, "-connectionwidth", NULL, + Tk_Offset(TrackItemStruct, connection_width), 0, RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_BOOL, "-filledhistory", NULL, + Tk_Offset(TrackItemStruct, flags), FILLED_HISTORY_BIT, RADAR_DRAW_FLAG, False }, + { RADAR_CONFIG_BOOL, "-filledmarker", NULL, + Tk_Offset(TrackItemStruct, flags), MARKER_FILLED_BIT, RADAR_DRAW_FLAG, False }, + { RADAR_CONFIG_BOOL, "-frozenlabel", NULL, + Tk_Offset(TrackItemStruct, flags), FROZEN_LABEL_BIT, RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_ANCHOR, "-labelanchor", NULL, + Tk_Offset(TrackItemStruct, label_anchor), 0, RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_ANGLE, "-labelangle", NULL, + Tk_Offset(TrackItemStruct, label_angle), 0, + RADAR_COORDS_FLAG|RADAR_POLAR_FLAG, False }, + { RADAR_CONFIG_DIM, "-labeldistance", NULL, + Tk_Offset(TrackItemStruct, label_distance), 0, + RADAR_COORDS_FLAG|RADAR_POLAR_FLAG, False }, + { RADAR_CONFIG_DIM, "-labeldx", NULL, + Tk_Offset(TrackItemStruct, label_dx), 0, + RADAR_COORDS_FLAG|RADAR_CARTESIAN_FLAG, False }, + { RADAR_CONFIG_DIM, "-labeldy", NULL, + Tk_Offset(TrackItemStruct, label_dy), 0, + RADAR_COORDS_FLAG|RADAR_CARTESIAN_FLAG, False }, + { RADAR_CONFIG_LABEL_FORMAT, "-labelformat", NULL, + Tk_Offset(TrackItemStruct, field_set.label_format), 0, + RADAR_COORDS_FLAG|RADAR_CLFC_FLAG, False }, + { RADAR_CONFIG_LEADER_ANCHORS, "-leaderanchors", NULL, + Tk_Offset(TrackItemStruct, leader_anchors), 0, RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_COLOR, "-leadercolor", NULL, + Tk_Offset(TrackItemStruct, leader_color), 0, RADAR_DRAW_FLAG, False }, + { RADAR_CONFIG_LINE_END, "-leaderfirstend", NULL, + Tk_Offset(TrackItemStruct, leader_first_end), 0, RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_LINE_END, "-leaderlastend", NULL, + Tk_Offset(TrackItemStruct, leader_last_end), 0, RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_BOOL, "-leadersensitive", NULL, + Tk_Offset(TrackItemStruct, header.part_sensitive), PART_NUMBER_TO_BIT(RADAR_LEADER), + RADAR_REPICK_FLAG, False }, + { RADAR_CONFIG_LINE_STYLE, "-leaderstyle", NULL, + Tk_Offset(TrackItemStruct, leader_style), 0, RADAR_DRAW_FLAG, False }, + { RADAR_CONFIG_LINE_SHAPE, "-leadershape", NULL, + Tk_Offset(TrackItemStruct, leader_shape), 0, RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_DIM, "-leaderwidth", NULL, + Tk_Offset(TrackItemStruct, leader_width), 0, RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_COLOR, "-markercolor", NULL, + Tk_Offset(TrackItemStruct, marker_color), 0, RADAR_DRAW_FLAG, False }, + { RADAR_CONFIG_PATTERN, "-markerfillpattern", NULL, + Tk_Offset(TrackItemStruct, marker_fill_pattern), 0, RADAR_DRAW_FLAG, False }, + { RADAR_CONFIG_DIM, "-markersize", NULL, + Tk_Offset(TrackItemStruct, marker_size), 0, RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_LINE_STYLE, "-markerstyle", NULL, + Tk_Offset(TrackItemStruct, marker_style), 0, RADAR_DRAW_FLAG, False }, + { RADAR_CONFIG_BOOL, "-mixedhistory", NULL, + Tk_Offset(TrackItemStruct, flags), DOT_MIXED_HISTORY_BIT, RADAR_DRAW_FLAG, False }, + { RADAR_CONFIG_UINT, "-numfields", NULL, + Tk_Offset(TrackItemStruct, field_set.num_fields), 0, 0, True }, + { RADAR_CONFIG_POINT, "-position", NULL, Tk_Offset(TrackItemStruct, pos), 0, + RADAR_COORDS_FLAG|RADAR_MOVED_FLAG, False}, + { RADAR_CONFIG_PRI, "-priority", NULL, + Tk_Offset(TrackItemStruct, header.priority), 0, + RADAR_DRAW_FLAG|RADAR_REPICK_FLAG, False }, + { RADAR_CONFIG_BOOL, "-sensitive", NULL, + Tk_Offset(TrackItemStruct, header.flags), SENSITIVE_BIT, RADAR_REPICK_FLAG, False }, + { RADAR_CONFIG_POINT, "-speedvector", NULL, Tk_Offset(TrackItemStruct, speed_vector), 0, + RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_COLOR, "-speedvectorcolor", NULL, + Tk_Offset(TrackItemStruct, speed_vector_color), 0, RADAR_DRAW_FLAG, False }, + { RADAR_CONFIG_BOOL, "-speedvectorsensitive", NULL, + Tk_Offset(TrackItemStruct, header.part_sensitive), PART_NUMBER_TO_BIT(RADAR_SPEED_VECTOR), + RADAR_REPICK_FLAG, False }, + { RADAR_CONFIG_PATTERN, "-symbol", NULL, + Tk_Offset(TrackItemStruct, symbol), 0, RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_COLOR, "-symbolcolor", NULL, + Tk_Offset(TrackItemStruct, symbol_color), 0, RADAR_DRAW_FLAG, False }, + { RADAR_CONFIG_BOOL, "-symbolsensitive", NULL, + Tk_Offset(TrackItemStruct, header.part_sensitive), PART_NUMBER_TO_BIT(RADAR_CURRENT_POSITION), + RADAR_REPICK_FLAG, False }, + { RADAR_CONFIG_TAGS, "-tags", NULL, + Tk_Offset(TrackItemStruct, header.tags), 0, 0, False }, + { RADAR_CONFIG_BOOL, "-visible", NULL, + Tk_Offset(TrackItemStruct, header.flags), VISIBLE_BIT, + RADAR_DRAW_FLAG|RADAR_REPICK_FLAG|RADAR_VIS_FLAG, False }, + { RADAR_CONFIG_UINT, "-visiblehistorysize", NULL, + Tk_Offset(TrackItemStruct, visible_history_size), 0, RADAR_DRAW_FLAG, False }, + + { RADAR_CONFIG_END, NULL, NULL, 0, 0, 0 } +}; + +static RadarAttrConfig wp_attrs[] = { + { RADAR_CONFIG_BOOL, "-composerotation", NULL, + Tk_Offset(TrackItemStruct, header.flags), COMPOSE_ROTATION_BIT, + RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_BOOL, "-composescale", NULL, + Tk_Offset(TrackItemStruct, header.flags), COMPOSE_SCALE_BIT, + RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_ITEM, "-connecteditem", NULL, + Tk_Offset(TrackItemStruct, header.connected_item), 0, + RADAR_COORDS_FLAG|RADAR_ITEM_FLAG, False }, + { RADAR_CONFIG_COLOR, "-connectioncolor", NULL, + Tk_Offset(TrackItemStruct, connection_color), 0, RADAR_DRAW_FLAG, False }, + { RADAR_CONFIG_BOOL, "-connectionsensitive", NULL, + Tk_Offset(TrackItemStruct, header.part_sensitive), PART_NUMBER_TO_BIT(RADAR_CONNECTION), + RADAR_REPICK_FLAG, False }, + { RADAR_CONFIG_LINE_STYLE, "-connectionstyle", NULL, + Tk_Offset(TrackItemStruct, connection_style), 0, RADAR_DRAW_FLAG, False }, + { RADAR_CONFIG_DIM, "-connectionwidth", NULL, + Tk_Offset(TrackItemStruct, connection_width), 0, RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_BOOL, "-filledmarker", NULL, + Tk_Offset(TrackItemStruct, flags), MARKER_FILLED_BIT, RADAR_DRAW_FLAG, False }, + { RADAR_CONFIG_ANCHOR, "-labelanchor", NULL, + Tk_Offset(TrackItemStruct, label_anchor), 0, RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_ANGLE, "-labelangle", NULL, + Tk_Offset(TrackItemStruct, label_angle), 0, + RADAR_COORDS_FLAG|RADAR_POLAR_FLAG, False }, + { RADAR_CONFIG_DIM, "-labeldistance", NULL, + Tk_Offset(TrackItemStruct, label_distance), 0, + RADAR_COORDS_FLAG|RADAR_POLAR_FLAG, False }, + { RADAR_CONFIG_DIM, "-labeldx", NULL, + Tk_Offset(TrackItemStruct, label_dx), 0, + RADAR_COORDS_FLAG|RADAR_CARTESIAN_FLAG, False }, + { RADAR_CONFIG_DIM, "-labeldy", NULL, + Tk_Offset(TrackItemStruct, label_dy), 0, + RADAR_COORDS_FLAG|RADAR_CARTESIAN_FLAG, False }, + { RADAR_CONFIG_LABEL_FORMAT, "-labelformat", NULL, + Tk_Offset(TrackItemStruct, field_set.label_format), 0, + RADAR_COORDS_FLAG|RADAR_CLFC_FLAG, False }, + { RADAR_CONFIG_LEADER_ANCHORS, "-leaderanchors", NULL, + Tk_Offset(TrackItemStruct, leader_anchors), 0, RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_COLOR, "-leadercolor", NULL, + Tk_Offset(TrackItemStruct, leader_color), 0, RADAR_DRAW_FLAG, False }, + { RADAR_CONFIG_LINE_END, "-leaderfirstend", NULL, + Tk_Offset(TrackItemStruct, leader_first_end), 0, RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_LINE_END, "-leaderlastend", NULL, + Tk_Offset(TrackItemStruct, leader_last_end), 0, RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_BOOL, "-leadersensitive", NULL, + Tk_Offset(TrackItemStruct, header.part_sensitive), PART_NUMBER_TO_BIT(RADAR_LEADER), + RADAR_REPICK_FLAG, False }, + { RADAR_CONFIG_LINE_SHAPE, "-leadershape", NULL, + Tk_Offset(TrackItemStruct, leader_shape), 0, RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_LINE_STYLE, "-leaderstyle", NULL, + Tk_Offset(TrackItemStruct, leader_style), 0, RADAR_DRAW_FLAG, False }, + { RADAR_CONFIG_DIM, "-leaderwidth", NULL, + Tk_Offset(TrackItemStruct, leader_width), 0, RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_COLOR, "-markercolor", NULL, + Tk_Offset(TrackItemStruct, marker_color), 0, RADAR_DRAW_FLAG, False }, + { RADAR_CONFIG_PATTERN, "-markerfillpattern", NULL, + Tk_Offset(TrackItemStruct, marker_fill_pattern), 0, RADAR_DRAW_FLAG, False }, + { RADAR_CONFIG_DIM, "-markersize", NULL, + Tk_Offset(TrackItemStruct, marker_size), 0, RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_LINE_STYLE, "-markerstyle", NULL, + Tk_Offset(TrackItemStruct, marker_style), 0, RADAR_DRAW_FLAG, False }, + { RADAR_CONFIG_UINT, "-numfields", NULL, + Tk_Offset(TrackItemStruct, field_set.num_fields), 0, 0, True }, + { RADAR_CONFIG_POINT, "-position", NULL, Tk_Offset(TrackItemStruct, pos), 0, + RADAR_COORDS_FLAG, False}, + { RADAR_CONFIG_PRI, "-priority", NULL, + Tk_Offset(TrackItemStruct, header.priority), 0, + RADAR_DRAW_FLAG|RADAR_REPICK_FLAG, False }, + { RADAR_CONFIG_BOOL, "-sensitive", NULL, + Tk_Offset(TrackItemStruct, header.flags), SENSITIVE_BIT, RADAR_REPICK_FLAG, False }, + { RADAR_CONFIG_PATTERN, "-symbol", NULL, + Tk_Offset(TrackItemStruct, symbol), 0, RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_COLOR, "-symbolcolor", NULL, + Tk_Offset(TrackItemStruct, symbol_color), 0, RADAR_DRAW_FLAG, False }, + { RADAR_CONFIG_BOOL, "-symbolsensitive", NULL, + Tk_Offset(TrackItemStruct, header.part_sensitive), PART_NUMBER_TO_BIT(RADAR_CURRENT_POSITION), + RADAR_REPICK_FLAG, False }, + { RADAR_CONFIG_TAGS, "-tags", NULL, + Tk_Offset(TrackItemStruct, header.tags), 0, 0, False }, + { RADAR_CONFIG_BOOL, "-visible", NULL, + Tk_Offset(TrackItemStruct, header.flags), VISIBLE_BIT, + RADAR_DRAW_FLAG|RADAR_REPICK_FLAG|RADAR_VIS_FLAG, False }, + + { RADAR_CONFIG_END, NULL, NULL, 0, 0, 0 } +}; + + +/* + ********************************************************************************** + * + * PointPolarToCartesian -- + * Convert a point in polar coordinates in + * a reference system described by heading + * dx_ref, dy_ref to a point in cartesian + * coordinates. + * + ********************************************************************************** + */ +static RadarReal +ProjectionToAngle(RadarDim dx, + RadarDim dy) +{ + if (dx == 0) { + if (dy < 0) { + return -M_PI_2; + } + else if (dy > 0) { + return M_PI_2; + } + else { + return 0.0; + } + } + else if (dx < 0) { + return atan((double) dy / (double) dx) - M_PI; + } + else { + return atan((double) dy / (double) dx); + } + return 0.0; +} + +static void +PointPolarToCartesian(RadarReal heading, + int rho, + int theta, + int *delta_x, + int *delta_y) +{ + double to_angle; + + /* Compute angle in trigonometric system */ + to_angle = DegreesToRadian(theta) + heading - M_PI_2; + /* to_angle = heading - DegreesToRadian(theta);*/ + /* Compute cartesian coordinates */ + *delta_x = (int) (rho * cos(to_angle)); + *delta_y = (int) (rho * sin(to_angle)); +} + + +/* + ********************************************************************************** + * + * Init -- + * + ********************************************************************************** + */ +static int +Init(Item item, + int *argc, + Arg **args) +{ + TrackItem track = (TrackItem) item; + FieldSet field_set = &track->field_set; + WidgetInfo *wi = item->wi; + + /*printf("size of a track = %d\n", sizeof(TrackItemStruct));*/ + + SET(item->flags, VISIBLE_BIT); + SET(item->flags, SENSITIVE_BIT); + SET(item->flags, COMPOSE_ROTATION_BIT); + SET(item->flags, COMPOSE_SCALE_BIT); + SET(item->part_sensitive, PART_NUMBER_TO_BIT(RADAR_CURRENT_POSITION)); + SET(item->part_sensitive, PART_NUMBER_TO_BIT(RADAR_LEADER)); + SET(item->part_sensitive, PART_NUMBER_TO_BIT(RADAR_CONNECTION)); + SET(item->part_sensitive, PART_NUMBER_TO_BIT(RADAR_SPEED_VECTOR)); + track->symbol_color = RadarGetColorByValue(wi->win, wi->fore_color); + track->symbol = Tk_GetBitmap(wi->interp, wi->win, Tk_GetUid("AtcSymbol15")); + track->label_anchor = RadarAnchorCenter; + track->label_angle = DEFAULT_LABEL_ANGLE; + track->label_distance = DEFAULT_LABEL_DISTANCE; + SET(track->flags, POLAR_BIT); + CLEAR(track->flags, FROZEN_LABEL_BIT); + track->leader_anchors = NULL; + track->leader_color = RadarGetColorByValue(wi->win, wi->fore_color); + track->leader_style = LINE_SIMPLE; + track->leader_shape = LINE_STRAIGHT; + track->leader_width = DEFAULT_LINE_WIDTH; + track->connection_color = RadarGetColorByValue(wi->win, wi->fore_color); + track->connection_style = LINE_SIMPLE; + track->connection_width = DEFAULT_LINE_WIDTH; + track->marker_color = RadarGetColorByValue(wi->win, wi->fore_color); + track->marker_style = LINE_SIMPLE; + track->marker_fill_pattern = RadarUnspecifiedPattern; + track->speed_vector_color = RadarGetColorByValue(wi->win, wi->fore_color); + CLEAR(track->flags, MARKER_FILLED_BIT); + SET(track->flags, FILLED_HISTORY_BIT); + CLEAR(track->flags, DOT_MIXED_HISTORY_BIT); + CLEAR(track->flags, CIRCLE_HISTORY_BIT); + + if (item->class == RadarTrack) { + item->priority = DEFAULT_TRACK_PRIORITY; + track->visible_history_size = DEFAULT_VISIBLE_HISTORY_SIZE; + track->marker_size = DEFAULT_MARKER_SIZE; + track->speed_vector.x = 0; + track->speed_vector.y = 0; + } + else { + item->priority = DEFAULT_WAY_POINT_PRIORITY; + track->visible_history_size = 0; + track->marker_size = 0; + track->speed_vector.x = 0.0; + track->speed_vector.y = 10.0; + } + field_set->wi = wi; + field_set->label_format = NULL; + /* + * Then try to see if some fields are needed. + */ + if ((*argc > 0) && (LangString((*args)[0])[0] != '-') && + (Tcl_GetInt(wi->interp, (args[0])[0], &field_set->num_fields) != RADAR_ERROR)) { + *args += 1; + *argc -= 1; + ITEM_P.InitFields(field_set); + } + else { + Tcl_AppendResult(wi->interp, " number of fields expected", NULL); + return RADAR_ERROR; + } + + track->pos.x = 0; + track->pos.y = 0; + track->field_set.label_pos.x = 0; + track->field_set.label_pos.y = 0; + track->leader_first_end = NULL; + track->leader_last_end = NULL; + + track->history = NULL; + track->dev.x = 0; + track->dev.y = 0; + track->speed_vector_dev.x = 0; + track->speed_vector_dev.y = 0; + track->marker_size_dev = 0; + track->leader_points = NULL; + + return RADAR_OK; +} + + +/* + ********************************************************************************** + * + * Clone -- + * + ********************************************************************************** + */ +static void +Clone(Item item) +{ + TrackItem track = (TrackItem) item; + WidgetInfo *wi = item->wi; + + if (track->history) { + track->history = RadarListDuplicate(track->history); + } + track->dev.x = 0; + track->dev.y = 0; + track->speed_vector_dev.x = 0; + track->speed_vector_dev.y = 0; + track->marker_size_dev = 0; + if (track->leader_points) { + track->leader_points = RadarListDuplicate(track->leader_points); + } + if (track->leader_first_end) { + LineEndDuplicate(track->leader_first_end); + } + if (track->leader_last_end) { + LineEndDuplicate(track->leader_last_end); + } + + ITEM_P.CloneFields(&track->field_set); + + /* + * We get all shared resources, colors bitmaps. + */ + track->symbol_color = RadarGetColorByValue(wi->win, track->symbol_color); + track->leader_color = RadarGetColorByValue(wi->win, track->leader_color); + track->connection_color = RadarGetColorByValue(wi->win, track->connection_color); + track->marker_color = RadarGetColorByValue(wi->win, track->marker_color); + track->speed_vector_color = RadarGetColorByValue(wi->win, track->speed_vector_color); + if (track->symbol != RadarUnspecifiedPattern) { + track->symbol = Tk_GetBitmap(wi->interp, wi->win, + Tk_NameOfBitmap(wi->dpy, track->symbol)); + } + if (track->marker_fill_pattern != RadarUnspecifiedPattern) { + track->marker_fill_pattern = Tk_GetBitmap(wi->interp, wi->win, + Tk_NameOfBitmap(wi->dpy, track->marker_fill_pattern)); + } +} + + +/* + ********************************************************************************** + * + * Destroy -- + * + ********************************************************************************** + */ +static void +Destroy(Item item) +{ + TrackItem track = (TrackItem) item; + WidgetInfo *wi = item->wi; + + if (track->leader_points) { + RadarListFree(track->leader_points); + } + if (track->leader_first_end) { + LineEndDelete(track->leader_first_end); + } + if (track->leader_last_end) { + LineEndDelete(track->leader_last_end); + } + + if (track->history) { + RadarListFree(track->history); + } + + /* + * Release shared resources. + */ + RadarFreeColor(track->symbol_color); + RadarFreeColor(track->leader_color); + RadarFreeColor(track->connection_color); + RadarFreeColor(track->marker_color); + RadarFreeColor(track->speed_vector_color); + if (track->symbol != RadarUnspecifiedPattern) { + Tk_FreeBitmap(wi->dpy, track->symbol); + } + if (track->marker_fill_pattern != RadarUnspecifiedPattern) { + Tk_FreeBitmap(wi->dpy, track->marker_fill_pattern); + } + + ITEM_P.FreeFields(&track->field_set); +} + + +/* + ********************************************************************************** + * + * Configure -- + * + ********************************************************************************** + */ +static void +AddToHistory(TrackItem track, + RadarPoint old_pos) +{ + WidgetInfo *wi = ((Item) track)->wi; + + /*printf("Track moved, manage history: %d\n", wi->track_manage_history);*/ + if (track->history) { + if (wi->track_manage_history) { + HistoryStruct hist; + + hist.world = old_pos; + hist.dev = track->dev; + hist.visible = True; + RadarListAdd(track->history, &hist, RadarListHead); + RadarListTruncate(track->history, wi->track_managed_history_size); + } + } + else { + /* We do not shift the first time we move as the preceding position + * is not valid. */ + /*printf("creating history\n");*/ + track->history = RadarListNew(wi->track_managed_history_size+1, + sizeof(HistoryStruct)); + } +} + +static int +Configure(Item item, + int argc, + RadarAttrList argv, + int *flags) +{ + TrackItem track = (TrackItem) item; + WidgetInfo *wi = item->wi; + Item old_connected; + RadarPoint old_pos; + + old_pos = track->pos; + old_connected = item->connected_item; + + if (ITEM_P.ConfigureAttributes((char *) item, -1, argc, argv, flags) == RADAR_ERROR) { + return RADAR_ERROR; + } + + /* + * Trunc the visible history to the managed size. + */ + track->visible_history_size = MIN(track->visible_history_size, + wi->track_managed_history_size); + /* + * Adapt to the new label locating system. + */ + if (ISSET(*flags, RADAR_POLAR_FLAG)) { + SET(track->flags, POLAR_BIT); + } + else if (ISSET(*flags, RADAR_CARTESIAN_FLAG)) { + CLEAR(track->flags, POLAR_BIT); + } + + if (ISSET(*flags, RADAR_ITEM_FLAG)) { + /* + * If the new connected item is not appropriate back up + * to the old one. + */ + if ((item->connected_item == RADAR_NO_ITEM) || + (((item->connected_item->class == RadarTrack) || + (item->connected_item->class == RadarWayPoint)) && + (item->parent == item->connected_item->parent))) { + ITEM.UpdateItemDependency(item, old_connected); + } + else { + item->connected_item = old_connected; + } + } + +#ifdef OM + if (ISSET(*flags, RADAR_VIS_FLAG)) { + /* Record the change to trigger the overlap manager latter */ + if ((item->class == RadarTrack) && ISSET(item->flags, VISIBLE_BIT)) { + ((GroupItem) item->parent)->call_om = True; + } + } +#endif + + /* If the current position has changed, shift the past pos. */ + if (ISSET(*flags, RADAR_MOVED_FLAG)) { + if (item->class == RadarTrack) { + AddToHistory(track, old_pos); + } + } + + return RADAR_OK; +} + + +/* + ********************************************************************************** + * + * Query -- + * + ********************************************************************************** + */ +static int +Query(Item item, + int argc, + RadarAttrList argv) +{ + if (ITEM_P.QueryAttribute((char *) item, -1, argv[0]) == RADAR_ERROR) { + return RADAR_ERROR; + } + + return RADAR_OK; +} + + +/* + ********************************************************************************** + * + * ComputeCoordinates -- + * + ********************************************************************************** + */ + +static void +ComputeCoordinates(Item item, + RadarBool force) +{ + WidgetInfo *wi = item->wi; + TrackItem track = (TrackItem) item; + FieldSet field_set = &track->field_set; + Item c_item; + History hist; + RadarPoint old_label_pos, old_pos, p, xp; + RadarDim old_label_width, old_label_height; + RadarReal rotation; + RadarBBox bbox; + RadarPoint *points; + int num_acc_pos, i; + int num_points, alignment; + int w2=0, h2=0, w=0, h=0; + + ResetBBox(&item->item_bounding_box); + old_label_pos = field_set->label_pos; + old_label_width = field_set->label_width; + old_label_height = field_set->label_height; + + /* + * Suppress history if history management was turned off. + */ + if ((item->class == RadarTrack) && !wi->track_manage_history) { + RadarListEmpty(track->history); + } + + old_pos = track->dev; + + RadarTransformPoint(wi->current_transfo, &track->pos, &track->dev); + /*printf("track pos %g %g --> %g %g\n", track->pos.x, track->pos.y, track->dev.x, track->dev.y);*/ + if (track->symbol != RadarUnspecifiedPattern) { + Tk_SizeOfBitmap(wi->dpy, track->symbol, &w, &h); + /*printf("taille symbole %d %d\n", w, h);*/ + w2 = (w+1)/2; + h2 = (h+1)/2; + bbox.orig.x = track->dev.x - w2; + bbox.orig.y = track->dev.y - h2; + bbox.corner.x = bbox.orig.x + w; + bbox.corner.y = bbox.orig.y + h; + + AddBBoxToBBox(&item->item_bounding_box, &bbox); + } + + /* Here we approximate the past position sizes to the size + of the current position. They are actually smaller but who + care :-). In fact it is even worse as we use the overall + information from the symbol font. + */ + if ((item->class == RadarTrack) && track->history) { + ResetBBox(&bbox); + num_acc_pos = RadarListSize(track->history); + hist = RadarListArray(track->history); + for (i = 0; i < num_acc_pos; i++) { + RadarTransformPoint(wi->current_transfo, &hist[i].world, &hist[i].dev); + if ((i < track->visible_history_size) && (hist[i].visible)) { + bbox.orig.x = hist[i].dev.x - w2; + bbox.orig.y = hist[i].dev.y - h2; + bbox.corner.x = bbox.orig.x + w; + bbox.corner.y = bbox.orig.y + h; + AddBBoxToBBox(&item->item_bounding_box, &bbox); + } + } + } + + /* + * Compute the speed vector end. + */ + if (item->class == RadarTrack) { + p.x = track->pos.x + track->speed_vector.x * wi->speed_vector_length; + p.y = track->pos.y + track->speed_vector.y * wi->speed_vector_length; + RadarTransformPoint(wi->current_transfo, &p, &track->speed_vector_dev); + AddPointToBBox(&item->item_bounding_box, track->speed_vector_dev.x, + track->speed_vector_dev.y); + } + + /* + * Take care of the connection between items. + */ + c_item = item->connected_item; + if ((c_item != RADAR_NO_ITEM) && (track->connection_width > 0)) { + ResetBBox(&bbox); + w2 = track->connection_width/2; + AddPointToBBox(&item->item_bounding_box, track->dev.x-w2, track->dev.y-w2); + AddPointToBBox(&item->item_bounding_box, ((TrackItem)c_item)->dev.x+w2, + ((TrackItem)c_item)->dev.y+w2); + } + + /* + * Compute the size of the circular marker. + */ + p.x = track->pos.x + track->marker_size; + p.y = track->pos.y; + RadarTransformPoint(wi->current_transfo, &p, &xp); + xp.x = xp.x - track->dev.x; + xp.y = xp.y - track->dev.y; + track->marker_size_dev = sqrt(xp.x*xp.x + xp.y*xp.y); + if (track->marker_size_dev > PRECISION_LIMIT) { + AddPointToBBox(&item->item_bounding_box, + track->dev.x - (RadarPos) track->marker_size_dev, + track->dev.y - (RadarPos) track->marker_size_dev); + AddPointToBBox(&item->item_bounding_box, + track->dev.x + (RadarPos) track->marker_size_dev, + track->dev.y + (RadarPos) track->marker_size_dev); + } + + /* Compute the new label bounding box. */ + if (field_set->label_format) { + RadarDim bb_width, bb_height, dist; + RadarPoint leader_end; + + ITEM_P.GetLabelBBox(field_set, &bb_width, &bb_height); + /* + * Compute the label position. + */ + if (ISCLEAR(track->flags, FROZEN_LABEL_BIT)) { + if (ISSET(track->flags, POLAR_BIT)) { + /* + * Adjust the min dist spec given in label_distance by + * the size of the label. + */ + if ((track->label_anchor == RadarAnchorN) || + (track->label_anchor == RadarAnchorCenter) || + (track->label_anchor == RadarAnchorS)) { + dist = sqrt(bb_width*bb_width/4+bb_height*bb_height/4); + } + else { + dist = sqrt(bb_width*bb_width+bb_height*bb_height); + } + dist += track->label_distance; + /* + * Compute heading after applying the transform. + */ + RadarTransfoDecompose(wi->current_transfo, NULL, NULL, &rotation, NULL); + /*printf("rotation=%g, heading=%g, angle=%d\n", rotation, + ProjectionToAngle(track->speed_vector.x, track->speed_vector.y), + track->label_angle);*/ + rotation = ProjectionToAngle(track->speed_vector.x, track->speed_vector.y)-rotation; + PointPolarToCartesian(rotation, dist, track->label_angle, + &track->label_dx, &track->label_dy); + } + field_set->label_pos.x = track->dev.x + track->label_dx; + field_set->label_pos.y = track->dev.y - track->label_dy; + Anchor2Origin(&field_set->label_pos, bb_width, bb_height, + track->label_anchor, &field_set->label_pos); + } + + AddPointToBBox(&item->item_bounding_box, field_set->label_pos.x, + field_set->label_pos.y); + AddPointToBBox(&item->item_bounding_box, + field_set->label_pos.x + (RadarPos) bb_width, + field_set->label_pos.y + (RadarPos) bb_height); + + /* + * Process the leader. + */ + if (track->leader_width > 0) { + int left_x, left_y, right_x, right_y; + RadarPoint end_points[LINE_END_POINTS]; + + /* + * Compute the actual leader end in the label. + */ + if (track->leader_anchors) { + left_x = track->leader_anchors->left_x; + right_x = track->leader_anchors->right_x; + left_y = track->leader_anchors->left_y; + right_y = track->leader_anchors->right_y; + } + else { + left_x = right_x = left_y = right_y = 50; + } + if (track->label_angle >= 270 || track->label_angle < 90) { + if (track->leader_anchors && (left_y < 0)) { + ITEM_P.GetFieldBBox(field_set, left_x, &bbox); + leader_end.x = bbox.orig.x; + leader_end.y = bbox.corner.y; + } + else { + leader_end.x = field_set->label_pos.x + left_x*bb_width/100; + leader_end.y = field_set->label_pos.y + left_y*bb_height/100; + } + alignment = AA_LEFT; + } + else { + if (track->leader_anchors && (right_y < 0)) { + ITEM_P.GetFieldBBox(field_set, right_x, &bbox); + leader_end.x = bbox.corner.x; + leader_end.y = bbox.corner.y; + } + else { + leader_end.x = field_set->label_pos.x + right_x*bb_width/100; + leader_end.y = field_set->label_pos.y + right_y*bb_height/100; + } + alignment = AA_RIGHT; + } + + ITEM.SetFieldsAutoAlign(item, alignment); + + /* Clip the leader on the label's fields */ + ITEM_P.LeaderToLabel(field_set, &track->dev, &leader_end); + + /* Setup leader shape points */ + if (!track->leader_points) { + track->leader_points = RadarListNew(LINE_SHAPE_POINTS, sizeof(RadarPoint)); + } + GetLineShape(&track->dev, &leader_end, track->leader_width, + track->leader_shape, &bbox, track->leader_points); + AddBBoxToBBox(&item->item_bounding_box, &bbox); + points = (RadarPoint *) RadarListArray(track->leader_points); + num_points = RadarListSize(track->leader_points); + + /* Setup leader ends */ + if (track->leader_first_end != NULL) { + GetLineEnd(&points[0], &points[1], track->leader_width, + CapRound, track->leader_first_end, end_points); + AddPointsToBBox(&item->item_bounding_box, end_points, LINE_END_POINTS); + } + if (track->leader_last_end != NULL) { + GetLineEnd(&points[num_points-1], &points[num_points-2], track->leader_width, + CapRound, track->leader_last_end, end_points); + AddPointsToBBox(&item->item_bounding_box, end_points, LINE_END_POINTS); + } + } + } + + /* Update connected items. */ + if ((old_label_pos.x != field_set->label_pos.x) || + (old_label_pos.y != field_set->label_pos.y) || + (old_label_width != field_set->label_width) || + (old_label_height != field_set->label_height) || + (old_pos.x != track->dev.x) || + (old_pos.y != track->dev.y)) { + /* Update connected items */ + SET(item->flags, UPDATE_DEPENDENT_BIT); + +#ifdef OM + /* Record the move to trigger the overlap manager latter */ + if (item->class == RadarTrack) { + ((GroupItem) item->parent)->call_om = True; + } +#endif + } +} + + +/* + ********************************************************************************** + * + * ToArea -- + * Tell if the object is entirely outside (-1), + * entirely inside (1) or in between (0). + * + ********************************************************************************** + */ +static int +ToArea(Item item, + RadarBBox *area, + Tk_Uid tag_uid, + int enclosed, + RadarBool report) +{ + WidgetInfo *wi = item->wi; + TrackItem track = (TrackItem) item; + int inside; + int width, height; + RadarDim lwidth, lheight; + RadarBBox bbox; + + /* + * Try the current position. + */ + ResetBBox(&bbox); + if (track->symbol != RadarUnspecifiedPattern) { + Tk_SizeOfBitmap(wi->dpy, track->symbol, &width, &height); + bbox.orig.x = track->dev.x-(width+1)/2; + bbox.orig.y = track->dev.y-(height+1)/2; + bbox.corner.x = bbox.orig.x + width; + bbox.corner.y = bbox.orig.y + height; + } + inside = BBoxInBBox(&bbox, area); + if (inside == 0) { + printf("track pos\n"); + return 0; + } + + /* + * Try the fields. + */ + ITEM_P.GetLabelBBox(&track->field_set, &lwidth, &lheight); + if ((lwidth > 0.0) && (lheight > 0.0)) { + if (ITEM_P.FieldsToArea(&track->field_set, area) != inside) { + return 0; + } + } + + /* + * Try the leader. + */ + if (track->field_set.label_format && (track->leader_width > 0)) { + RadarPoint end_points[LINE_END_POINTS]; + RadarPoint *points; + int num_points; + + points = (RadarPoint *) RadarListArray(track->leader_points); + num_points = RadarListSize(track->leader_points); + width = track->leader_width > 1 ? track->leader_width : 0; + if (PolylineInBBox(points, num_points, width, + CapRound, JoinRound, area) != inside) { + printf("track leader\n"); + return 0; + } + if (track->leader_first_end != NULL) { + GetLineEnd(&points[0], &points[1], track->leader_width, + CapRound, track->leader_first_end, end_points); + if (PolygonInBBox(end_points, LINE_END_POINTS, area) != inside) { + printf("track leader\n"); + return 0; + } + } + if (track->leader_last_end != NULL) { + GetLineEnd(&points[num_points-1], &points[num_points-2], track->leader_width, + CapRound, track->leader_last_end, end_points); + if (PolygonInBBox(end_points, LINE_END_POINTS, area) != inside) { + printf("track leader\n"); + return 0; + } + } + } + + /* + * Try the speed vector. + */ + if (item->class == RadarTrack) { + if (LineInBBox(&track->dev, &track->speed_vector_dev, area) != inside) { + printf("track speed vector\n"); + return 0; + } + } + + /* + * Try the connection. + */ + if ((item->connected_item != RADAR_NO_ITEM) && (track->connection_width > 0)) { + RadarPoint pts[2]; + + pts[0] = track->dev; + pts[1] = ((TrackItem) item->connected_item)->dev; + width = track->connection_width > 1 ? track->connection_width : 0; + if (PolylineInBBox(pts, 2, width, CapRound, JoinRound, area) != inside) { + printf("track connection\n"); + return 0; + } + } + + return inside; +} + + +/* + ********************************************************************************** + * + * Draw -- + * + ********************************************************************************** + */ + +static void +Draw(Item item) +{ + WidgetInfo *wi = item->wi; + TrackItem track = (TrackItem) item; + Item c_item; + char tmp_str[] = "."; + XGCValues values; + History hist; + int h_side_size, side_size, width=0, height=0; + int i, nb_hist, num_acc_pos; + + + /* Draw the marker */ + if (track->marker_size_dev != 0) { + SetLineStyle(wi->dpy, wi->gc, track->marker_style); + values.foreground = RadarPixel(track->marker_color); + values.line_width = 0; + if (ISSET(track->flags, MARKER_FILLED_BIT)) { + if (track->marker_fill_pattern == RadarUnspecifiedPattern) { + /* Fill solid */ + values.fill_style = FillSolid; + XChangeGC(wi->dpy, wi->gc, GCFillStyle | GCLineWidth | GCForeground, &values); + } + else { + /* Fill stippled */ + values.fill_style = FillStippled; + values.stipple = track->marker_fill_pattern; + XChangeGC(wi->dpy, wi->gc, + GCFillStyle | GCStipple | GCLineWidth | GCForeground, &values); + } + XFillArc(wi->dpy, wi->draw_buffer, wi->gc, + track->dev.x - (RadarPos) track->marker_size_dev, + track->dev.y - (RadarPos) track->marker_size_dev, + track->marker_size_dev * 2, track->marker_size_dev * 2, + 0, 360 * 64); + } + else { + XChangeGC(wi->dpy, wi->gc, GCLineWidth | GCForeground, &values); + XDrawArc(wi->dpy, wi->draw_buffer, wi->gc, + track->dev.x - (RadarPos) track->marker_size_dev, + track->dev.y - (RadarPos) track->marker_size_dev, + track->marker_size_dev * 2, track->marker_size_dev * 2, + 0, 360 * 64); + } + } + + /* + * Draw the connection. + */ + c_item = item->connected_item; + if ((c_item != RADAR_NO_ITEM) && (track->connection_width > 0)) { + RadarPoint pts[2]; + + pts[0] = track->dev; + pts[1] = ((TrackItem) item->connected_item)->dev; + DrawLineShape(wi->dpy, wi->draw_buffer, wi->gc, pts, 2, + track->connection_style, track->connection_color, + track->connection_width, LINE_STRAIGHT); + } + + /* + * Draw the speed vector. + */ + if (item->class == RadarTrack) { + values.foreground = RadarPixel(track->speed_vector_color); + values.line_width = 0; + values.line_style = LineSolid; + values.fill_style = FillSolid; + XChangeGC(wi->dpy, wi->gc, + GCForeground | GCLineWidth | GCLineStyle | GCFillStyle, &values); + XDrawLine(wi->dpy, wi->draw_buffer, wi->gc, track->dev.x, track->dev.y, + track->speed_vector_dev.x, track->speed_vector_dev.y); + } + + /* + * Draw the leader. + */ + if (track->field_set.label_format && track->leader_width > 0) { + RadarPoint end_points[LINE_END_POINTS]; + XPoint xpoints[LINE_END_POINTS]; + RadarPoint *points; + int num_points; + + points = (RadarPoint *) RadarListArray(track->leader_points); + num_points = RadarListSize(track->leader_points); + DrawLineShape(wi->dpy, wi->draw_buffer, wi->gc, + points, num_points, + track->leader_style, track->leader_color, + track->leader_width, track->leader_shape); + if (track->leader_first_end != NULL) { + GetLineEnd(&points[0], &points[1], track->leader_width, + CapRound, track->leader_first_end, end_points); + for (i = 0; i < LINE_END_POINTS; i++) { + xpoints[i].x = end_points[i].x; + xpoints[i].y = end_points[i].y; + } + XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, xpoints, LINE_END_POINTS, + Nonconvex, CoordModeOrigin); + } + if (track->leader_last_end != NULL) { + GetLineEnd(&points[num_points-1], &points[num_points-2], track->leader_width, + CapRound, track->leader_last_end, end_points); + for (i = 0; i < LINE_END_POINTS; i++) { + xpoints[i].x = end_points[i].x; + xpoints[i].y = end_points[i].y; + } + XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, xpoints, LINE_END_POINTS, + Nonconvex, CoordModeOrigin); + } + } + + tmp_str[0] = track->symbol; + values.foreground = RadarPixel(track->symbol_color); + values.fill_style = FillSolid; + XChangeGC(wi->dpy, wi->gc, GCForeground|GCFillStyle, &values); + if (track->symbol != RadarUnspecifiedPattern) { + Tk_SizeOfBitmap(wi->dpy, track->symbol, &width, &height); + } + + /* + * Draw the history, current pos excepted. + */ + if ((item->class == RadarTrack) && track->history) { + if (ISCLEAR(track->flags, FILLED_HISTORY_BIT)) { + values.line_width = 0; + values.line_style = LineSolid; + XChangeGC(wi->dpy, wi->gc, GCLineWidth | GCLineStyle, &values); + } + num_acc_pos = RadarListSize(track->history); + hist = RadarListArray(track->history); + side_size = MAX(width, height); + for (i = 0, nb_hist = 0; + i < MIN(track->visible_history_size, num_acc_pos); i++) { + side_size--; + side_size = MAX(1, side_size); + h_side_size = (side_size+1)/2; + if (hist[i].visible) { + if (ISSET(track->flags, DOT_MIXED_HISTORY_BIT) && !(nb_hist++ % 2)) { + XDrawPoint(wi->dpy, wi->draw_buffer, wi->gc, hist[i].dev.x, hist[i].dev.y); + } + else { + if (ISSET(track->flags, CIRCLE_HISTORY_BIT)) { + if (ISSET(track->flags, FILLED_HISTORY_BIT)) { + XFillArc(wi->dpy, wi->draw_buffer, wi->gc, + hist[i].dev.x - h_side_size, hist[i].dev.y - h_side_size, + side_size, side_size, 0, 360*64); + } + else { + XDrawArc(wi->dpy, wi->draw_buffer, wi->gc, + hist[i].dev.x - h_side_size, hist[i].dev.y - h_side_size, + side_size - 1, side_size - 1, 0, 360*64); + } + } + else { + if (ISSET(track->flags, FILLED_HISTORY_BIT)) { + XFillRectangle(wi->dpy, wi->draw_buffer, wi->gc, + hist[i].dev.x - h_side_size, hist[i].dev.y - h_side_size, + side_size, side_size); + } + else { + XDrawRectangle(wi->dpy, wi->draw_buffer, wi->gc, + hist[i].dev.x - h_side_size, hist[i].dev.y - h_side_size, + side_size - 1, side_size - 1); + } + } + } + } + } + } + + /* + * Draw the current position using a pattern for Tk. + */ + if (track->symbol != RadarUnspecifiedPattern) { + int x = track->dev.x - (width+1)/2; + int y = track->dev.y - (height+1)/2; + values.fill_style = FillStippled; + values.stipple = track->symbol; + values.ts_x_origin = x; + values.ts_y_origin = y; + XChangeGC(wi->dpy, wi->gc, + GCFillStyle|GCStipple|GCTileStipXOrigin|GCTileStipYOrigin, &values); + XFillRectangle(wi->dpy, wi->draw_buffer, wi->gc, x, y, width, height); + } + + /* + * Draw the label. + */ + ITEM_P.DrawFields(&track->field_set); +} + + +/* + ********************************************************************************** + * + * IsSensitive -- + * + ********************************************************************************** + */ +static RadarBool +IsSensitive(Item item, + int item_part) +{ + if (ISCLEAR(item->flags, SENSITIVE_BIT) || + !item->parent->class->IsSensitive(item->parent, RADAR_NO_PART)) { + return False; + } + + if (item_part < RADAR_NO_PART) { + return ISSET(item->part_sensitive, PART_NUMBER_TO_BIT(item_part)); + } + else if (item_part >= 0) { + return ITEM_P.IsFieldSensitive(&((TrackItem) item)->field_set, item_part); + } + return True; +} + + +/* + ********************************************************************************** + * + * Pick -- + * + ********************************************************************************** + */ +static double +Pick(Item item, + RadarPoint *p, + Item start_item, + int aperture, + Item *a_item, + int *part) +{ + WidgetInfo *wi= item->wi; + TrackItem track = (TrackItem) item; + Item c_item; + RadarBBox bbox; + double dist=0, new_dist; + RadarPoint *points; + int num_points, i; + int width=0, height=0; + double width_2; + int best_part; + + /* + * Try one of the fields. + */ + dist = ITEM_P.FieldsPick(&track->field_set, p, &best_part); + if (dist <= 0.0) { + goto report0; + } + + /* + * Try the current position symbol. + */ + ResetBBox(&bbox); + if (track->symbol != RadarUnspecifiedPattern) { + Tk_SizeOfBitmap(wi->dpy, track->symbol, &width, &height); + bbox.orig.x = track->dev.x-(width+1)/2; + bbox.orig.y = track->dev.y-(height+1)/2; + bbox.corner.x = bbox.orig.x + width; + bbox.corner.y = bbox.orig.y + height; + } + + new_dist = RectangleToPointDist(&bbox, p); + if (new_dist < dist) { + best_part = RADAR_CURRENT_POSITION; + dist = new_dist; + } + if (dist <= 0.0) { + goto report0; + } + + /* + * Try the leader. + */ + if (track->field_set.label_format && (track->leader_width > 0)) { + RadarPoint end_points[LINE_END_POINTS]; + + width_2 = (track->leader_width>1) ? ((double) track->leader_width)/2.0 : 0; + points = (RadarPoint *) RadarListArray(track->leader_points); + num_points = RadarListSize(track->leader_points)-1; + for (i = 0; i < num_points; i++) { + new_dist = LineToPointDist(&points[i], &points[i+1], p); + new_dist -= width_2; + if (new_dist < dist) { + best_part = RADAR_LEADER; + dist = new_dist; + } + if (dist <= 0.0) { + goto report0; + } + } + if (track->leader_first_end != NULL) { + GetLineEnd(&points[0], &points[1], track->leader_width, + CapRound, track->leader_first_end, end_points); + new_dist = PolygonToPointDist(end_points, LINE_END_POINTS, p); + if (new_dist < dist) { + best_part = RADAR_LEADER; + dist = new_dist; + } + if (dist <= 0.0) { + goto report0; + } + } + if (track->leader_last_end != NULL) { + GetLineEnd(&points[num_points-1], &points[num_points-2], track->leader_width, + CapRound, track->leader_last_end, end_points); + new_dist = PolygonToPointDist(end_points, LINE_END_POINTS, p); + if (new_dist < dist) { + best_part = RADAR_LEADER; + dist = new_dist; + } + if (dist <= 0.0) { + goto report0; + } + } + } + + /* + * Try the speed vector. + */ + if (item->class == RadarTrack) { + new_dist = LineToPointDist(&track->dev, &track->speed_vector_dev, p); + if (new_dist < dist) { + best_part = RADAR_SPEED_VECTOR; + dist = new_dist; + } + if (dist <= 0.0) { + goto report0; + } + } + + /* + * Try the connection. + */ + c_item = item->connected_item; + if ((c_item != RADAR_NO_ITEM) && (track->connection_width > 0)) { + RadarPoint pts[2]; + + pts[0] = track->dev; + pts[1] = ((TrackItem) item->connected_item)->dev; + new_dist = PolylineToPointDist(pts, 2, track->connection_width, + CapRound, JoinRound, p); + if (new_dist < dist) { + dist = new_dist; + best_part = RADAR_CONNECTION; + } + if (dist <= 0.0) { + report0: + dist = 0.0; + } + } + + /* printf("track %d reporting part %d, distance %lf\n", + item->id, best_part, dist); */ + *part = best_part; + return dist; +} + + +/* + ********************************************************************************** + * + * PostScript -- + * + ********************************************************************************** + */ +static void +PostScript(Item item, + PostScriptInfo ps_info) +{ +} + + +/* + ********************************************************************************** + * + * SendTrackToOm -- + * + ********************************************************************************** + */ +/* + * TODO: + * + * The tracks should be identified by their ids not their + * structure pointer. This would enable an easy interface + * between the overlap manager and the applications when + * dealing with tracks. + */ +void * +SendTrackToOm(void *ptr, + void *item, + int *x, + int *y, + int *sv_dx, + int *sv_dy, + int *label_x, + int *label_y, + int *label_width, + int *label_height, + int *rho, + int *theta, + int *visibility) +{ + WidgetInfo *wi = (WidgetInfo *) ptr; + Item current_item = (Item) item; + TrackItem track; + RadarBBox radar_bbox, bbox; + RadarBool to_be_sent; + + radar_bbox.orig.x = radar_bbox.orig.y = 0; + radar_bbox.corner.x = wi->width; + radar_bbox.corner.y = wi->height; + + if (current_item == RADAR_NO_ITEM) { + current_item = ((GroupItem) wi->top_group)->head; + } + else { + current_item = current_item->next; + } + + while (current_item != RADAR_NO_ITEM) { + to_be_sent = current_item->class == RadarTrack; + + /* We send invisibles items because the current algorithm + take care of the age of the tracks. + to_be_sent &= ISSET(current_item->flags, VISIBLE_BIT);*/ + + IntersectBBox(&radar_bbox, ¤t_item->item_bounding_box, &bbox); + to_be_sent &= !IsEmptyBBox(&bbox); + + if (to_be_sent) { + track = (TrackItem) current_item; + + *x = track->dev.x; + *y = wi->height - track->dev.y; + + /* + * We must send world values for speed vector deltas as device + * equivalents can be null. But then if the image is rotated this + * is nonsense. + */ + *sv_dx = track->speed_vector.x; + *sv_dy = track->speed_vector.y; + + *label_x = track->field_set.label_pos.x; + *label_y = wi->height - track->field_set.label_pos.y; + if (track->field_set.label_format) { + RadarDim bb_width, bb_height; + + ITEM_P.GetLabelBBox(&track->field_set, &bb_width, &bb_height); + *label_width = bb_width; + *label_height = bb_height; + } + else { + *label_width = 0; + *label_height = 0; + } + *rho = sqrt(track->label_dx*track->label_dx + track->label_dy*track->label_dy); + *theta = track->label_angle; + break; + } + + current_item = current_item->next; + } + + return (void *) current_item; +} + + +/* + ********************************************************************************** + * + * SetLabelAngleFromOm -- + * + ********************************************************************************** + */ +void +SetLabelAngleFromOm(void *ptr, /* No longer in use. */ + void *item, + int theta) +{ + TrackItem track = (TrackItem) item; + + theta %= 360; + + if ((theta >= 0) && (track->label_angle != theta)) { + track->label_angle = theta; + ITEM.Invalidate((Item) item, RADAR_COORDS_FLAG); + } +} + + +/* + ********************************************************************************** + * + * QueryLabelPosition -- OverlapMan query the widget about what would be the + * label position if label_angle is theta + * + ********************************************************************************** + */ +void +QueryLabelPosition(void *ptr, /* No longer in use. */ + void *item, + int theta, + int* x, + int* y, + int* w, + int* h) +{ + Item it = (Item) item; + WidgetInfo *wi = it->wi; + TrackItem track = (TrackItem) it; + + if (track->field_set.label_format) { + RadarDim bb_width, bb_height; + int delta_x, delta_y; + RadarReal heading; + + /* + * !! BUG !! This doesn't work if the current transform has some rotation. + */ + heading = ProjectionToAngle(track->speed_vector.x, track->speed_vector.y); + PointPolarToCartesian(heading, track->label_distance, theta, &delta_x, &delta_y); + ITEM_P.GetLabelBBox(&track->field_set, &bb_width, &bb_height); + /* + * !! BUG !! This assume a label placing relative to the center anchor. + * We must fix this by taking into account the label anchor. + */ + *x = track->dev.x + (RadarPos) (delta_x - bb_width/2); + *y = track->dev.y - (RadarPos) (delta_y + bb_height/2); + *y = wi->height - *y; + *w = bb_width; + *h = bb_height; + } + else { + *x = *y = *w = *h = 0; + } +} + + +/* + ********************************************************************************** + * + * SetHistoryVisibility -- PLC - not yet implemented + * + ********************************************************************************** + */ +void +SetHistoryVisibility(Item item, + int index, + RadarBool visible) +{ +} + + +/* + ********************************************************************************** + * + * TruncHistory -- PLC - not yet interfaced + * + ********************************************************************************** + */ +void +TruncHistory(Item item) +{ + TrackItem track = (TrackItem) item; + + if (track->history) { + int size = RadarListSize (track->history); + History hist_tbl = RadarListArray (track->history); + while (size--) { + hist_tbl[size].visible = False; + } + ITEM.Invalidate(item, RADAR_COORDS_FLAG); + } +} + + +/* + ********************************************************************************** + * + * GetFieldSet -- + * + ********************************************************************************** + */ +static FieldSet +GetFieldSet(Item item) +{ + return &((TrackItem) item)->field_set; +} + + +/* + ********************************************************************************** + * + * GetAnchor -- + * + ********************************************************************************** + */ +static void +GetAnchor(Item item, + RadarAnchor anchor, + RadarPoint *p) +{ + FieldSet field_set = &((TrackItem) item)->field_set; + RadarDim width, height; + + if (field_set->label_format) { + ITEM_P.GetLabelBBox(field_set, &width, &height); + Origin2Anchor(&field_set->label_pos, width, height, anchor, p); + } + else { + p->x = p->y = 0.0; + } +} + + +/* + ********************************************************************************** + * + * Coords -- + * Return or edit the item position. + * + ********************************************************************************** + */ +static int +Coords(Item item, + int index, + int cmd, + RadarPoint **pts, + int *num_pts) +{ + TrackItem track = (TrackItem) item; + + if ((cmd == COORDS_ADD) || (cmd == COORDS_ADD_LAST) || (cmd == COORDS_REMOVE)) { + Tcl_AppendResult(item->wi->interp, " ", + item->class->name, "s can't add or remove vertices", NULL); + return RADAR_ERROR; + } + else if ((cmd == COORDS_REPLACE) || (cmd == COORDS_REPLACE_ALL)) { + if (*num_pts == 0) { + Tcl_AppendResult(item->wi->interp, + " coords command need 1 point on ", + item->class->name, "s", NULL); + return RADAR_ERROR; + } + if (item->class == RadarTrack) { + AddToHistory(track, track->pos); + } + track->pos = (*pts)[0]; + ITEM.Invalidate(item, RADAR_COORDS_FLAG); + } + else if ((cmd == COORDS_READ) || (cmd == COORDS_READ_ALL)) { + *num_pts = 1; + *pts = &track->pos; + } + return RADAR_OK; +} + + +/* + ********************************************************************************** + * + * Exported functions struct -- + * + ********************************************************************************** + */ +static ItemClassStruct TRACK_ITEM_CLASS = { + sizeof(TrackItemStruct), + True, + True, + True, + "track", + track_attrs, + Init, + Clone, + Destroy, + Configure, + Query, + GetFieldSet, + GetAnchor, + NULL, + Coords, + ComputeCoordinates, + ToArea, + Draw, + IsSensitive, + Pick, + PostScript +}; + +static ItemClassStruct WAY_POINT_ITEM_CLASS = { + sizeof(TrackItemStruct), + True, + True, + True, + "waypoint", + wp_attrs, + Init, + Clone, + Destroy, + Configure, + Query, + GetFieldSet, + GetAnchor, + NULL, + Coords, + ComputeCoordinates, + ToArea, + Draw, + IsSensitive, + Pick, + PostScript +}; + +RadarItemClassId RadarTrack = (RadarItemClassId) &TRACK_ITEM_CLASS; +RadarItemClassId RadarWayPoint = (RadarItemClassId) &WAY_POINT_ITEM_CLASS; |