1 // XDrawChem
2 // Copyright (C) 2004-2005 Bryan Herger <bherger@users.sourceforge.net>
3 // Copyright (C) 2020 Yaman Qalieh <ybq987@gmail.com>
4
5 // This program is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14
15 // You should have received a copy of the GNU General Public License
16 // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
18 // gobject.cpp - GraphicObject's implementation of functions
19
20 #include <QPoint>
21 #include <QPolygon>
22 #include <QRect>
23 #include <QString>
24
25 #include "bondedit.h"
26 #include "defs.h"
27 #include "drawable.h"
28 #include "gobject.h"
29 #include "render2d.h"
30
GraphicObject(Render2D * r1,QObject * parent)31 GraphicObject::GraphicObject(Render2D *r1, QObject *parent) : Drawable(parent) {
32 r = r1;
33 highlighted = false;
34 style = 0;
35 ot = 0;
36 }
37
CloneTo(Drawable * target) const38 GraphicObject *GraphicObject::CloneTo(Drawable *target) const {
39 if (!target)
40 target = new GraphicObject(r, parent());
41
42 GraphicObject *t = static_cast<GraphicObject *>(this->Drawable::CloneTo(target));
43 t->objectPoints = objectPoints;
44 t->ot = ot;
45 return t;
46 }
47
ToXML(QString xml_id)48 QString GraphicObject::ToXML(QString xml_id) {
49 QString s, n1;
50
51 // begin graphic object
52 s.append("<graphicobject id=\"");
53 s.append(xml_id);
54 s.append("\">\n");
55
56 // write object type (ot)
57 s.append("<objecttype>");
58 n1.setNum(ot);
59 s.append(n1);
60 s.append("</objecttype>\n");
61
62 // write Style
63 s.append("<style>");
64 n1.setNum(style);
65 s.append(n1);
66 s.append("</style>\n");
67
68 // write points
69 if (ot == TYPE_BEZIER) {
70 int ci, xi, yi;
71
72 for (ci = 0; ci < 4; ci++) {
73 s.append("<point>");
74 objectPoints.point(ci, &xi, &yi);
75 n1.setNum(xi);
76 s.append(n1);
77 s.append(" ");
78 n1.setNum(yi);
79 s.append(n1);
80 s.append("</point>\n");
81 }
82 }
83 // write color
84 s.append("<color>");
85 n1.setNum(color.red());
86 s.append(n1);
87 s.append(" ");
88 n1.setNum(color.green());
89 s.append(n1);
90 s.append(" ");
91 n1.setNum(color.blue());
92 s.append(n1);
93 s.append("</color>\n");
94
95 // end bracket
96 s.append("</graphicobject>\n");
97
98 return s;
99 }
100
ToCDXML(QString xml_id)101 QString GraphicObject::ToCDXML(QString xml_id) {
102 QString s, n1;
103
104 return s; // until I learn how to do these objects in CDXML
105
106 // begin arrow
107 s.append("<graphic id=\"");
108 s.append(xml_id);
109 s.append("\" BoundingBox=\"");
110 n1.setNum(end->x);
111 s.append(n1);
112 s.append(" ");
113 n1.setNum(end->y);
114 s.append(n1);
115 s.append(" ");
116 n1.setNum(start->x);
117 s.append(n1);
118 s.append(" ");
119 n1.setNum(start->y);
120 s.append(n1);
121 s.append("\" ");
122 if (style == BRACKET_SQUARE)
123 s.append("GraphicType=\"Bracket\" BracketType=\"SquarePair\"");
124 if (style == BRACKET_CURVE)
125 s.append("GraphicType=\"Bracket\" BracketType=\"RoundPair\"");
126 if (style == BRACKET_BRACE)
127 s.append("GraphicType=\"Bracket\" BracketType=\"CurlyPair\"");
128 s.append("/>\n");
129
130 return s;
131 }
132
133 // set GraphicObject from XDrawChem-format XML
FromXML(QString xml_tag)134 void GraphicObject::FromXML(QString xml_tag) {
135 int i1, i2;
136
137 i1 = xml_tag.indexOf("<Start>");
138 if (i1 >= 0) {
139 i2 = xml_tag.indexOf("</Start>") + 8;
140 SetStartFromXML(xml_tag.mid(i1, i2 - i1));
141 }
142 i1 = xml_tag.indexOf("<End>");
143 if (i1 >= 0) {
144 i2 = xml_tag.indexOf("</End>") + 6;
145 SetEndFromXML(xml_tag.mid(i1, i2 - i1));
146 }
147 i1 = xml_tag.indexOf("<objecttype>");
148 if (i1 >= 0) {
149 i2 = xml_tag.indexOf("</objecttype>") + 13;
150 ot = xml_tag.mid(i1 + 12, 2).toInt();
151 }
152 i1 = xml_tag.indexOf("<style>");
153 if (i1 >= 0) {
154 i2 = xml_tag.indexOf("</style>") + 8;
155 style = xml_tag.mid(i1 + 7, i2 - i1 - 15).toInt();
156 }
157 i1 = xml_tag.indexOf("<color>");
158 if (i1 >= 0) {
159 i2 = xml_tag.indexOf("</color>") + 8;
160 SetColorFromXML(xml_tag.mid(i1, i2 - i1));
161 }
162 if (ot == TYPE_BEZIER) {
163 objectPoints.resize(4);
164 int ci, xi, yi, i3 = 0;
165 QString xml_subtag;
166
167 for (ci = 0; ci < 4; ci++) {
168 i1 = xml_tag.indexOf("<point>", i3);
169 i2 = xml_tag.indexOf("</point>", i3) + 8;
170 i3 = i2 + 1;
171 xml_subtag = xml_tag.mid(i1, i2 - i1);
172 i1 = xml_subtag.indexOf("<point>");
173 i2 = xml_subtag.indexOf("</point>");
174 xml_subtag.remove(i2, 999);
175 xml_subtag.remove(i1, 7);
176
177 QTextStream ts(&xml_subtag, QIODevice::ReadOnly);
178
179 ts >> xi >> yi;
180 qDebug() << ci << " " << xi << " " << yi;
181 objectPoints.setPoint(ci, xi, yi);
182 }
183 start = new DPoint(objectPoints.point(0));
184 end = new DPoint(objectPoints.point(1));
185 }
186 }
187
Render()188 void GraphicObject::Render() {
189 QColor c1;
190
191 if (highlighted)
192 c1 = QColor(255, 0, 0);
193 else
194 c1 = color;
195 if (ot == TYPE_BEZIER)
196 r->drawBezier(objectPoints, c1, false, style);
197 if (ot == TYPE_GRAPHIC_LINE)
198 r->drawLine(start->toQPoint(), end->toQPoint(), 1, GetColor(), 1);
199 if (ot == TYPE_GRAPHIC_BONDMARK)
200 r->drawLine(start->toQPoint(), end->toQPoint(), 1, GetColor(), 1);
201 }
202
Edit()203 void GraphicObject::Edit() {
204 return; // it's not practical to edit any graphic objects this way
205 /*
206 BondEditDialog be(r, "bracket editor", start, end, TYPE_BRACKET, 0, 0, 0,
207 style, color);
208 if ( !be.exec() ) return;
209 qDebug() << "change" ;
210 style = be.Style();
211 color = be.Color();
212 */
213 }
214
Type()215 int GraphicObject::Type() {
216 // real type is stored in style
217 return TYPE_GRAPHIC_OBJECT;
218 }
219
Find(DPoint * target)220 bool GraphicObject::Find(DPoint *target) {
221 if (start == target)
222 return true;
223 if (end == target)
224 return true;
225 return false;
226 }
227
228 // Do not allow connections to this object.
229 // Simplest way to do this, I think, is to disallow this function
FindNearestPoint(DPoint * target,double & dist)230 DPoint *GraphicObject::FindNearestPoint(DPoint *target, double &dist) {
231 dist = 99999.0;
232 return 0;
233 }
234
FindNearestObject(DPoint * target,double & dist)235 Drawable *GraphicObject::FindNearestObject(DPoint *target, double &dist) {
236 DPoint *tl = new DPoint;
237 DPoint *tr = new DPoint;
238 DPoint *bl = new DPoint;
239 DPoint *br = new DPoint;
240 double tl_x, tl_y, br_x, br_y, swp, dist1, dist2;
241
242 tl_x = start->x;
243 tl_y = start->y;
244 br_x = end->x;
245 br_y = end->y;
246 if (tl_x < br_x) {
247 swp = tl_x;
248 tl_x = br_x;
249 br_x = swp;
250 }
251 if (tl_y < br_y) {
252 swp = tl_y;
253 tl_y = br_y;
254 br_y = swp;
255 }
256 tl->x = tl_x;
257 tl->y = tl_y;
258 bl->x = tl_x;
259 bl->y = br_y;
260 tr->x = br_x;
261 tr->y = tl_y;
262 br->x = br_x;
263 br->y = br_y;
264 dist1 = DistanceToLine(tl, bl, target);
265 dist2 = DistanceToLine(tr, br, target);
266 if (dist1 < dist2)
267 dist = dist1;
268 else
269 dist = dist2;
270 delete tl;
271 delete tr;
272 delete bl;
273 delete br;
274
275 return this;
276 }
277
setPoints(DPoint * s,DPoint * e)278 void GraphicObject::setPoints(DPoint *s, DPoint *e) {
279 start = s;
280 end = e;
281 }
282
isWithinRect(QRect n,bool)283 bool GraphicObject::isWithinRect(QRect n, bool /*shiftdown*/) {
284 if (DPointInRect(start, n) && DPointInRect(end, n))
285 highlighted = true;
286 else
287 highlighted = false;
288 return highlighted;
289 }
290
BoundingBox()291 QRect GraphicObject::BoundingBox() {
292 if (highlighted == false)
293 return QRect(QPoint(999, 999), QPoint(0, 0));
294 int top, bottom, left, right, swp;
295
296 top = (int)start->y;
297 left = (int)start->x;
298 bottom = (int)end->y;
299 right = (int)end->x;
300 if (bottom < top) {
301 swp = top;
302 top = bottom;
303 bottom = swp;
304 }
305 if (right < left) {
306 swp = left;
307 left = right;
308 right = swp;
309 }
310 return QRect(QPoint(left, top), QPoint(right, bottom));
311 }
312
setPointArray(QPolygon inp1)313 void GraphicObject::setPointArray(QPolygon inp1) {
314 objectPoints = inp1;
315 // kludge around lack opf Start and End in this object type/style
316 start = new DPoint(objectPoints.point(0));
317 end = new DPoint(objectPoints.point(1));
318 }
319