aboutsummaryrefslogtreecommitdiff
path: root/generic/Track.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/Track.c')
-rw-r--r--generic/Track.c1771
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, &current_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;