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 #include <iostream>
19 
20 #include <QApplication>
21 #include <QClipboard>
22 #include <QMessageBox>
23 
24 #include "arrow.h"
25 #include "bond.h"
26 #include "bracket.h"
27 #include "chemdata.h"
28 #include "crings_dialog.h"
29 #include "defs.h"
30 #include "drawable.h"
31 #include "gobject.h"
32 #include "molecule.h"
33 #include "netaccess.h"
34 #include "text.h"
35 #include "tool_13c_nmr.h"
36 #include "tool_1h_nmr.h"
37 #include "tool_2d3d.h"
38 #include "tool_ir.h"
39 #include "tooldialog.h"
40 
41 // For AutoLayout
42 class LayoutGroup {
43   public:
44     QList<Drawable *> items;
45     LayoutGroup *left;
46     LayoutGroup *right;
47     LayoutGroup *above;
48     LayoutGroup *below;
49     bool placed;
Move(double x,double y)50     void Move(double x, double y) {
51         qDebug() << "MOVE:" << x << " " << y;
52         for (Drawable *tmp_draw : items) {
53             tmp_draw->SelectAll();
54             tmp_draw->Move(x, y);
55             tmp_draw->DeselectAll();
56         }
57     }
BoundingBox()58     QRect BoundingBox() {
59         int top = 99999, bottom = 0, left = 99999, right = 0;
60         QRect tmprect;
61 
62         for (Drawable *tmp_draw : items) {
63             tmp_draw->SelectAll();
64             tmprect = tmp_draw->BoundingBox();
65             tmp_draw->DeselectAll();
66             if (tmprect.isValid()) {
67                 if (tmprect.left() < left)
68                     left = tmprect.left();
69                 if (tmprect.right() > right)
70                     right = tmprect.right();
71                 if (tmprect.top() < top)
72                     top = tmprect.top();
73                 if (tmprect.bottom() > bottom)
74                     bottom = tmprect.bottom();
75             }
76         }
77         return QRect(QPoint(left, top), QPoint(right, bottom));
78     }
Center()79     QPoint Center() { return BoundingBox().center(); }
80 };
81 
82 // Determine Molecule clicked, do Tool action
Tool(DPoint * target,int mode)83 void ChemData::Tool(DPoint *target, int mode) {
84     // QClipboard *cb = QApplication::clipboard();
85 
86     qDebug() << "ChemData::Tool: " << mode;
87     Molecule *m = 0;
88     NetAccess *na = new NetAccess();
89     CustomRingDialog cr1;
90     ToolDialog tool1;
91     Tool_1HNMR_Dialog *tool1hnmr;
92     Tool_13CNMR_Dialog *tool13cnmr;
93     Tool_IR_Dialog *toolir;
94     Tool_2D3D tool2d3d;
95     QString tmpname, serverName;
96     QStringList choices;
97     // int dret;
98 
99     for (Drawable *tmp_draw : drawlist) {
100         if (tmp_draw->Type() == TYPE_MOLECULE) {
101             m = (Molecule *)tmp_draw;
102             if (m->BoundingBoxAll().contains(target->toQPoint(), false))
103                 break;
104             m = 0;
105         }
106     }
107     if (m == 0)
108         return;
109     double kow = 0.0;
110     QString thisInChI;
111 
112     switch (mode) {
113     case MODE_TOOL_MOLECULE_INFO:
114         mi = new MolInfoDialog(r);
115         thisInChI = m->ToInChI();
116         tt_mw = m->CalcMW();
117         mi->setMW(tt_mw->getText());
118         tt_ef = m->CalcEmpiricalFormula();
119         mi->setEF(tt_ef->getText());
120         tt_ea = m->CalcElementalAnalysis();
121         mi->setEA(tt_ea->getText());
122 
123         serverName = getenv("XDC_SERVER");
124         if (serverName.length() < 2)
125             serverName = XDC_SERVER;
126         if (na->getNameCAS(serverName, thisInChI)) {
127             mi->setCAS(na->scas);
128             mi->setName(na->siupacname);
129             mi->setSynonyms(na->sname);
130             mi->setPCC(na->spccompound);
131         }
132 
133         connect(mi, SIGNAL(MIDClose()), this, SLOT(returnFromMID()));
134 
135         mi->show();
136         // if ( !mi->exec() ) return;
137         // if (mi->isMWChecked()) drawlist.append(tt_mw);
138         // if (mi->isEFChecked()) drawlist.append(tt_ef);
139         // delete mi;
140         break;
141     case MODE_TOOL_CALCMW:
142         tt = m->CalcMW();
143         if (tt != 0)
144             drawlist.append(tt);
145         break;
146     case MODE_TOOL_CALCEF:
147         tt = m->CalcEmpiricalFormula();
148         if (tt != 0)
149             drawlist.append(tt);
150         break;
151     case MODE_TOOL_CALCEA:
152         tt = m->CalcElementalAnalysis();
153         if (tt != 0)
154             drawlist.append(tt);
155         break;
156     case MODE_TOOL_13CNMR:
157         tool13cnmr = new Tool_13CNMR_Dialog;
158         tool13cnmr->setMolecule(m);
159         tool13cnmr->show();
160         // m->Calc13CNMR();
161         break;
162     case MODE_TOOL_1HNMR:
163         tool1hnmr = new Tool_1HNMR_Dialog;
164         tool1hnmr->setMolecule(m);
165         tool1hnmr->show();
166         // m->Calc1HNMR();
167         break;
168     case MODE_TOOL_IR:
169         toolir = new Tool_IR_Dialog;
170         toolir->setMolecule(m);
171         toolir->show();
172         // m->CalcIR();
173         break;
174     case MODE_TOOL_PKA:
175         m->CalcpKa();
176         break;
177     case MODE_TOOL_RETRO:
178         Retro(m);
179         break;
180     case MODE_TOOL_REACTIVITY_FORWARD:
181         m->Reactivity(mode);
182         break;
183     case MODE_TOOL_REACTIVITY_RETRO:
184         m->Reactivity(mode);
185         for (Bond *tmp_bond = m->bondsFirst(); tmp_bond != 0; tmp_bond = m->bondsNext()) {
186             if (tmp_bond->getReactions().length() > 2) {
187                 tmp_bond->SetColor(QColor(124, 252, 0));
188             }
189         }
190         r->update();
191         break;
192     case MODE_TOOL_CHARGES:
193         m->Reactivity(mode);
194         break;
195     case MODE_TOOL_KOW:
196         kow = m->CalcKOW();
197         QMessageBox::information(
198             r, tr("Octanol-water partition"),
199             tr("Estimated octanol-water partition constant (log Kow) = %1").arg(kow));
200         break;
201     case MODE_TOOL_2D3D:
202         m->Make3DVersion();
203         break;
204     case MODE_TOOL_NAME:
205         m->CalcName();
206         break;
207     case MODE_TOOL_CUSTOMRING:
208         cr1.setMolecule(m);
209         if (cr1.exec() == QDialog::Accepted)
210             emit SignalUpdateCustomRingMenu();
211 
212         break;
213     case MODE_TOOL_TOSMILES:
214         tmpname = m->ToSMILES();
215         if (tmpname.length() == 0) {
216             qDebug() << "Could not get SMILES string!";
217         }
218         QMessageBox::information(r, tr("SMILES string"),
219                                  tr("SMILES string for selected molecule:") + "\n\n" + tmpname);
220         break;
221     case MODE_TOOL_TOINCHI:
222         // m->AddNMRprotons();
223         tmpname = m->ToInChI();
224         // m->RemoveNMRprotons();
225         if (tmpname.length() == 0) {
226             qDebug() << "Could not get InChI string!";
227         }
228         QMessageBox::information(r, tr("InChI string"),
229                                  tr("InChI string for selected molecule:") + "\n\n" + tmpname);
230         break;
231     case MODE_TOOL_CLEANUPMOL:
232         m->CleanUp();
233         break;
234     case MODE_TOOL_GROUP_REACTANT:
235         m->setGroupType(GROUP_REACTANT);
236         break;
237     case MODE_TOOL_GROUP_PRODUCT:
238         m->setGroupType(GROUP_PRODUCT);
239         break;
240     case MODE_TOOL_GROUP_CLEAR:
241         m->setGroupType(GROUP_NONE);
242         break;
243     case MODE_TOOL_TEST:
244         tool1.setMolecule(m);
245         tool1.exec();
246         break;
247     }
248     // Need to pick next tool manually
249 }
250 
Save3D(QString fn3d)251 void ChemData::Save3D(QString fn3d) {
252     // save 3D image of first molecule
253     Molecule *m = 0;
254 
255     for (Drawable *tmp_draw : drawlist) {
256         if (tmp_draw->Type() == TYPE_MOLECULE) {
257             m = (Molecule *)tmp_draw;
258             break;
259         }
260     }
261 
262     if (m != 0) {
263         m->Make3DVersion(fn3d);
264     } else {
265         qDebug() << "No molecule in input file!";
266     }
267 }
268 
returnFromMID()269 void ChemData::returnFromMID() {
270     Q_CHECK_PTR(mi);
271     Q_CHECK_PTR(tt_mw);
272     Q_CHECK_PTR(tt_ef);
273     Q_CHECK_PTR(tt_ea);
274     if (mi->isMWChecked())
275         drawlist.append(tt_mw);
276     if (mi->isEFChecked())
277         drawlist.append(tt_ef);
278     if (mi->isEAChecked())
279         drawlist.append(tt_ea);
280     mi->hide();
281     delete mi;
282 }
283 
clearAllGroups()284 void ChemData::clearAllGroups() {
285     Molecule *m = 0;
286     QString tmpname;
287 
288     for (Drawable *tmp_draw : drawlist) {
289         if (tmp_draw->Type() == TYPE_MOLECULE) {
290             m = (Molecule *)tmp_draw;
291             m->setGroupType(GROUP_NONE);
292         }
293     }
294 }
295 
296 // calculate molecular weights of Molecules
297 // AutoLayout
AutoLayout()298 void ChemData::AutoLayout() {
299     QList<LayoutGroup *> layout;
300     LayoutGroup *tmp_lo, *tl, *tr, *ta, *tb, *tl1;
301     int dista, distb, distl, distr, d1, d2, d3, d4, ds;
302     Text *tmp_text;
303     Arrow *tmp_arrow;
304     Drawable *td2;
305     Drawable *tmp_draw;
306 
307     // first, put Arrows and Molecules into LayoutGroups
308     for (Drawable *tmp_draw : drawlist) {
309         if (tmp_draw->Type() == TYPE_ARROW) {
310             tmp_lo = new LayoutGroup;
311             tmp_lo->items.append(tmp_draw);
312             tmp_lo->placed = false;
313             tmp_lo->left = 0;
314             tmp_lo->right = 0;
315             tmp_lo->above = 0;
316             tmp_lo->below = 0;
317             layout.append(tmp_lo);
318         }
319         if (tmp_draw->Type() == TYPE_MOLECULE) {
320             tmp_lo = new LayoutGroup;
321             tmp_lo->items.append(tmp_draw);
322             tmp_lo->placed = false;
323             tmp_lo->left = 0;
324             tmp_lo->right = 0;
325             tmp_lo->above = 0;
326             tmp_lo->below = 0;
327             layout.append(tmp_lo);
328         }
329     }
330     // now, attach Text to Arrows as needed
331     for (LayoutGroup *tmp_lo : layout) {
332         td2 = tmp_lo->items.first();
333         if (td2->Type() == TYPE_ARROW) {
334             tmp_arrow = (Arrow *)td2;
335             foreach (tmp_draw, drawlist) {
336                 if (tmp_draw->Type() == TYPE_TEXT) {
337                     tmp_text = (Text *)tmp_draw;
338                     int ns;
339                     QPoint amid = tmp_arrow->Midpoint();
340                     QPoint tcenter = tmp_text->NearestCenter(amid, tmp_arrow->Orientation(), ns);
341                     int dx = tcenter.x() - amid.x();
342                     int dy = tcenter.y() - amid.y();
343                     double dist = sqrt((double)(dx * dx + dy * dy));
344 
345                     qDebug() << dist;
346                     if (dist < 25) {
347                         if (tmp_arrow->Orientation() == ARROW_HORIZONTAL) {
348                             if (dy < 0) { // above arrow
349                                 dy = dy + 12;
350                                 tmp_text->ForceMove(-dx, -dy);
351                             } else { // below arrow
352                                 dy = dy - 12;
353                                 tmp_text->ForceMove(-dx, -dy);
354                             }
355                         } else {          // ARROW_VERTICAL
356                             if (dx < 0) { // above arrow
357                                 dx = dx + 12;
358                                 tmp_text->ForceMove(-dx, -dy);
359                             } else { // below arrow
360                                 dx = dx - 12;
361                                 tmp_text->ForceMove(-dx, -dy);
362                             }
363                         }
364                         tmp_lo->items.append(tmp_text); // add Text to LayoutGroup
365                     }                                   // if (dist...)
366                 }                                       // if (...TYPE_TEXT)
367             }                                           // for (...)
368         }                                               // if (...TYPE_ARROW)
369     }                                                   // for(...)
370     // Now determine position of LayoutGroups
371     for (LayoutGroup *tmp_lo : layout) {
372         QRect box = tmp_lo->BoundingBox();
373         QPoint l1(box.left(), box.center().y());
374         QPoint r1(box.right(), box.center().y());
375         QPoint a1(box.top(), box.center().x());
376         QPoint b1(box.bottom(), box.center().x());
377 
378         // check sides
379         dista = 9999;
380         distb = 9999;
381         distl = 9999;
382         distr = 9999;
383         ds = 9999;
384         tl = 0;
385         tr = 0;
386         ta = 0;
387         tb = 0;
388         foreach (tl1, layout) {
389             QRect box1 = tl1->BoundingBox();
390             QPoint l2(box1.left(), box1.center().y());
391             QPoint r2(box1.right(), box1.center().y());
392             QPoint a2(box1.top(), box1.center().x());
393             QPoint b2(box1.bottom(), box1.center().x());
394 
395             d1 = (int)(r->DistanceBetween(l1, r2));
396             d2 = (int)(r->DistanceBetween(r1, l2));
397             d3 = (int)(r->DistanceBetween(a1, b2));
398             d4 = (int)(r->DistanceBetween(b1, a2));
399             if (d1 < ds)
400                 ds = d1;
401             if (d2 < ds)
402                 ds = d2;
403             if (d3 < ds)
404                 ds = d3;
405             if (d4 < ds)
406                 ds = d4;
407             if (d1 == ds)
408                 tl = tl1;
409             if (d2 == ds)
410                 tr = tl1;
411             if (d3 == ds)
412                 ta = tl1;
413             if (d4 == ds)
414                 tb = tl1;
415         }
416         if (tl != 0) {
417             qDebug() << "left";
418             tl->right = tmp_lo;
419             tmp_lo->left = tl;
420         }
421         if (tr != 0) {
422             qDebug() << "right";
423             tr->left = tmp_lo;
424             tmp_lo->right = tr;
425         }
426         if (ta != 0) {
427             qDebug() << "above";
428             ta->below = tmp_lo;
429             tmp_lo->above = ta;
430         }
431         if (tb != 0) {
432             qDebug() << "below";
433             tb->above = tmp_lo;
434             tmp_lo->below = tb;
435         }
436         qDebug();
437     }
438     // Place everything
439     // Start with things near arrows
440     for (LayoutGroup *tmp_lo : layout) {
441         if (tmp_lo->items.first()->Type() == TYPE_ARROW) {
442             tmp_lo->placed = true;
443             tmp_arrow = (Arrow *)(tmp_lo->items.first());
444             if (tmp_arrow->Orientation() == ARROW_HORIZONTAL) {
445                 // adjust position according to already placed Molecule or Arrow
446                 if (tmp_lo->left != 0) {
447                     if (tmp_lo->left->placed == true) {
448                         int dy = tmp_lo->Center().y() - tmp_lo->left->Center().y();
449 
450                         tmp_lo->Move(0, -dy);
451                     }
452                 }
453                 if (tmp_lo->right != 0) {
454                     if (tmp_lo->right->placed == true) {
455                         int dy = tmp_lo->Center().y() - tmp_lo->right->Center().y();
456 
457                         tmp_lo->Move(0, -dy);
458                     }
459                 }
460                 if (tmp_lo->left != 0) {
461                     if (tmp_lo->left->placed == false) {
462                         int dy = tmp_lo->left->Center().y() - tmp_lo->Center().y();
463 
464                         tmp_lo->left->Move(0, -dy);
465                         tmp_lo->left->placed = true;
466                     }
467                 }
468                 if (tmp_lo->right != 0) {
469                     if (tmp_lo->right->placed == false) {
470                         int dy = tmp_lo->right->Center().y() - tmp_lo->Center().y();
471 
472                         tmp_lo->right->Move(0, -dy);
473                         tmp_lo->right->placed = true;
474                     }
475                 }
476             } else { // ARROW_VERTICAL
477                 // adjust position according to already placed Molecule or Arrow
478                 if (tmp_lo->above != 0) {
479                     if (tmp_lo->above->placed == true) {
480                         int dx = tmp_lo->Center().y() - tmp_lo->above->Center().y();
481 
482                         tmp_lo->Move(-dx, 0);
483                     }
484                 }
485                 if (tmp_lo->below != 0) {
486                     if (tmp_lo->below->placed == true) {
487                         int dx = tmp_lo->Center().x() - tmp_lo->below->Center().x();
488 
489                         tmp_lo->Move(-dx, 0);
490                     }
491                 }
492                 if (tmp_lo->above != 0) {
493                     if (tmp_lo->above->placed == false) {
494                         int dx = tmp_lo->above->Center().x() - tmp_lo->Center().x();
495 
496                         tmp_lo->above->Move(-dx, 0);
497                         tmp_lo->above->placed = true;
498                     }
499                 }
500                 if (tmp_lo->below != 0) {
501                     if (tmp_lo->below->placed == false) {
502                         int dx = tmp_lo->below->Center().x() - tmp_lo->Center().x();
503 
504                         tmp_lo->below->Move(-dx, 0);
505                         tmp_lo->below->placed = true;
506                     }
507                 }
508             } // if (tmp_arrow...)
509         }     // if (...TYPE_ARROW)
510     }         // for (...)
511 }
512 
fromSMILES(QString sm)513 void ChemData::fromSMILES(QString sm) {
514     Molecule *m1 = new Molecule(r);
515 
516     m1->FromSMILES(sm);
517     m1->SelectAll();
518     drawlist.append(m1);
519 }
520 
SmartPlace(QString sf,DPoint * t1)521 void ChemData::SmartPlace(QString sf, DPoint *t1) {
522 
523     if (sf.contains("cyclopentadiene") > 0)
524         sf.replace(QRegExp("diene"), "diene-sp");
525     double ang1 = -CalculateRingAttachAngle(t1) + 1.5708;
526 
527     load(sf);
528     Drawable *tmp_draw = drawlist.last();
529     Molecule *m1 = (Molecule *)tmp_draw;
530 
531     if (fabs(ang1) < 0.1) {
532         ang1 = 3.14159;
533     } else {
534         if (fabs(ang1) > 3.13) {
535             ang1 = 0.0;
536         }
537     }
538     qDebug() << "angle = " << (ang1 * 180.0 / 3.14159) << " degrees!";
539     DPoint *tmp_pt = m1->GetRingAttachPoint();
540     m1->Rotate(ang1);
541     double dx, dy;
542 
543     dx = t1->x - tmp_pt->x;
544     dy = t1->y - tmp_pt->y;
545     m1->Move(dx, dy);
546     QList<DPoint *> nb = m1->BreakRingBonds(tmp_pt);
547     foreach (tmp_pt, nb) {
548         addBond(tmp_pt, t1, 1, tmp_pt->new_order, QColor(0, 0, 0), true);
549         qDebug() << "added a bond";
550     }
551 }
552 
SmartPlaceToo(QString sf,DPoint * t1)553 void ChemData::SmartPlaceToo(QString sf, DPoint *t1) {
554     double ang1 = -CalculateRingAttachAngle(t1) + 3.14159;
555 
556     load(sf);
557     Drawable *tmp_draw = drawlist.last();
558     Molecule *m1 = (Molecule *)tmp_draw;
559 
560     qDebug() << "angle = " << (ang1 * 180.0 / 3.14159) << " degrees!";
561     // tmp_pt = m1->GetRingAttachPoint();
562     DPoint *tmp_pt = m1->GetAttachPoint(sf);
563     m1->Rotate(ang1);
564     double dx, dy;
565 
566     dx = t1->x - tmp_pt->x;
567     dy = t1->y - tmp_pt->y;
568     m1->Move(dx, dy);
569     QList<DPoint *> nb = m1->BreakRingBonds(tmp_pt);
570     for (DPoint *tmp_pt : nb) {
571         addBond(tmp_pt, t1, 1, tmp_pt->new_order, QColor(0, 0, 0), true);
572         qDebug() << "added a bond";
573     }
574     // need to put back N if EDANS
575     if (sf.contains("edans") > 0) {
576         t1->element = "NH";
577         Text *nt = new Text(r);
578 
579         nt->setPoint(t1);
580         nt->setJustify(JUSTIFY_CENTER);
581         nt->setText("NH");
582         //        nt->setTextMask( "  " );
583         addText(nt);
584     }
585 }
586 
SmartPlaceThree(QString sf,DPoint * t1)587 void ChemData::SmartPlaceThree(QString sf, DPoint *t1) {
588     double ang1 = -CalculateRingAttachAngle(t1);
589 
590     load(sf);
591     Drawable *tmp_draw = drawlist.last();
592     Molecule *m1 = (Molecule *)tmp_draw;
593 
594     qDebug() << "angle = " << (ang1 * 180.0 / 3.14159) << " degrees!";
595     // tmp_pt = m1->GetRingAttachPoint();
596     DPoint *tmp_pt = m1->GetAttachPoint(sf);
597     m1->Rotate(ang1);
598     double dx, dy;
599 
600     dx = t1->x - tmp_pt->x;
601     dy = t1->y - tmp_pt->y;
602     m1->Move(dx, dy);
603     QList<DPoint *> nb = m1->BreakRingBonds(tmp_pt);
604     for (DPoint *tmp_pt : nb) {
605         addBond(tmp_pt, t1, 1, tmp_pt->new_order, QColor(0, 0, 0), true);
606         qDebug() << "added a bond";
607     }
608     // need to put back N
609     t1->element = "NH";
610     Text *nt = new Text(r);
611 
612     nt->setPoint(t1);
613     nt->setJustify(JUSTIFY_CENTER);
614     nt->setText("NH");
615     //    nt->setTextMask( "  " );
616     addText(nt);
617 }
618 
CalculateRingAttachAngle(DPoint * t1)619 double ChemData::CalculateRingAttachAngle(DPoint *t1) {
620     double a1;
621     Molecule *m = 0;
622 
623     for (Drawable *tmp_draw : drawlist) {
624         if ((tmp_draw->Type() == TYPE_MOLECULE) && (tmp_draw->Find(t1) == true)) {
625             m = (Molecule *)tmp_draw;
626             break;
627         }
628     }
629     if (m == 0)
630         return 0.0;
631 
632     a1 = m->CalculateRingAttachAngle(t1);
633 
634     return a1;
635 }
636 
637 // Implemented using Crossing Number Algorithm
SelectWithinLoop(QVector<QPoint> curr_lasso)638 bool ChemData::SelectWithinLoop(QVector<QPoint> curr_lasso) {
639 
640     int count;
641     bool retval = false; // Were any selectable Drawables found?
642 
643     QList<Drawable *> obj_list = UniqueObjects();
644 
645     for (Drawable *tmp_draw : obj_list) {
646         count = 0;
647 
648         QPointF center;
649 
650         // Get center of object
651         if (tmp_draw->End()) {
652             center = r->Midpoint(tmp_draw->Start()->toQPoint(), tmp_draw->End()->toQPoint());
653         } else {
654             center = tmp_draw->Start()->toQPoint();
655         }
656 
657         // Count number of times lasso passes through left of center
658         for (int i = 0; i < curr_lasso.size() - 1; ++i) {
659             count +=
660                 ((curr_lasso.at(i).y() < center.y()) ^ (curr_lasso.at(i + 1).y() < center.y())) &
661                 (curr_lasso.at(i).x() < center.x());
662         }
663 
664         // Odd count -> Drawable is inside
665         if (count & 1) {
666             retval = true;
667             tmp_draw->Highlight(true);
668         }
669     }
670 
671     return retval;
672 }
673