1 // -*- C++ -*-
2
3 /*
4 * Gnome Chemistry Utils
5 * gccv/arc.cc
6 *
7 * Copyright (C) 2009-2010 Jean Bréfort <jean.brefort@normalesup.org>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 3 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
22 * USA
23 */
24
25 #include "config.h"
26 #include "arc.h"
27
28 namespace gccv {
29
Arc(Canvas * canvas,double xc,double yc,double radius,double start,double end)30 Arc::Arc (Canvas *canvas, double xc, double yc, double radius, double start, double end):
31 LineItem (canvas),
32 m_X (xc),
33 m_Y (yc),
34 m_Radius (radius),
35 m_Start (start),
36 m_End (end),
37 m_Head (ArrowHeadNone),
38 m_A (6.),
39 m_B (8.),
40 m_C (4.)
41 {
42 }
43
Arc(Group * parent,double xc,double yc,double radius,double start,double end,ItemClient * client)44 Arc::Arc (Group *parent, double xc, double yc, double radius, double start, double end, ItemClient *client):
45 LineItem (parent, client),
46 m_X (xc),
47 m_Y (yc),
48 m_Radius (radius),
49 m_Start (start),
50 m_End (end),
51 m_Head (ArrowHeadNone),
52 m_A (6.),
53 m_B (8.),
54 m_C (4.)
55 {
56 }
57
~Arc()58 Arc::~Arc ()
59 {
60 }
61
Distance(double x,double y,Item ** item) const62 double Arc::Distance (double x, double y, Item **item) const
63 {
64 // use cairo_in_stroke to detect if the point is inside
65 // size for the surface is probably unimportant
66 if (item)
67 *item = const_cast <Arc *> (this);
68 cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
69 cairo_t *cr = cairo_create (surface);
70 cairo_surface_destroy (surface);
71 cairo_set_line_width (cr, GetLineWidth () + 1.); // add 1. to the width to help for selection
72 ToCairo (cr);
73 // FIXME, take colors into account
74 if (cairo_in_stroke (cr, x, y)) {
75 cairo_destroy (cr);
76 return 0.;
77 }
78 cairo_destroy (cr);
79 return G_MAXDOUBLE; // FIXME
80 }
81
Draw(cairo_t * cr,G_GNUC_UNUSED bool is_vector) const82 void Arc::Draw (cairo_t *cr, G_GNUC_UNUSED bool is_vector) const
83 {
84 if (ApplyLine (cr))
85 ToCairo (cr);
86 cairo_restore (cr);
87 }
88
UpdateBounds()89 void Arc::UpdateBounds ()
90 {
91 cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
92 cairo_t *cr = cairo_create (surface);
93 cairo_set_line_width (cr, GetLineWidth ());
94 if (m_Head == ArrowHeadNone) {
95 if (m_Start < m_End)
96 cairo_arc (cr, m_X, m_Y, m_Radius, m_Start, m_End);
97 else
98 cairo_arc_negative (cr, m_X, m_Y, m_Radius, m_Start, m_End);
99 cairo_stroke_extents (cr, &m_x0, &m_y0, &m_x1, &m_y1);
100 } else {
101 double end = m_End + ((m_End > m_Start)? -1.: 1.) * m_A / m_Radius;
102 if (m_Start < m_End)
103 cairo_arc (cr, m_X, m_Y, m_Radius, m_Start, end);
104 else
105 cairo_arc_negative (cr, m_X, m_Y, m_Radius, m_Start, end);
106 cairo_stroke_extents (cr, &m_x0, &m_y0, &m_x1, &m_y1);
107 // now take the head into account
108 double x0, y0, x1, y1, rot;
109 x0 = m_X + m_Radius * cos (end);
110 y0 = m_Y + m_Radius * sin (end);
111 x1 = m_X + m_Radius * cos (m_End);
112 y1 = m_Y + m_Radius * sin (m_End);
113 rot = atan2 (y1 - y0, x1 - x0);
114 cairo_save (cr);
115 cairo_translate (cr, x0, y0);
116 cairo_rotate (cr, rot);
117 switch (m_Head) {
118 case ArrowHeadRight:
119 // FIXME
120 break;
121 case ArrowHeadLeft:
122 // FIXME
123 break;
124 default:
125 cairo_move_to (cr, 0., GetLineWidth () / 2.);
126 cairo_line_to (cr, m_A - m_B, GetLineWidth () / 2. + m_C);
127 cairo_line_to (cr, m_A, 0.);
128 cairo_line_to (cr, m_A - m_B, -GetLineWidth () / 2. - m_C);
129 cairo_line_to (cr, 0., -GetLineWidth () / 2.);
130 break;
131 }
132 cairo_close_path (cr);
133 cairo_restore (cr);
134 cairo_fill_extents (cr, &x0, &y0, &x1, &y1);
135 if (x0 < m_x0)
136 m_x0 = x0;
137 if (y0 < m_y0)
138 m_y0 = y0;
139 if (x1 > m_x1)
140 m_x1 = x1;
141 if (y1 > m_y1)
142 m_y1 = y1;
143 }
144 cairo_surface_destroy (surface);
145 cairo_destroy (cr);
146 Item::UpdateBounds ();
147 }
148
ToCairo(cairo_t * cr) const149 void Arc::ToCairo (cairo_t *cr) const
150 {
151 if (m_Head == ArrowHeadNone) {
152 if (m_Start < m_End)
153 cairo_arc (cr, m_X, m_Y, m_Radius, m_Start, m_End);
154 else
155 cairo_arc_negative (cr, m_X, m_Y, m_Radius, m_Start, m_End);
156 cairo_stroke (cr);
157 } else {
158 double end = m_End + ((m_End > m_Start)? -1.: 1.) * m_A / m_Radius;
159 if (m_Start < m_End)
160 cairo_arc (cr, m_X, m_Y, m_Radius, m_Start, end);
161 else
162 cairo_arc_negative (cr, m_X, m_Y, m_Radius, m_Start, end);
163 cairo_stroke (cr);
164 // now draw the head
165 double x0, y0, x1, y1, rot;
166 x0 = m_X + m_Radius * cos (end);
167 y0 = m_Y + m_Radius * sin (end);
168 x1 = m_X + m_Radius * cos (m_End);
169 y1 = m_Y + m_Radius * sin (m_End);
170 rot = atan2 (y1 - y0, x1 - x0);
171 cairo_save (cr);
172 cairo_translate (cr, x0, y0);
173 cairo_rotate (cr, rot);
174 switch (m_Head) {
175 case ArrowHeadRight:
176 // FIXME
177 break;
178 case ArrowHeadLeft:
179 // FIXME
180 break;
181 default:
182 cairo_move_to (cr, 0., GetLineWidth () / 2.);
183 cairo_line_to (cr, m_A - m_B, GetLineWidth () / 2. + m_C);
184 cairo_line_to (cr, m_A, 0.);
185 cairo_line_to (cr, m_A - m_B, -GetLineWidth () / 2. - m_C);
186 cairo_line_to (cr, 0., -GetLineWidth () / 2.);
187 break;
188 }
189 cairo_close_path (cr);
190 cairo_fill (cr);
191 cairo_restore (cr);
192 }
193 }
194
195 } // namespace gccv
196