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