diff options
author | Ian McIntosh <ian_mcintosh@linuxadvocate.org> | 2005-10-11 18:28:45 +0000 |
---|---|---|
committer | Ian McIntosh <ian_mcintosh@linuxadvocate.org> | 2005-10-11 18:28:45 +0000 |
commit | 488a4cd652a42e09058fd4b589086677e49547de (patch) | |
tree | 688fff2bd4b570c48f4c89cd66a0c476c089bfaf | |
parent | 7ae9d377f0993dfc08a3503b4e91c0bfb45ea283 (diff) |
Added to test polygon point reduction algorithm and others.
Prepare for rectangle clipping.
Add Douglas-Peucker point simplification algorithm. Add point distance from
line function. Add in/out/partial rect overlap function.
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | data/layers.xml | 44 | ||||
-rw-r--r-- | data/roadster.glade | 460 | ||||
-rw-r--r-- | src/Makefile.am | 5 | ||||
-rw-r--r-- | src/gui.c | 13 | ||||
-rw-r--r-- | src/main.h | 2 | ||||
-rw-r--r-- | src/mainwindow.c | 5 | ||||
-rw-r--r-- | src/map.c | 2 | ||||
-rw-r--r-- | src/map_draw_gdk.c | 146 | ||||
-rw-r--r-- | src/map_hittest.c | 2 | ||||
-rw-r--r-- | src/map_math.c | 178 | ||||
-rw-r--r-- | src/map_math.h | 12 | ||||
-rw-r--r-- | src/test_poly.c | 209 | ||||
-rw-r--r-- | src/test_poly.h | 31 |
14 files changed, 932 insertions, 184 deletions
@@ -1,3 +1,10 @@ +2005-10-11 Ian McIntosh <ian_mcintosh@linuxadvocate.org> + + * src/test_poly.c: + * src/test_poly.h: Added to test polygon point reduction algorithm and others. + * src/map_draw_gdk.c: Prepare for rectangle clipping. + * src/map_math.c: Add Douglas-Peucker point simplification algorithm. Add point distance from line function. Add in/out/partial rect overlap function. + 2005-10-10 Ian McIntosh <ian_mcintosh@linuxadvocate.org> * data/layers.xml: diff --git a/data/layers.xml b/data/layers.xml index 9f43dfd..56825ad 100644 --- a/data/layers.xml +++ b/data/layers.xml @@ -39,8 +39,8 @@ </layer> <layer data-source="parks" draw-type="polygon-labels"> - <property zoom-level="6" name="font-size" value="10" /> - <property zoom-level="7" name="font-size" value="10" /> +<!-- <property zoom-level="6" name="font-size" value="10" /> --> + <property zoom-level="7" name="font-size" value="9" /> <property zoom-level="8" name="font-size" value="11" /> <property zoom-level="9" name="font-size" value="12" /> <property zoom-level="10" name="font-size" value="22" /> @@ -50,8 +50,8 @@ </layer> <layer data-source="lakes" draw-type="polygon-labels"> - <property zoom-level="5" name="font-size" value="9" /> - <property zoom-level="6" name="font-size" value="9" /> +<!-- <property zoom-level="5" name="font-size" value="9" /> --> + <property zoom-level="6" name="font-size" value="9" /> <property zoom-level="7" name="font-size" value="9" /> <property zoom-level="8" name="font-size" value="10" /> <property zoom-level="9" name="font-size" value="11" /> @@ -62,9 +62,9 @@ </layer> <layer data-source="misc-areas" draw-type="polygon-labels"> - <property zoom-level="6" name="font-size" value="10" /> - <property zoom-level="7" name="font-size" value="12" /> - <property zoom-level="8" name="font-size" value="13" /> +<!-- <property zoom-level="6" name="font-size" value="10" /> --> + <property zoom-level="7" name="font-size" value="10" /> + <property zoom-level="8" name="font-size" value="11" /> <property zoom-level="9" name="font-size" value="14" /> <property zoom-level="10" name="font-size" value="24" /> <property zoom-level="6-10" name="color" value="#303030FF" /> @@ -151,26 +151,26 @@ </layer> <layer data-source="minor-highway-ramps" draw-type="lines"> <!-- minor highway ramp top --> - <property zoom-level="8" name="line-width" value="3" /> - <property zoom-level="9" name="line-width" value="5" /> + <property zoom-level="8" name="line-width" value="1" /> + <property zoom-level="9" name="line-width" value="5" /> <property zoom-level="10" name="line-width" value="8" /> - <property zoom-level="6-10" name="color" value="#fffbffff" /> + <property zoom-level="8-10" name="color" value="#fffbffff" /> </layer> <layer data-source="minor-roads" draw-type="lines"> <!-- minor roads top --> <property zoom-level="7" name="line-width" value="1" /> - <property zoom-level="7" name="color" value="#CAC2A9ff" /> + <property zoom-level="7" name="color" value="#D9D0B7ff" /> <property zoom-level="7" name="line-cap" value="square" /> - <property zoom-level="8" name="line-width" value="1" /> + <property zoom-level="8" name="line-width" value="2" /> <property zoom-level="9" name="line-width" value="10" /> <property zoom-level="10" name="line-width" value="18" /> <property zoom-level="8-10" name="color" value="#FFFFFFFF" /> </layer> <layer data-source="minor-highway-ramps" draw-type="lines"> <!-- minor highway ramps top --> - <property zoom-level="8" name="line-width" value="5" /> + <property zoom-level="8" name="line-width" value="3" /> <property zoom-level="9" name="line-width" value="7" /> <property zoom-level="10" name="line-width" value="10"/> <property zoom-level="7-10" name="color" value="#c0c0c0ff" /> @@ -190,11 +190,13 @@ <layer data-source="minor-roads" draw-type="lines"> <!-- minor roads bottom --> - <property zoom-level="8" name="line-width" value="3" /> + <property zoom-level="8" name="line-width" value="4" /> <property zoom-level="8" name="line-cap" value="square" /> - <property zoom-level="9" name="line-width" value="12" /> + <property zoom-level="8" name="color" value="#D5CEB4ff" /> + + <property zoom-level="9" name="line-width" value="12" /> <property zoom-level="10" name="line-width" value="20" /> - <property zoom-level="8-10" name="color" value="#C5BEA4ff" /> + <property zoom-level="9-10" name="color" value="#C5BEA4ff" /> </layer> <layer data-source="railroads" draw-type="lines"> @@ -227,7 +229,11 @@ </layer> <layer data-source="lakes" draw-type="polygons"> - <property zoom-level="1-10" name="color" value="#B5C6D6FF" /> + <property zoom-level="1-10" name="color" value="#B6CCDEFF" /> + </layer> + <layer data-source="lakes" draw-type="lines"> + <property zoom-level="1-10" name="line-width" value="2" /> + <property zoom-level="1-10" name="color" value="#9Db6bEFF" /> </layer> <layer data-source="parks" draw-type="polygons"> @@ -235,8 +241,8 @@ <property zoom-level="1-10" name="color" value="#DEDBADff" /> </layer> <layer data-source="parks" draw-type="lines"> - <property zoom-level="1-10" name="line-width" value="2" /> - <property zoom-level="1-10" name="color" value="#BEBB8Dff" /> + <property zoom-level="1-10" name="line-width" value="2" /> + <property zoom-level="1-10" name="color" value="#BEBB8Dff" /> </layer> <layer data-source="misc-areas" draw-type="polygons"> diff --git a/data/roadster.glade b/data/roadster.glade index 2178663..7736b07 100644 --- a/data/roadster.glade +++ b/data/roadster.glade @@ -1139,7 +1139,7 @@ Banks</property> <property name="use_underline">True</property> <child internal-child="image"> - <widget class="GtkImage" id="image10265"> + <widget class="GtkImage" id="image10292"> <property name="visible">True</property> <property name="stock">gtk-open</property> <property name="icon_size">1</property> @@ -1172,7 +1172,7 @@ Banks</property> <property name="use_underline">True</property> <child internal-child="image"> - <widget class="GtkImage" id="image10266"> + <widget class="GtkImage" id="image10293"> <property name="visible">True</property> <property name="stock">gtk-save-as</property> <property name="icon_size">1</property> @@ -1199,7 +1199,7 @@ Banks</property> <accelerator key="Q" modifiers="GDK_CONTROL_MASK" signal="activate"/> <child internal-child="image"> - <widget class="GtkImage" id="image10267"> + <widget class="GtkImage" id="image10294"> <property name="visible">True</property> <property name="stock">gtk-quit</property> <property name="icon_size">1</property> @@ -1302,7 +1302,7 @@ Banks</property> <property name="visible">True</property> <property name="label" translatable="yes">_Auto</property> <property name="use_underline">True</property> - <property name="active">False</property> + <property name="active">True</property> </widget> </child> @@ -1311,7 +1311,7 @@ Banks</property> <property name="visible">True</property> <property name="label" translatable="yes">_Day Colors</property> <property name="use_underline">True</property> - <property name="active">False</property> + <property name="active">True</property> <property name="group">auto1</property> </widget> </child> @@ -1370,7 +1370,7 @@ Banks</property> <accelerator key="Left" modifiers="GDK_MOD1_MASK" signal="activate"/> <child internal-child="image"> - <widget class="GtkImage" id="image10268"> + <widget class="GtkImage" id="image10295"> <property name="visible">True</property> <property name="stock">gtk-go-back</property> <property name="icon_size">1</property> @@ -1393,7 +1393,7 @@ Banks</property> <accelerator key="Right" modifiers="GDK_MOD1_MASK" signal="activate"/> <child internal-child="image"> - <widget class="GtkImage" id="image10269"> + <widget class="GtkImage" id="image10296"> <property name="visible">True</property> <property name="stock">gtk-media-forward</property> <property name="icon_size">1</property> @@ -1453,7 +1453,7 @@ Banks</property> <accelerator key="F9" modifiers="0" signal="activate"/> <child internal-child="image"> - <widget class="GtkImage" id="image10270"> + <widget class="GtkImage" id="image10297"> <property name="visible">True</property> <property name="stock">gtk-refresh</property> <property name="icon_size">1</property> @@ -1501,7 +1501,7 @@ Banks</property> <signal name="activate" handler="mainwindow_on_aboutmenuitem_activate" last_modification_time="Sat, 12 Mar 2005 06:48:18 GMT"/> <child internal-child="image"> - <widget class="GtkImage" id="image10271"> + <widget class="GtkImage" id="image10298"> <property name="visible">True</property> <property name="stock">gtk-about</property> <property name="icon_size">1</property> @@ -1553,7 +1553,7 @@ Banks</property> <signal name="activate" handler="mainwindow_on_import_maps_activate" last_modification_time="Fri, 04 Mar 2005 04:28:20 GMT"/> <child internal-child="image"> - <widget class="GtkImage" id="image10272"> + <widget class="GtkImage" id="image10299"> <property name="visible">True</property> <property name="stock">gtk-open</property> <property name="icon_size">1</property> @@ -1581,7 +1581,7 @@ Banks</property> <accelerator key="F5" modifiers="0" signal="activate"/> <child internal-child="image"> - <widget class="GtkImage" id="image10273"> + <widget class="GtkImage" id="image10300"> <property name="visible">True</property> <property name="stock">gtk-refresh</property> <property name="icon_size">1</property> @@ -1603,7 +1603,7 @@ Banks</property> <accelerator key="F6" modifiers="0" signal="activate"/> <child internal-child="image"> - <widget class="GtkImage" id="image10274"> + <widget class="GtkImage" id="image10301"> <property name="visible">True</property> <property name="stock">gtk-refresh</property> <property name="icon_size">1</property> @@ -1623,6 +1623,15 @@ Banks</property> </child> <child> + <widget class="GtkMenuItem" id="polygon_test_window1"> + <property name="visible">True</property> + <property name="label" translatable="yes">Polygon Test Window</property> + <property name="use_underline">True</property> + <signal name="activate" handler="test_poly_show" last_modification_time="Tue, 11 Oct 2005 21:37:38 GMT"/> + </widget> + </child> + + <child> <widget class="GtkImageMenuItem" id="gotomenuitem"> <property name="visible">True</property> <property name="label" translatable="yes">_GoTo Dialog</property> @@ -1631,7 +1640,7 @@ Banks</property> <accelerator key="g" modifiers="GDK_CONTROL_MASK" signal="activate"/> <child internal-child="image"> - <widget class="GtkImage" id="image10275"> + <widget class="GtkImage" id="image10302"> <property name="visible">True</property> <property name="stock">gtk-jump-to</property> <property name="icon_size">1</property> @@ -2055,151 +2064,127 @@ Banks</property> <property name="shadow_type">GTK_SHADOW_IN</property> <child> - <widget class="GtkVBox" id="mainwindowcontentsbox"> + <widget class="GtkVBox" id="vbox8924"> <property name="visible">True</property> <property name="homogeneous">False</property> <property name="spacing">0</property> <child> - <widget class="GtkToolbar" id="toolbar2"> - <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property> - <property name="toolbar_style">GTK_TOOLBAR_BOTH</property> - <property name="tooltips">False</property> - <property name="show_arrow">True</property> + <widget class="GtkVPaned" id="vpaned1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="position">100</property> <child> - <widget class="GtkToolItem" id="toolitem1"> - <property name="visible">True</property> - <property name="visible_horizontal">True</property> - <property name="visible_vertical">True</property> - <property name="is_important">False</property> + <widget class="GtkScrolledWindow" id="scrolledwindow9247"> + <property name="height_request">100</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_NEVER</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> <child> - <widget class="GtkButton" id="button44"> + <widget class="GtkTreeView" id="directionstreeview"> <property name="visible">True</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="focus_on_click">False</property> - - <child> - <widget class="GtkLabel" id="label92351"> - <property name="visible">True</property> - <property name="label" translatable="yes"><b>United States</b></property> - <property name="use_underline">False</property> - <property name="use_markup">True</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0.5</property> - <property name="yalign">0.5</property> - <property name="xpad">8</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> - </widget> - </child> + <property name="can_focus">True</property> + <property name="headers_visible">True</property> + <property name="rules_hint">True</property> + <property name="reorderable">False</property> + <property name="enable_search">False</property> + <property name="fixed_height_mode">False</property> + <property name="hover_selection">False</property> + <property name="hover_expand">False</property> </widget> </child> </widget> <packing> - <property name="expand">False</property> - <property name="homogeneous">False</property> + <property name="shrink">False</property> + <property name="resize">False</property> </packing> </child> <child> - <widget class="GtkToolItem" id="toolitem2"> + <widget class="GtkVBox" id="mainwindowcontentsbox"> <property name="visible">True</property> - <property name="visible_horizontal">True</property> - <property name="visible_vertical">True</property> - <property name="is_important">False</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> <child> - <widget class="GtkButton" id="button45"> - <property name="visible">True</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="focus_on_click">False</property> + <widget class="GtkToolbar" id="toolbar2"> + <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property> + <property name="toolbar_style">GTK_TOOLBAR_BOTH</property> + <property name="tooltips">False</property> + <property name="show_arrow">True</property> <child> - <widget class="GtkLabel" id="label92353"> + <widget class="GtkMenuToolButton" id="countrybutton"> <property name="visible">True</property> - <property name="label" translatable="yes"><b>Massachusetts</b></property> - <property name="use_underline">False</property> - <property name="use_markup">True</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0.5</property> - <property name="yalign">0.5</property> - <property name="xpad">8</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> + <property name="label" translatable="yes">Country</property> + <property name="use_underline">True</property> + <property name="visible_horizontal">True</property> + <property name="visible_vertical">True</property> + <property name="is_important">False</property> </widget> + <packing> + <property name="expand">False</property> + <property name="homogeneous">False</property> + </packing> </child> - </widget> - </child> - </widget> - <packing> - <property name="expand">False</property> - <property name="homogeneous">False</property> - </packing> - </child> - <child> - <widget class="GtkToolItem" id="toolitem3"> - <property name="visible">True</property> - <property name="visible_horizontal">True</property> - <property name="visible_vertical">True</property> - <property name="is_important">False</property> - - <child> - <widget class="GtkButton" id="button46"> - <property name="visible">True</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="focus_on_click">False</property> + <child> + <widget class="GtkMenuToolButton" id="statebutton"> + <property name="visible">True</property> + <property name="label" translatable="yes">State</property> + <property name="use_underline">True</property> + <property name="visible_horizontal">True</property> + <property name="visible_vertical">True</property> + <property name="is_important">False</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="homogeneous">False</property> + </packing> + </child> <child> - <widget class="GtkLabel" id="label92352"> + <widget class="GtkMenuToolButton" id="citybutton"> <property name="visible">True</property> - <property name="label" translatable="yes"><b>Cambridge</b></property> - <property name="use_underline">False</property> - <property name="use_markup">True</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0.5</property> - <property name="yalign">0.5</property> - <property name="xpad">8</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> + <property name="label" translatable="yes">City</property> + <property name="use_underline">True</property> + <property name="visible_horizontal">True</property> + <property name="visible_vertical">True</property> + <property name="is_important">False</property> </widget> + <packing> + <property name="expand">False</property> + <property name="homogeneous">False</property> + </packing> </child> </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <placeholder/> </child> </widget> <packing> - <property name="expand">False</property> - <property name="homogeneous">False</property> + <property name="shrink">True</property> + <property name="resize">True</property> </packing> </child> </widget> <packing> <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">False</property> + <property name="expand">True</property> + <property name="fill">True</property> </packing> </child> - - <child> - <placeholder/> - </child> </widget> </child> </widget> @@ -5569,4 +5554,249 @@ review</property> </child> </widget> +<widget class="GtkWindow" id="test_polywindow"> + <property name="width_request">300</property> + <property name="height_request">300</property> + <property name="title" translatable="yes">Polygon Reduction Test</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_CENTER</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + + <child> + <widget class="GtkVBox" id="test_poly_contentbox"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkHBox" id="hbox103"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">12</property> + + <child> + <widget class="GtkVBox" id="vbox8926"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">4</property> + + <child> + <widget class="GtkVBox" id="vbox8927"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label92390"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Reduction Tolerance</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHScale" id="test_poly_scale"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="draw_value">True</property> + <property name="value_pos">GTK_POS_LEFT</property> + <property name="digits">2</property> + <property name="update_policy">GTK_UPDATE_CONTINUOUS</property> + <property name="inverted">False</property> + <property name="adjustment">0.10000000149 0 1 0.00999999977648 0 0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox8928"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label92391"> + <property name="label" translatable="yes"><b>Smoothing</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHScale" id="hscale2"> + <property name="can_focus">True</property> + <property name="draw_value">True</property> + <property name="value_pos">GTK_POS_LEFT</property> + <property name="digits">2</property> + <property name="update_policy">GTK_UPDATE_CONTINUOUS</property> + <property name="inverted">False</property> + <property name="adjustment">0.10000000149 0 1 0.00999999977648 0 0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVSeparator" id="vseparator7"> + <property name="visible">True</property> + </widget> + <packing> + <property name="padding">4</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="test_poly_clear_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + + <child> + <widget class="GtkImage" id="image10281"> + <property name="visible">True</property> + <property name="stock">gtk-clear</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkFrame" id="frame60"> + <property name="border_width">2</property> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + + <child> + <widget class="GtkDrawingArea" id="test_polydrawingarea"> + <property name="visible">True</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="test_polylabel"> + <property name="visible">True</property> + <property name="label" translatable="yes">label92389</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> +</widget> + </glade-interface> diff --git a/src/Makefile.am b/src/Makefile.am index aa9c0a9..2056ead 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -21,10 +21,12 @@ roadster_SOURCES = \ main.c\ db.c\ downloadmanager.c\ + directionswindow.c\ gui.c\ mainwindow.c\ gotowindow.c\ map.c\ + mapinfowindow.c\ map_draw_cairo.c\ map_draw_gdk.c\ map_history.c\ @@ -50,7 +52,8 @@ roadster_SOURCES = \ road.c\ animator.c\ gfreelist.c\ - tooltipwindow.c + tooltipwindow.c\ + test_poly.c roadster_LDADD = \ $(GNOME_LIBS) \ @@ -35,14 +35,21 @@ #include "gotowindow.h" #include "importwindow.h" #include "searchwindow.h" +#include "mapinfowindow.h" #include "locationeditwindow.h" +#ifdef ENABLE_TEST_MODULES +#include "test_poly.h" +#endif + void gui_init(void) { GladeXML* pGladeXML = gui_load_xml(GLADE_FILE_NAME, NULL); glade_xml_signal_autoconnect(pGladeXML); // init all windows/dialogs + g_print("- initializing mapinfowindow\n"); + mapinfowindow_init(pGladeXML); g_print("- initializing mainwindow\n"); mainwindow_init(pGladeXML); g_print("- initializing searchwindow\n"); @@ -51,6 +58,12 @@ void gui_init(void) gotowindow_init(pGladeXML); g_print("- initializing importwindow\n"); importwindow_init(pGladeXML); + +#ifdef ENABLE_TEST_MODULES + g_print("- initializing test_poly\n"); + test_poly_init(pGladeXML); +#endif + //datasetwindow_init(pGladeXML); g_print("- initializing locationeditwindow\n"); locationeditwindow_init(pGladeXML); @@ -26,6 +26,8 @@ //#define G_DISABLE_ASSERT +#define ENABLE_TEST_MODULES + #include <gtk/gtk.h> #define USE_GNOME_VFS // comment this out to get a faster single-threaded compile (can't import, though) diff --git a/src/mainwindow.c b/src/mainwindow.c index 68ddd51..8dc24a2 100644 --- a/src/mainwindow.c +++ b/src/mainwindow.c @@ -48,6 +48,7 @@ #include "glyph.h" #include "animator.h" #include "map_history.h" +#include "mapinfowindow.h" #include "tooltipwindow.h" @@ -447,7 +448,7 @@ void mainwindow_init(GladeXML* pGladeXML) g_signal_connect(G_OBJECT(g_MainWindow.pWindow), "window_state_event", G_CALLBACK(mainwindow_on_window_state_change), NULL); g_signal_connect(G_OBJECT(g_MainWindow.pWindow), "key_press_event", G_CALLBACK(mainwindow_on_key_press), NULL); g_signal_connect(G_OBJECT(g_MainWindow.pWindow), "key_release_event", G_CALLBACK(mainwindow_on_key_release), NULL); - + // Drawing area g_MainWindow.pDrawingArea = GTK_DRAWING_AREA(gtk_drawing_area_new()); @@ -494,6 +495,8 @@ void mainwindow_init(GladeXML* pGladeXML) // XXX: move map to starting location... for now it's (0,0) mainwindow_add_history(); mainwindow_update_zoom_buttons(); // make sure buttons are grayed out + + mapinfowindow_update(g_MainWindow.pMap); } gboolean mainwindow_locationset_list_is_separator_callback(GtkTreeModel *_unused, GtkTreeIter *pIter, gpointer __unused) @@ -158,7 +158,7 @@ gchar* g_apszMapRenderTypeNames[] = {"lines", "polygons", "line-labels", "polygo // init the module void map_init(void) { - g_print("*********************************** %f\n", WORLD_FEET_PER_DEGREE); + //g_print("*********************************** %f\n", WORLD_FEET_PER_DEGREE); } gboolean map_new(map_t** ppMap, GtkWidget* pTargetWidget) diff --git a/src/map_draw_gdk.c b/src/map_draw_gdk.c index 4a538e8..c972531 100644 --- a/src/map_draw_gdk.c +++ b/src/map_draw_gdk.c @@ -38,6 +38,7 @@ #include "db.h" #include "road.h" #include "map_style.h" +#include "map_math.h" #include "locationset.h" #include "location.h" #include "scenemanager.h" @@ -51,6 +52,13 @@ static void map_draw_gdk_layer_fill(map_t* pMap, GdkPixmap* pPixmap, rendermetri static void map_draw_gdk_locations(map_t* pMap, GdkPixmap* pPixmap, rendermetrics_t* pRenderMetrics); static void map_draw_gdk_locationset(map_t* pMap, GdkPixmap* pPixmap, rendermetrics_t* pRenderMetrics, locationset_t* pLocationSet, GPtrArray* pLocationsArray); +typedef struct { + GdkPixmap* pPixmap; + GdkGC* pGC; + maplayerstyle_t* pLayerStyle; + rendermetrics_t* pRenderMetrics; +} gdk_draw_context_t; + //static void map_draw_gdk_tracks(map_t* pMap, GdkPixmap* pPixmap, rendermetrics_t* pRenderMetrics); void map_draw_gdk_set_color(GdkGC* pGC, color_t* pColor) @@ -147,6 +155,53 @@ void map_draw_gdk(map_t* pMap, GPtrArray* pTiles, rendermetrics_t* pRenderMetric TIMER_END(maptimer, "END RENDER MAP (gdk)"); } +// useful for filling the screen with a color. not much else. +static void map_draw_gdk_layer_fill(map_t* pMap, GdkPixmap* pPixmap, rendermetrics_t* pRenderMetrics, maplayerstyle_t* pLayerStyle) +{ + GdkGC* pGC = pMap->pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->pTargetWidget)]; + + GdkGCValues gcValues; + if(pLayerStyle->pGlyphFill != NULL) { + // Instead of filling with a color, fill with a tiled image + gdk_gc_get_values(pGC, &gcValues); + gdk_gc_set_fill(pGC, GDK_TILED); + gdk_gc_set_tile(pGC, glyph_get_pixmap(pLayerStyle->pGlyphFill, pMap->pTargetWidget)); + + // This makes the fill image scroll with the map, instead of staying still + gdk_gc_set_ts_origin(pGC, SCALE_X(pRenderMetrics, pRenderMetrics->fScreenLongitude), SCALE_Y(pRenderMetrics, pRenderMetrics->fScreenLatitude)); + } + else { + // Simple color fill + map_draw_gdk_set_color(pGC, &(pLayerStyle->clrPrimary)); + } + + gdk_draw_rectangle(pPixmap, pMap->pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->pTargetWidget)], + TRUE, 0,0, pMap->MapDimensions.uWidth, pMap->MapDimensions.uHeight); + + if(pLayerStyle->pGlyphFill != NULL) { + // Restore fill style + gdk_gc_set_values(pGC, &gcValues, GDK_GC_FILL); + } +} + +// +static void map_draw_gdk_polygons(const GArray* pMapPointsArray, const gdk_draw_context_t* pContext) +{ + // Copy all points into this array. Yuuup this is slow. :) + GdkPoint aPoints[MAX_GDK_LINE_SEGMENTS]; + mappoint_t* pPoint; + + gint iPoint; + for(iPoint=0 ; iPoint<pMapPointsArray->len ; iPoint++) { + pPoint = &g_array_index(pMapPointsArray, mappoint_t, iPoint); + + aPoints[iPoint].x = pContext->pLayerStyle->nPixelOffsetX + (gint)SCALE_X(pContext->pRenderMetrics, pPoint->fLongitude); + aPoints[iPoint].y = pContext->pLayerStyle->nPixelOffsetY + (gint)SCALE_Y(pContext->pRenderMetrics, pPoint->fLatitude); + } + + gdk_draw_polygon(pContext->pPixmap, pContext->pGC, TRUE, aPoints, pMapPointsArray->len); +} + static void map_draw_gdk_layer_polygons(map_t* pMap, GdkPixmap* pPixmap, rendermetrics_t* pRenderMetrics, GPtrArray* pRoadsArray, maplayerstyle_t* pLayerStyle) { mappoint_t* pPoint; @@ -174,13 +229,21 @@ static void map_draw_gdk_layer_polygons(map_t* pMap, GdkPixmap* pPixmap, renderm map_draw_gdk_set_color(pGC, &(pLayerStyle->clrPrimary)); } + gdk_draw_context_t context; + context.pPixmap = pPixmap; + context.pGC = pGC; + context.pLayerStyle = pLayerStyle; + context.pRenderMetrics = pRenderMetrics; + for(iString=0 ; iString<pRoadsArray->len ; iString++) { pRoad = g_ptr_array_index(pRoadsArray, iString); - if(!map_rects_overlap(&(pRoad->rWorldBoundingBox), &(pRenderMetrics->rWorldBoundingBox))) { + EOverlapType eOverlapType = map_rect_a_overlap_type_with_rect_b(&(pRoad->rWorldBoundingBox), &(pRenderMetrics->rWorldBoundingBox)); + if(eOverlapType == OVERLAP_NONE) { continue; } + // XXX: should we remove this? if(pRoad->pMapPointsArray->len < 3) { //g_warning("not drawing polygon with < 3 points\n"); continue; @@ -191,17 +254,15 @@ static void map_draw_gdk_layer_polygons(map_t* pMap, GdkPixmap* pPixmap, renderm continue; } - GdkPoint aPoints[MAX_GDK_LINE_SEGMENTS]; - - for(iPoint=0 ; iPoint<pRoad->pMapPointsArray->len ; iPoint++) { - pPoint = &g_array_index(pRoad->pMapPointsArray, mappoint_t, iPoint); - - aPoints[iPoint].x = pLayerStyle->nPixelOffsetX + (gint)SCALE_X(pRenderMetrics, pPoint->fLongitude); - aPoints[iPoint].y = pLayerStyle->nPixelOffsetY + (gint)SCALE_Y(pRenderMetrics, pPoint->fLatitude); + if(eOverlapType == OVERLAP_PARTIAL) { + // draw clipped + // XXX: Currently no clipping, just draw normally + map_draw_gdk_polygons(pRoad->pMapPointsArray, &context); + } + else { + // draw normally + map_draw_gdk_polygons(pRoad->pMapPointsArray, &context); } - - gdk_draw_polygon(pPixmap, pMap->pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->pTargetWidget)], - TRUE, aPoints, pRoad->pMapPointsArray->len); } if(pLayerStyle->pGlyphFill != NULL) { // Restore fill style @@ -209,45 +270,34 @@ static void map_draw_gdk_layer_polygons(map_t* pMap, GdkPixmap* pPixmap, renderm } } -// useful for filling the screen with a color. not much else. -static void map_draw_gdk_layer_fill(map_t* pMap, GdkPixmap* pPixmap, rendermetrics_t* pRenderMetrics, maplayerstyle_t* pLayerStyle) +static void map_draw_gdk_lines(const GArray* pMapPointsArray, const gdk_draw_context_t* pContext) { - GdkGC* pGC = pMap->pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->pTargetWidget)]; - - GdkGCValues gcValues; - if(pLayerStyle->pGlyphFill != NULL) { - // Instead of filling with a color, fill with a tiled image - gdk_gc_get_values(pGC, &gcValues); - gdk_gc_set_fill(pGC, GDK_TILED); - gdk_gc_set_tile(pGC, glyph_get_pixmap(pLayerStyle->pGlyphFill, pMap->pTargetWidget)); - - // This makes the fill image scroll with the map, instead of staying still - gdk_gc_set_ts_origin(pGC, SCALE_X(pRenderMetrics, pRenderMetrics->fScreenLongitude), SCALE_Y(pRenderMetrics, pRenderMetrics->fScreenLatitude)); - } - else { - // Simple color fill - map_draw_gdk_set_color(pGC, &(pLayerStyle->clrPrimary)); - } + // Copy all points into this array. Yuuup this is slow. :) + GdkPoint aPoints[MAX_GDK_LINE_SEGMENTS]; + mappoint_t* pPoint; - gdk_draw_rectangle(pPixmap, pMap->pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->pTargetWidget)], - TRUE, 0,0, pMap->MapDimensions.uWidth, pMap->MapDimensions.uHeight); + gint iPoint; + for(iPoint=0 ; iPoint<pMapPointsArray->len ; iPoint++) { + pPoint = &g_array_index(pMapPointsArray, mappoint_t, iPoint); - if(pLayerStyle->pGlyphFill != NULL) { - // Restore fill style - gdk_gc_set_values(pGC, &gcValues, GDK_GC_FILL); + aPoints[iPoint].x = pContext->pLayerStyle->nPixelOffsetX + (gint)SCALE_X(pContext->pRenderMetrics, pPoint->fLongitude); + aPoints[iPoint].y = pContext->pLayerStyle->nPixelOffsetY + (gint)SCALE_Y(pContext->pRenderMetrics, pPoint->fLatitude); } + + gdk_draw_lines(pContext->pPixmap, pContext->pGC, aPoints, pMapPointsArray->len); } static void map_draw_gdk_layer_lines(map_t* pMap, GdkPixmap* pPixmap, rendermetrics_t* pRenderMetrics, GPtrArray* pRoadsArray, maplayerstyle_t* pLayerStyle) { road_t* pRoad; - mappoint_t* pPoint; gint iString; gint iPoint; if(pLayerStyle->fLineWidth <= 0.0) return; // Don't draw invisible lines if(pLayerStyle->clrPrimary.fAlpha == 0.0) return; // invisible? (not that we respect it in gdk drawing anyway) + GdkGC* pGC = pMap->pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->pTargetWidget)]; + // Translate generic cap style into GDK constant gint nCapStyle; if(pLayerStyle->nCapStyle == MAP_CAP_STYLE_ROUND) { @@ -278,10 +328,17 @@ static void map_draw_gdk_layer_lines(map_t* pMap, GdkPixmap* pPixmap, rendermetr map_draw_gdk_set_color(pMap->pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->pTargetWidget)], &(pLayerStyle->clrPrimary)); + gdk_draw_context_t context; + context.pPixmap = pPixmap; + context.pGC = pGC; + context.pLayerStyle = pLayerStyle; + context.pRenderMetrics = pRenderMetrics; + for(iString=0 ; iString<pRoadsArray->len ; iString++) { pRoad = g_ptr_array_index(pRoadsArray, iString); - if(!map_rects_overlap(&(pRoad->rWorldBoundingBox), &(pRenderMetrics->rWorldBoundingBox))) { + EOverlapType eOverlapType = map_rect_a_overlap_type_with_rect_b(&(pRoad->rWorldBoundingBox), &(pRenderMetrics->rWorldBoundingBox)); + if(eOverlapType == OVERLAP_NONE) { continue; } @@ -295,17 +352,14 @@ static void map_draw_gdk_layer_lines(map_t* pMap, GdkPixmap* pPixmap, rendermetr continue; } - // Copy all points into this array. Yuuup this is slow. :) - GdkPoint aPoints[MAX_GDK_LINE_SEGMENTS]; - - for(iPoint=0 ; iPoint<pRoad->pMapPointsArray->len ; iPoint++) { - pPoint = &g_array_index(pRoad->pMapPointsArray, mappoint_t, iPoint); - - aPoints[iPoint].x = pLayerStyle->nPixelOffsetX + (gint)SCALE_X(pRenderMetrics, pPoint->fLongitude); - aPoints[iPoint].y = pLayerStyle->nPixelOffsetY + (gint)SCALE_Y(pRenderMetrics, pPoint->fLatitude); + if(eOverlapType == OVERLAP_PARTIAL) { + // draw clipped + map_draw_gdk_lines(pRoad->pMapPointsArray, &context); + } + else { + // draw directly + map_draw_gdk_lines(pRoad->pMapPointsArray, &context); } - - gdk_draw_lines(pPixmap, pMap->pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->pTargetWidget)], aPoints, pRoad->pMapPointsArray->len); } } diff --git a/src/map_hittest.c b/src/map_hittest.c index 6b7ac6d..9ab938d 100644 --- a/src/map_hittest.c +++ b/src/map_hittest.c @@ -333,7 +333,7 @@ static gboolean map_hittest_locationselections(map_t* pMap, rendermetrics_t* pRe return FALSE; } -// Does the given point come close enough to the line segment to be considered a hit? + static gboolean map_hittest_line(mappoint_t* pPoint1, mappoint_t* pPoint2, mappoint_t* pHitPoint, gdouble fMaxDistance, mappoint_t* pReturnClosestPoint, gdouble* pfReturnPercentAlongLine) { if(pHitPoint->fLatitude < (pPoint1->fLatitude - fMaxDistance) && pHitPoint->fLatitude < (pPoint2->fLatitude - fMaxDistance)) return FALSE; diff --git a/src/map_math.c b/src/map_math.c index 6d820ff..3d63b80 100644 --- a/src/map_math.c +++ b/src/map_math.c @@ -23,6 +23,7 @@ #include <gtk/gtk.h> #include "map.h" +#include "map_math.h" // ======================================================== // Coordinate Conversion Functions @@ -65,6 +66,20 @@ void map_windowpoint_to_mappoint(map_t* pMap, screenpoint_t* pScreenPoint, mappo pMapPoint->fLatitude = pMap->MapCenter.fLatitude - map_pixels_to_degrees(pMap, nPixelDeltaY, pMap->uZoomLevel); } +EOverlapType map_rect_a_overlap_type_with_rect_b(const maprect_t* pA, const maprect_t* pB) +{ + // First, quickly determine if there is no overlap + if(map_rects_overlap(pA,pB) == FALSE) return OVERLAP_NONE; + + if(pA->A.fLatitude < pB->A.fLatitude) return OVERLAP_PARTIAL; + if(pA->B.fLatitude > pB->B.fLatitude) return OVERLAP_PARTIAL; + + if(pA->A.fLongitude < pB->A.fLongitude) return OVERLAP_PARTIAL; + if(pA->B.fLongitude > pB->B.fLongitude) return OVERLAP_PARTIAL; + + return OVERLAP_FULL; +} + gboolean map_rects_overlap(const maprect_t* p1, const maprect_t* p2) { if(p1->B.fLatitude < p2->A.fLatitude) return FALSE; @@ -159,6 +174,169 @@ gboolean map_math_maprects_equal(maprect_t* pA, maprect_t* pB) return map_points_equal(&(pA->A), &(pB->A)) && map_points_equal(&(pA->B), &(pB->B)); } +// +// clipping a map polygon (array of mappoints) to a maprect +// +typedef enum { EDGE_NORTH, EDGE_SOUTH, EDGE_EAST, EDGE_WEST, EDGE_FIRST=0, EDGE_LAST=3 } ERectEdge; + +// static map_math_clip_line_to_worldrect_edge_recursive(mappoint_t* pA, mappoint_t* pB, maprect_t* pRect, ERectEdge eEdge, GArray* pOutput) +// { +// +// } + +gboolean map_math_mappoint_in_maprect(const mappoint_t* pPoint, const maprect_t* pRect) +{ + if(pPoint->fLatitude < pRect->A.fLatitude) return FALSE; + if(pPoint->fLatitude > pRect->B.fLatitude) return FALSE; + if(pPoint->fLongitude < pRect->A.fLongitude) return FALSE; + if(pPoint->fLongitude > pRect->B.fLongitude) return FALSE; + return TRUE; +} + +void map_math_clip_pointstring_to_worldrect(GArray* pMapPointsArray, maprect_t* pRect, GArray* pOutput) +{ + gint nLen = pMapPointsArray->len; + if(nLen <= 2) return; + + mappoint_t* pA = &g_array_index(pMapPointsArray, mappoint_t, 0); + mappoint_t* pB = NULL; + + gboolean bPointAIsInside = map_math_mappoint_in_maprect(pA, pRect); + + gint i; + for(i=1 ; i<pMapPointsArray->len ; i++) { + gint iEdge; + for(iEdge=EDGE_FIRST ; iEdge<=EDGE_LAST ; iEdge++) { + switch(iEdge) { + case EDGE_NORTH: + break; + case EDGE_SOUTH: + break; + case EDGE_EAST: + break; + case EDGE_WEST: + break; + } + } + } +} + +void static map_math_simplify_pointstring_recursive(const GArray* pInput, gint8* pabInclude, gdouble fTolerance, gint iFirst, gint iLast) +{ + if(iFirst+1 >= iLast) return; // no points between first and last? + + mappoint_t* pA = &g_array_index(pInput, mappoint_t, iFirst); + mappoint_t* pB = &g_array_index(pInput, mappoint_t, iLast); + + // Init to bad values + gint iFarthestIndex = -1; + gdouble fBiggestDistanceSquared = 0.0; + + // Of all points between A and B, which is farthest from the line AB? + mappoint_t* pPoint; + gint i; + for(i=(iFirst+1) ; i<=(iLast-1) ; i++) { + pPoint = &g_array_index(pInput, mappoint_t, i); + gdouble fDistanceSquared = map_math_point_distance_squared_from_line(pPoint, pA, pB); + + if(fDistanceSquared > fBiggestDistanceSquared) { + fBiggestDistanceSquared = fDistanceSquared; + iFarthestIndex = i; + } + } + if(fBiggestDistanceSquared > (fTolerance * fTolerance) && (iFarthestIndex != -1)) { // add last test just in case fTolerance == 0.0 + // Mark for inclusion + pabInclude[iFarthestIndex] = 1; + + map_math_simplify_pointstring_recursive(pInput, pabInclude, fTolerance, iFirst, iFarthestIndex); + map_math_simplify_pointstring_recursive(pInput, pabInclude, fTolerance, iFarthestIndex, iLast); + } +} + +void map_math_simplify_pointstring(const GArray* pInput, gdouble fTolerance, GArray* pOutput) +{ + if(pInput->len < 2) return; + + gint8* pabInclude = g_new0(gint8, pInput->len + 20); + + // Mark first and last points + pabInclude[0] = 1; + pabInclude[pInput->len-1] = 1; + + map_math_simplify_pointstring_recursive(pInput, pabInclude, fTolerance, 0, pInput->len-1); + + // + // cleanup + // + mappoint_t* pPoint; + gint i; + for(i=0 ; i<pInput->len ; i++) { + pPoint = &g_array_index(pInput, mappoint_t, i); + if(pabInclude[i] == 1) { + g_array_append_val(pOutput, *pPoint); + } + } + g_free(pabInclude); +} + +// Does the given point come close enough to the line segment to be considered a hit? +gdouble map_math_point_distance_squared_from_line(mappoint_t* pHitPoint, mappoint_t* pPoint1, mappoint_t* pPoint2) +{ + // Some bad ASCII art demonstrating the situation: + // + // / (u) + // / | + // / | + // (0,0) =====(a)========== (v) + + // v is the translated-to-origin vector of line + // u is the translated-to-origin vector of the hitpoint + // a is the closest point on v to the end of u (the hit point) + + // + // 1. Convert p1->p2 vector into a vector (v) that is assumed to come out of the origin (0,0) + // + mappoint_t v; + v.fLatitude = pPoint2->fLatitude - pPoint1->fLatitude; // 10->90 becomes 0->80 (just store 80) + v.fLongitude = pPoint2->fLongitude - pPoint1->fLongitude; + + gdouble fLengthV = sqrt((v.fLatitude*v.fLatitude) + (v.fLongitude*v.fLongitude)); + if(fLengthV == 0.0) return FALSE; // bad data: a line segment with no length? + + // + // 2. Make a unit vector out of v (meaning same direction but length=1) by dividing v by v's length + // + mappoint_t unitv; + unitv.fLatitude = v.fLatitude / fLengthV; + unitv.fLongitude = v.fLongitude / fLengthV; // unitv is now a unit (=1.0) length v + + // + // 3. Translate the hitpoint in the same way we translated v + // + mappoint_t u; + u.fLatitude = pHitPoint->fLatitude - pPoint1->fLatitude; + u.fLongitude = pHitPoint->fLongitude - pPoint1->fLongitude; + + // + // 4. Use the dot product of (unitv) and (u) to find (a), the point along (v) that is closest to (u). see diagram above. + // + gdouble fLengthAlongV = (unitv.fLatitude * u.fLatitude) + (unitv.fLongitude * u.fLongitude); + + mappoint_t a; + a.fLatitude = v.fLatitude * (fLengthAlongV / fLengthV); // multiply each component by the percentage + a.fLongitude = v.fLongitude * (fLengthAlongV / fLengthV); + // NOTE: (a) is *not* where it actually hit on the *map*. don't draw this point! we'd have to translate it back away from the origin. + + // + // 5. Calculate the distance from the end of (u) to (a). If it's less than the fMaxDistance, it's a hit. + // + gdouble fRise = u.fLatitude - a.fLatitude; + gdouble fRun = u.fLongitude - a.fLongitude; + gdouble fDistanceSquared = fRise*fRise + fRun*fRun; // compare squared distances. same results but without the sqrt. + + return fDistanceSquared; +} + #ifdef ROADSTER_DEAD_CODE /* diff --git a/src/map_math.h b/src/map_math.h index 5643b98..b7c6c99 100644 --- a/src/map_math.h +++ b/src/map_math.h @@ -24,7 +24,19 @@ #ifndef _MAP_MATH_H_ #define _MAP_MATH_H_ +typedef enum { + OVERLAP_FULL, + OVERLAP_NONE, + OVERLAP_PARTIAL +} EOverlapType; + gboolean map_math_screenpoint_in_screenrect(screenpoint_t* pPt, screenrect_t* pRect); gboolean map_math_maprects_equal(maprect_t* pA, maprect_t* pB); +EOverlapType map_rect_a_overlap_type_with_rect_b(const maprect_t* pA, const maprect_t* pB); +gboolean map_rects_overlap(const maprect_t* p1, const maprect_t* p2); + +void map_math_simplify_pointstring(const GArray* pInput, gdouble fTolerance, GArray* pOutput); +gdouble map_math_point_distance_squared_from_line(mappoint_t* pHitPoint, mappoint_t* pPoint1, mappoint_t* pPoint2); + #endif diff --git a/src/test_poly.c b/src/test_poly.c new file mode 100644 index 0000000..6208806 --- /dev/null +++ b/src/test_poly.c @@ -0,0 +1,209 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gtk/gtk.h> +#include <glade/glade.h> +#include <cairo.h> +#include <cairo-xlib.h> + +#include "gui.h" +#include "map.h" +#include "util.h" + +struct { + GtkWindow* pWindow; + + GtkHScale* pScale; + GtkVBox* pContentBox; + GtkButton* pClearButton; + GtkDrawingArea* pDrawingArea; + GtkLabel* pLabel; + + GArray* pPointsArray; +} g_Test_Poly; + +static gboolean on_time_to_update(GtkWidget *pDrawingArea, GdkEventExpose *event, gpointer data); +static void test_poly_draw(); +static gboolean on_mouse_button_click(GtkWidget* w, GdkEventButton *event); +static gboolean on_clear_clicked(GtkWidget* w, GdkEventButton *event); + +void test_poly_init(GladeXML* pGladeXML) +{ + GLADE_LINK_WIDGET(pGladeXML, g_Test_Poly.pWindow, GTK_WINDOW, "test_polywindow"); + GLADE_LINK_WIDGET(pGladeXML, g_Test_Poly.pScale, GTK_HSCALE, "test_poly_scale"); + GLADE_LINK_WIDGET(pGladeXML, g_Test_Poly.pContentBox, GTK_VBOX, "test_poly_contentbox"); + GLADE_LINK_WIDGET(pGladeXML, g_Test_Poly.pClearButton, GTK_BUTTON, "test_poly_clear_button"); + GLADE_LINK_WIDGET(pGladeXML, g_Test_Poly.pLabel, GTK_LABEL, "test_polylabel"); + GLADE_LINK_WIDGET(pGladeXML, g_Test_Poly.pDrawingArea, GTK_DRAWING_AREA, "test_polydrawingarea"); + + g_Test_Poly.pPointsArray = g_array_new(FALSE, FALSE, sizeof(mappoint_t)); + + // Drawing area + gtk_widget_set_double_buffered(GTK_WIDGET(g_Test_Poly.pDrawingArea), FALSE); + gtk_widget_add_events(GTK_WIDGET(g_Test_Poly.pDrawingArea), GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK); + g_signal_connect(G_OBJECT(g_Test_Poly.pDrawingArea), "expose-event", G_CALLBACK(on_time_to_update), NULL); + g_signal_connect(G_OBJECT(g_Test_Poly.pDrawingArea), "button_press_event", G_CALLBACK(on_mouse_button_click), NULL); + + // Scale + g_signal_connect(G_OBJECT(g_Test_Poly.pScale), "value-changed", G_CALLBACK(on_time_to_update), NULL); + // make it instant-change using our hacky callback + //g_signal_connect(G_OBJECT(g_Test_Poly.pScale), "change-value", G_CALLBACK(util_gtk_range_instant_set_on_value_changing_callback), NULL); + + // "Clear" button + g_signal_connect(G_OBJECT(g_Test_Poly.pClearButton), "clicked", G_CALLBACK(on_clear_clicked), NULL); + + // don't delete window on X, just hide it + g_signal_connect(G_OBJECT(g_Test_Poly.pWindow), "delete_event", G_CALLBACK(gtk_widget_hide), NULL); +} + +void test_poly_show(GtkMenuItem *menuitem, gpointer user_data) +{ + gtk_widget_show(GTK_WIDGET(g_Test_Poly.pWindow)); +} + +static gboolean on_clear_clicked(GtkWidget* w, GdkEventButton *event) +{ + g_array_remove_range(g_Test_Poly.pPointsArray, 0, g_Test_Poly.pPointsArray->len); + gtk_widget_queue_draw(GTK_WIDGET(g_Test_Poly.pDrawingArea)); +} + +static gboolean on_mouse_button_click(GtkWidget* w, GdkEventButton *event) +{ + gint nX, nY; + gdk_window_get_pointer(w->window, &nX, &nY, NULL); + + gint nWidth = GTK_WIDGET(g_Test_Poly.pDrawingArea)->allocation.width; + gint nHeight = GTK_WIDGET(g_Test_Poly.pDrawingArea)->allocation.height; + + mappoint_t point; + point.fLongitude = (gdouble)nX / (gdouble)nWidth; + point.fLatitude = (gdouble)nY / (gdouble)nHeight; + g_array_append_val(g_Test_Poly.pPointsArray, point); + + gtk_widget_queue_draw(GTK_WIDGET(g_Test_Poly.pDrawingArea)); +} + +void test_poly_draw_array(cairo_t* pCairo, GArray* pArray) +{ + if(pArray->len >= 1) { + mappoint_t* pPoint; + pPoint = &g_array_index(pArray, mappoint_t, 0); + cairo_move_to(pCairo, pPoint->fLongitude, pPoint->fLatitude); + cairo_arc(pCairo, pPoint->fLongitude, pPoint->fLatitude, 0.02, 0, 2*M_PI); + cairo_fill(pCairo); + cairo_move_to(pCairo, pPoint->fLongitude, pPoint->fLatitude); + gint i; + for(i=1 ; i<pArray->len ;i++) { + pPoint = &g_array_index(pArray, mappoint_t, i); + cairo_line_to(pCairo, pPoint->fLongitude, pPoint->fLatitude); + } + pPoint = &g_array_index(pArray, mappoint_t, 0); + cairo_line_to(pCairo, pPoint->fLongitude, pPoint->fLatitude); + } +} + +static gboolean on_time_to_update(GtkWidget *pDrawingArea, GdkEventExpose *event, gpointer data) +{ + Display* dpy; + Drawable drawable; + dpy = gdk_x11_drawable_get_xdisplay(GTK_WIDGET(g_Test_Poly.pDrawingArea)->window); + Visual *visual = DefaultVisual (dpy, DefaultScreen (dpy)); + gint width, height; + drawable = gdk_x11_drawable_get_xid(GTK_WIDGET(g_Test_Poly.pDrawingArea)->window); + gdk_drawable_get_size (GTK_WIDGET(g_Test_Poly.pDrawingArea)->window, &width, &height); + cairo_surface_t *pSurface = cairo_xlib_surface_create (dpy, drawable, visual, width, height); + + gdouble fValue = gtk_range_get_value(g_Test_Poly.pScale); + + cairo_t* pCairo = cairo_create (pSurface); + + cairo_scale(pCairo, width, height); + + cairo_set_source_rgba(pCairo, 1.0, 1.0, 1.0, 1.0); + cairo_rectangle(pCairo, 0.0, 0.0, 1.0, 1.0); + cairo_fill(pCairo); + + // Draw lines + cairo_set_line_join(pCairo, CAIRO_LINE_JOIN_ROUND); + cairo_save(pCairo); + cairo_set_line_width(pCairo, 0.02); + cairo_set_source_rgba(pCairo, 1.0, 0.0, 0.0, 1.0); + test_poly_draw_array(pCairo, g_Test_Poly.pPointsArray); + cairo_stroke(pCairo); + cairo_restore(pCairo); + + cairo_save(pCairo); + GArray* pSimplified = g_array_new(FALSE, FALSE, sizeof(mappoint_t)); + map_math_simplify_pointstring(g_Test_Poly.pPointsArray, fValue, pSimplified); + cairo_set_line_width(pCairo, 0.01); + cairo_set_source_rgba(pCairo, 0.0, 1.0, 0.0, 0.5); + test_poly_draw_array(pCairo, pSimplified); + cairo_fill(pCairo); + cairo_restore(pCairo); + + cairo_destroy(pCairo); + + if(g_Test_Poly.pPointsArray->len == 0) { + gtk_label_set_markup(g_Test_Poly.pLabel, "<b>Click to create points</b>"); + } + else { + gchar* pszMarkup = g_strdup_printf("%d points, %d simplified", g_Test_Poly.pPointsArray->len, pSimplified->len); + gtk_label_set_markup(g_Test_Poly.pLabel, pszMarkup); + g_free(pszMarkup); + } + + g_array_free(pSimplified, TRUE); + return TRUE; +} + +// static void paint (GtkWidget *widget,GdkEventExpose *eev,gpointer data) +// { +// gint width, height; +// gint i; +// cairo_t *cr; +// +// width = widget->allocation.width; +// height = widget->allocation.height; +// +// cr = gdk_cairo_create (widget->window); +// +// /* clear background */ +// cairo_set_source_rgb (cr, 1,1,1); +// cairo_paint (cr); +// +// +// cairo_select_font_face (cr, "Sans", CAIRO_FONT_SLANT_NORMAL, +// CAIRO_FONT_WEIGHT_BOLD); +// +// /* enclosing in a save/restore pair since we alter the +// * font size +// */ +// cairo_save (cr); +// cairo_set_font_size (cr, 40); +// cairo_move_to (cr, 40, 60); +// cairo_set_source_rgb (cr, 0,0,0); +// cairo_show_text (cr, "Hello World"); +// cairo_restore (cr); +// +// cairo_set_source_rgb (cr, 1,0,0); +// cairo_set_font_size (cr, 20); +// cairo_move_to (cr, 50, 100); +// cairo_show_text (cr, "greetings from gtk and cairo"); +// +// cairo_set_source_rgb (cr, 0,0,1); +// +// cairo_move_to (cr, 0, 150); +// for (i=0; i< width/10; i++) +// { +// cairo_rel_line_to (cr, 5, 10); +// cairo_rel_line_to (cr, 5, -10); +// } +// cairo_stroke (cr); +// +// cairo_destroy (cr); +// } +// +// static gboolean on_expose_event(GtkWidget *pDrawingArea, GdkEventExpose *event, gpointer data) +// { +// } diff --git a/src/test_poly.h b/src/test_poly.h new file mode 100644 index 0000000..c0476f6 --- /dev/null +++ b/src/test_poly.h @@ -0,0 +1,31 @@ +/*************************************************************************** + * test_poly.h + * + * Copyright 2005 Ian McIntosh + * ian_mcintosh@linuxadvocate.org + ****************************************************************************/ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _TEST_POLY_H_ +#define _TEST_POLY_H_ + +#include <glade/glade.h> + +void test_poly_init(GladeXML* pGladeXML); + +#endif |