ccGraphicalTransformationTool.cpp 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115
  1. //##########################################################################
  2. //# #
  3. //# CLOUDCOMPARE #
  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; version 2 or later of the License. #
  8. //# #
  9. //# This program is distributed in the hope that it will be useful, #
  10. //# but WITHOUT ANY WARRANTY; without even the implied warranty of #
  11. //# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
  12. //# GNU General Public License for more details. #
  13. //# #
  14. //# COPYRIGHT: EDF R&D / TELECOM ParisTech (ENST-TSI) #
  15. //# #
  16. //##########################################################################
  17. #include "ccGraphicalTransformationTool.h"
  18. #include "mainwindow.h"
  19. #include <ccGLUtils.h>
  20. #include <ccGLWindowInterface.h>
  21. //qCC_db
  22. #include <ccLog.h>
  23. #include <ccMesh.h>
  24. #include <ccPolyline.h>
  25. #include <ccPlane.h>
  26. #include <ccCoordinateSystem.h>
  27. #include <ccDBRoot.h>
  28. ccGraphicalTransformationTool::ccGraphicalTransformationTool(QWidget* parent)
  29. : ccOverlayDialog(parent)
  30. , Ui::GraphicalTransformationDlg()
  31. , m_toTransform("transformed")
  32. {
  33. setupUi(this);
  34. rotComboBox->clear();
  35. rotComboBox->insertItem(0, "XYZ", rotComboBoxItems::XYZ);
  36. rotComboBox->insertItem(1, "X", rotComboBoxItems::X);
  37. rotComboBox->insertItem(2, "Y", rotComboBoxItems::Y);
  38. rotComboBox->insertItem(3, "Z", rotComboBoxItems::Z);
  39. rotComboBox->insertItem(4, "None", rotComboBoxItems::NONE);
  40. rotComboBox->setCurrentIndex(rotComboBoxItems::XYZ);
  41. connect(pauseButton, &QAbstractButton::toggled, this, &ccGraphicalTransformationTool::pause);
  42. connect(okButton, &QAbstractButton::clicked, this, &ccGraphicalTransformationTool::apply);
  43. connect(razButton, &QAbstractButton::clicked, this, &ccGraphicalTransformationTool::reset);
  44. connect(cancelButton, &QAbstractButton::clicked, this, &ccGraphicalTransformationTool::cancel);
  45. connect(TxCheckBox, &QCheckBox::clicked, this, &ccGraphicalTransformationTool::incrementalTranslationToggle);
  46. connect(TyCheckBox, &QCheckBox::clicked, this, &ccGraphicalTransformationTool::incrementalTranslationToggle);
  47. connect(TzCheckBox, &QCheckBox::clicked, this, &ccGraphicalTransformationTool::incrementalTranslationToggle);
  48. connect(advPushButton, &QPushButton::toggled, this, &ccGraphicalTransformationTool::advModeToggle);
  49. connect(refAxisRadio, &QRadioButton::toggled, this, &ccGraphicalTransformationTool::advRefAxisRadioToggled);
  50. connect(objCenterRadio, &QRadioButton::toggled, this, &ccGraphicalTransformationTool::advObjectAxisRadioToggled);
  51. connect(advTranslateComboBox, qOverload<int>(&QComboBox::currentIndexChanged), this, &ccGraphicalTransformationTool::advTranslateRefUpdate);
  52. connect(advRotateComboBox, qOverload<int>(&QComboBox::currentIndexChanged), this, &ccGraphicalTransformationTool::advRotateRefUpdate);
  53. connect(rotComboBox, qOverload<int>(&QComboBox::activated), this, &ccGraphicalTransformationTool::advRotateComboBoxUpdate);
  54. connect(incrementalForwardButton, &QAbstractButton::clicked, this, &ccGraphicalTransformationTool::incrementalTransform);
  55. connect(incrementalBackwardButton, &QAbstractButton::clicked, this, &ccGraphicalTransformationTool::incrementalTransform);
  56. //add shortcuts
  57. addOverriddenShortcut(Qt::Key_Space); //space bar for the "pause" button
  58. addOverriddenShortcut(Qt::Key_Escape); //escape key for the "cancel" button
  59. addOverriddenShortcut(Qt::Key_Return); //return key for the "ok" button
  60. connect(this, &ccOverlayDialog::shortcutTriggered, this, &ccGraphicalTransformationTool::onShortcutTriggered);
  61. objCenterRadio->setChecked(true);
  62. advModeToggle(false);
  63. }
  64. ccGraphicalTransformationTool::~ccGraphicalTransformationTool()
  65. {
  66. clear();
  67. }
  68. void ccGraphicalTransformationTool::onShortcutTriggered(int key)
  69. {
  70. switch(key)
  71. {
  72. case Qt::Key_Space:
  73. pauseButton->toggle();
  74. return;
  75. case Qt::Key_Return:
  76. okButton->click();
  77. return;
  78. case Qt::Key_Escape:
  79. cancelButton->click();
  80. return;
  81. default:
  82. //nothing to do
  83. break;
  84. }
  85. }
  86. void ccGraphicalTransformationTool::pause(bool state)
  87. {
  88. if (!m_associatedWin)
  89. {
  90. return;
  91. }
  92. if (state)
  93. {
  94. m_associatedWin->setInteractionMode(ccGLWindowInterface::MODE_TRANSFORM_CAMERA);
  95. m_associatedWin->displayNewMessage("Transformation [PAUSED]", ccGLWindowInterface::UPPER_CENTER_MESSAGE, false, 3600, ccGLWindowInterface::MANUAL_TRANSFORMATION_MESSAGE);
  96. m_associatedWin->displayNewMessage("Unpause to transform again", ccGLWindowInterface::UPPER_CENTER_MESSAGE, true, 3600, ccGLWindowInterface::MANUAL_TRANSFORMATION_MESSAGE);
  97. }
  98. else
  99. {
  100. m_associatedWin->setInteractionMode(ccGLWindowInterface::MODE_TRANSFORM_ENTITIES);
  101. updateDisplayMessage();
  102. }
  103. //update mini-GUI
  104. pauseButton->blockSignals(true);
  105. pauseButton->setChecked(state);
  106. pauseButton->blockSignals(false);
  107. m_associatedWin->redraw(false, false); //we have to redraw the 3D layer for labels!
  108. }
  109. void ccGraphicalTransformationTool::advModeToggle(bool state)
  110. {
  111. advRotateComboBox->setVisible(state);
  112. advTranslateComboBox->setVisible(state);
  113. translateLabel->setVisible(state);
  114. rotateLabel->setVisible(state);
  115. rotAxisLabel->setVisible(state);
  116. objCenterRadio->setVisible(state);
  117. refAxisRadio->setVisible(state);
  118. incrementalRotLabel->setVisible(state);
  119. incrementalRotSpin->setVisible(state);
  120. incrementalTransLabel->setVisible(state);
  121. incrementalTransSpin->setVisible(state);
  122. incrementalForwardButton->setVisible(state);
  123. incrementalBackwardButton->setVisible(state);
  124. IncrementalTransformLabel->setVisible(state);
  125. m_advMode = state;
  126. int wPrev = this->width();
  127. if (state)
  128. {
  129. this->setGeometry(this->x() + (-wPrev + 250), this->y(), 250, 235);
  130. if (advTranslateComboBox->currentIndex() != 0)
  131. {
  132. TxCheckBox->setEnabled(false);
  133. TyCheckBox->setEnabled(false);
  134. }
  135. advRotateRefUpdate(advRotateComboBox->currentIndex());
  136. advTranslateRefUpdate(advTranslateComboBox->currentIndex());
  137. }
  138. else
  139. {
  140. TxCheckBox->setEnabled(true);
  141. TyCheckBox->setEnabled(true);
  142. this->setGeometry(this->x() , this->y(), 0, 0);
  143. this->adjustSize(); //adjust size will minimize the display height with the dropdowns not visible
  144. this->setGeometry(this->x() + (wPrev - 250), this->y(), 250, this->height());
  145. advRotateComboBox->setCurrentIndex(0); //index 0 is always the origin
  146. advTranslateComboBox->setCurrentIndex(0); //index 0 is always the origin
  147. }
  148. //update mini-GUI
  149. advPushButton->blockSignals(true);
  150. advPushButton->setChecked(state);
  151. advPushButton->blockSignals(false);
  152. updateDisplayMessage();
  153. }
  154. void ccGraphicalTransformationTool::populateAdvModeItems()
  155. {
  156. advRotateComboBox->clear();
  157. advTranslateComboBox->clear();
  158. advRotateComboBox->insertItem(0, "Origin");
  159. advTranslateComboBox->insertItem(0, "Origin");
  160. MainWindow* mainWindow = MainWindow::TheInstance();
  161. if (mainWindow)
  162. {
  163. ccHObject* root = mainWindow->dbRootObject();
  164. ccHObject::Container polylines;
  165. ccHObject::Container coordinateSystems;
  166. if (root)
  167. {
  168. root->filterChildren(polylines, true, CC_TYPES::POLY_LINE);
  169. root->filterChildren(coordinateSystems, true, CC_TYPES::COORDINATESYSTEM);
  170. root->filterChildren(m_advancedModeObjectList, true, CC_TYPES::PLANE);
  171. }
  172. if (!polylines.empty())
  173. {
  174. for (size_t i = 0; i < polylines.size(); i++)
  175. {
  176. ccPolyline* poly = static_cast<ccPolyline*>(polylines[i]);
  177. if (poly->size() == 2) //only single segment polylines allowed
  178. {
  179. m_advancedModeObjectList.push_back(polylines[i]);
  180. }
  181. }
  182. }
  183. if (!coordinateSystems.empty())
  184. {
  185. for (size_t i = 0; i < coordinateSystems.size(); i++)
  186. {
  187. m_advancedModeObjectList.push_back(coordinateSystems[i]);
  188. }
  189. }
  190. if (!m_advancedModeObjectList.empty())
  191. {
  192. for (size_t i = 0; i < m_advancedModeObjectList.size(); ++i)
  193. {
  194. QString item = QString("%1 (ID=%2)").arg(m_advancedModeObjectList[i]->getName()).arg(m_advancedModeObjectList[i]->getUniqueID());
  195. advTranslateComboBox->insertItem(static_cast<int>(i) + 1, item, QVariant(m_advancedModeObjectList[i]->getUniqueID()));
  196. advRotateComboBox->insertItem(static_cast<int>(i) + 1, item, QVariant(m_advancedModeObjectList[i]->getUniqueID()));
  197. }
  198. }
  199. }
  200. }
  201. ccGLMatrixd ccGraphicalTransformationTool::arbitraryVectorTranslation(const CCVector3& vec)
  202. {
  203. double theta = 0;
  204. if (CCCoreLib::LessThanEpsilon(std::abs(vec.z)))
  205. {
  206. if (CCCoreLib::LessThanEpsilon(std::abs(vec.y)))
  207. {
  208. theta = 0;
  209. }
  210. else if (vec.y < 0)
  211. {
  212. theta = -M_PI_2; //atan of -infinity is -pi/2
  213. }
  214. else
  215. {
  216. theta = M_PI_2; //atan of +infinity is pi/2
  217. }
  218. }
  219. else
  220. {
  221. theta = std::atan(vec.y / vec.z);
  222. if (vec.y < 0 && vec.z < 0)
  223. {
  224. theta = theta - M_PI;
  225. }
  226. else if (vec.z < 0 && vec.y > 0)
  227. {
  228. theta = M_PI + theta;
  229. }
  230. }
  231. double phiDenominator = std::sqrt((vec.y * vec.y) + (vec.z * vec.z));
  232. double phi = 0;
  233. if (CCCoreLib::LessThanEpsilon(phiDenominator))
  234. {
  235. if (CCCoreLib::LessThanEpsilon(std::abs(vec.x)))
  236. {
  237. phi = 0;
  238. }
  239. else if (vec.x < 0)
  240. {
  241. phi = -M_PI_2; //atan of -infinity is -pi/2
  242. }
  243. else
  244. {
  245. phi = M_PI_2; //atan of +infinity is pi/2
  246. }
  247. }
  248. else
  249. {
  250. phi = std::atan(vec.x / phiDenominator);
  251. }
  252. ccGLMatrixd xRotation = ccGLMatrixd();
  253. xRotation.setColumn(1, CCVector3d(0, std::cos(theta), -std::sin(theta)));
  254. xRotation.setColumn(2, CCVector3d(0, std::sin(theta), std::cos(theta)));
  255. ccGLMatrixd yRotation = ccGLMatrixd();
  256. yRotation.setColumn(0, CCVector3d(std::cos(phi), 0, -std::sin(phi)));
  257. yRotation.setColumn(2, CCVector3d(std::sin(phi), 0, std::cos(phi)));
  258. ccGLMatrixd arbitraryVectorTranslationAdjust = xRotation * yRotation;
  259. //special case
  260. if (CCCoreLib::LessThanEpsilon(std::abs(vec.x)) && CCCoreLib::LessThanEpsilon(std::abs(vec.y)) && vec.z < 0)
  261. {
  262. arbitraryVectorTranslationAdjust.scaleRotation(-1);
  263. }
  264. return arbitraryVectorTranslationAdjust;
  265. }
  266. ccGLMatrixd ccGraphicalTransformationTool::arbitraryVectorRotation(double angle, const CCVector3d& arbitraryVector)
  267. {
  268. // advRotationTransform = (cos(theta)*I) + ((1-cos(theta)*u) (X) u) + (sin(theta)*u_skewsym)
  269. // (X) represents tensor product
  270. // Reference: Ch 4.7.3 in Geometric Tools for Computer Graphics - P. Schneider & D. Eberly
  271. double cosTheta = std::cos(angle);
  272. double sinTheta = std::sin(angle);
  273. ccGLMatrixd firstTerm = ccGLMatrixd();
  274. firstTerm.scaleRotation(cosTheta);
  275. ccGLMatrixd secondTerm = ccGLMatrixd();
  276. CCVector3d v = (1 - cosTheta) * arbitraryVector;
  277. CCVector3d w = arbitraryVector;
  278. secondTerm.setColumn(0, CCVector3d(v[0] * w[0], v[1] * w[0], v[2] * w[0]));
  279. secondTerm.setColumn(1, CCVector3d(v[0] * w[1], v[1] * w[1], v[2] * w[1]));
  280. secondTerm.setColumn(2, CCVector3d(v[0] * w[2], v[1] * w[2], v[2] * w[2]));
  281. ccGLMatrixd thirdTerm = ccGLMatrixd();
  282. thirdTerm.setColumn(0, CCVector3d(0, arbitraryVector[2], -arbitraryVector[1]));
  283. thirdTerm.setColumn(1, CCVector3d(-arbitraryVector[2], 0, arbitraryVector[0]));
  284. thirdTerm.setColumn(2, CCVector3d(arbitraryVector[1], -arbitraryVector[0], 0));
  285. thirdTerm.scaleRotation(sinTheta);
  286. ccGLMatrixd advRotationTransform = firstTerm;
  287. advRotationTransform += secondTerm;
  288. advRotationTransform.scaleRow(3, .5);
  289. advRotationTransform += thirdTerm;
  290. advRotationTransform.scaleRow(3, .5);
  291. return advRotationTransform;
  292. }
  293. bool ccGraphicalTransformationTool::setAdvTranslationTransform(ccHObject* translateRef)
  294. {
  295. if (!m_associatedWin)
  296. {
  297. assert(false);
  298. return false;
  299. }
  300. if (translateRef == nullptr)
  301. {
  302. return false;
  303. }
  304. if (translateRef->isA(CC_TYPES::POLY_LINE))
  305. {
  306. ccPolyline* line = static_cast<ccPolyline*>(translateRef);
  307. CCVector3 arbitraryVec = *line->getPoint(1) - *line->getPoint(0);
  308. m_advTranslationTransform = arbitraryVectorTranslation(arbitraryVec);
  309. TxCheckBox->setChecked(false);
  310. TyCheckBox->setChecked(false);
  311. TxCheckBox->setEnabled(false);
  312. TyCheckBox->setEnabled(false);
  313. return true;
  314. }
  315. else if (translateRef->isA(CC_TYPES::PLANE))
  316. {
  317. ccPlane* plane = static_cast<ccPlane*>(translateRef);
  318. m_advTranslationTransform = ccGLMatrixd(plane->getTransformation().data());
  319. TxCheckBox->setEnabled(true);
  320. TyCheckBox->setEnabled(true);
  321. return true;
  322. }
  323. else if (translateRef->isA(CC_TYPES::COORDINATESYSTEM))
  324. {
  325. ccCoordinateSystem* cs = static_cast<ccCoordinateSystem*>(translateRef);
  326. m_advTranslationTransform = ccGLMatrixd(cs->getTransformation().data());
  327. TxCheckBox->setEnabled(true);
  328. TyCheckBox->setEnabled(true);
  329. return true;
  330. }
  331. else
  332. {
  333. advTranslateComboBox->setCurrentIndex(0);
  334. TxCheckBox->setEnabled(true);
  335. TyCheckBox->setEnabled(true);
  336. return false;
  337. }
  338. }
  339. bool ccGraphicalTransformationTool::setAdvRotationAxis(ccHObject* rotateRef, rotComboBoxItems selectedAxis)
  340. {
  341. if (!m_associatedWin || !rotateRef)
  342. {
  343. assert(false);
  344. return false;
  345. }
  346. CCVector3d newCenter;
  347. CCVector3d arbitraryVec;
  348. if (rotateRef->isA(CC_TYPES::POLY_LINE))
  349. {
  350. ccPolyline* line = static_cast<ccPolyline*>(rotateRef);
  351. CCVector3d end = *line->getPoint(1);
  352. CCVector3d start = *line->getPoint(0);
  353. arbitraryVec = end - start;
  354. rotComboBox->clear();
  355. rotComboBox->insertItem(0, "Z", rotComboBoxItems::Z);
  356. rotComboBox->insertItem(1, "None", rotComboBoxItems::NONE);
  357. rotComboBox->setCurrentIndex(rotComboBoxItems::Z);
  358. incrementalRotationToggle(rotComboBoxItems::Z);
  359. m_advRotationRefObjCenter = (start + end) / 2;
  360. arbitraryVec.normalize();
  361. }
  362. else if (rotateRef->isA(CC_TYPES::PLANE))
  363. {
  364. ccPlane* plane = static_cast<ccPlane*>(rotateRef);
  365. arbitraryVec = plane->getNormal();
  366. rotComboBox->clear();
  367. rotComboBox->insertItem(0, "Z", rotComboBoxItems::Z);
  368. rotComboBox->insertItem(1, "None", rotComboBoxItems::NONE);
  369. rotComboBox->setCurrentIndex(rotComboBoxItems::Z);
  370. incrementalRotationToggle(rotComboBoxItems::Z);
  371. m_advRotationRefObjCenter = plane->getCenter();
  372. }
  373. else if (rotateRef->isA(CC_TYPES::COORDINATESYSTEM))
  374. {
  375. ccCoordinateSystem* cs = static_cast<ccCoordinateSystem*>(rotateRef);
  376. switch (selectedAxis)
  377. {
  378. case rotComboBoxItems::X:
  379. {
  380. arbitraryVec = cs->getYZPlaneNormal();
  381. break;
  382. }
  383. case rotComboBoxItems::Y:
  384. {
  385. arbitraryVec = cs->getZXPlaneNormal();
  386. break;
  387. }
  388. case rotComboBoxItems::Z:
  389. default:
  390. {
  391. selectedAxis = rotComboBoxItems::Z;
  392. arbitraryVec = cs->getXYPlaneNormal();
  393. break;
  394. }
  395. }
  396. rotComboBox->clear();
  397. rotComboBox->insertItem(0, "X", rotComboBoxItems::X);
  398. rotComboBox->insertItem(1, "Y", rotComboBoxItems::Y);
  399. rotComboBox->insertItem(2, "Z", rotComboBoxItems::Z);
  400. rotComboBox->insertItem(3, "None", rotComboBoxItems::NONE);
  401. rotComboBox->setCurrentIndex(rotComboBoxItems::Z);
  402. incrementalRotationToggle(rotComboBoxItems::Z);
  403. m_advRotationRefObjCenter = cs->getOrigin();
  404. }
  405. else //Not a supported primitive for rotateRef
  406. {
  407. CCVector3d newCenter = m_toTransform.getBB_recursive().getCenter();
  408. setRotationCenter(newCenter);
  409. advRotateComboBox->setCurrentIndex(0);
  410. return false;
  411. }
  412. if (rotComboBox->findData(selectedAxis) == -1)
  413. {
  414. rotComboBox->setCurrentIndex(rotComboBox->findData(rotComboBoxItems::Z)); // Default to Z axis if passed an invalid axis selection
  415. }
  416. else
  417. {
  418. rotComboBox->setCurrentIndex(rotComboBox->findData(selectedAxis));
  419. }
  420. if (refAxisRadio->isChecked())
  421. {
  422. if (m_advRotateRefIsChild)
  423. {
  424. newCenter = m_advRotationRefObjCenter;
  425. m_position.applyRotation(arbitraryVec);
  426. }
  427. else
  428. {
  429. newCenter = (m_rotation.inverse() * m_advRotationRefObjCenter - m_rotation.inverse() * m_position.getTranslationAsVec3D());
  430. }
  431. }
  432. else if (objCenterRadio->isChecked())
  433. {
  434. if (m_advRotateRefIsChild)
  435. {
  436. m_position.applyRotation(arbitraryVec);
  437. }
  438. newCenter = m_toTransform.getBB_recursive().getCenter();
  439. }
  440. m_advRotationAxis = m_rotation.inverse() * arbitraryVec;
  441. setRotationCenter(newCenter);
  442. return true;
  443. }
  444. bool ccGraphicalTransformationTool::entityInTransformList(ccHObject* entity)
  445. {
  446. for (unsigned j = 0; j < m_toTransform.getChildrenNumber(); j++)
  447. {
  448. if (entity == m_toTransform.getChild(j) || m_toTransform.getChild(j)->isAncestorOf(entity))
  449. {
  450. return true;
  451. }
  452. }
  453. return false;
  454. }
  455. void ccGraphicalTransformationTool::advTranslateRefUpdate(int index)
  456. {
  457. if (index == 0 || m_advancedModeObjectList.empty()) // index 0 is always the origin
  458. {
  459. TxCheckBox->setEnabled(true);
  460. TyCheckBox->setEnabled(true);
  461. m_advTranslationTransform.toIdentity();
  462. MainWindow* mainWindow = MainWindow::TheInstance();
  463. if (mainWindow && m_advTranslateRef != nullptr)
  464. {
  465. mainWindow->db()->unselectEntity(m_advTranslateRef);
  466. m_advTranslateRef = nullptr;
  467. }
  468. return;
  469. }
  470. int id = advTranslateComboBox->itemData(index).toInt();
  471. for (size_t i = 0; i < m_advancedModeObjectList.size(); i++)
  472. {
  473. if (id == m_advancedModeObjectList[i]->getUniqueID())
  474. {
  475. MainWindow* mainWindow = MainWindow::TheInstance();
  476. if (mainWindow)
  477. {
  478. if (m_advTranslateRef != nullptr && m_advTranslateRef != m_advRotateRef) //leave selected if rotate ref
  479. {
  480. mainWindow->db()->unselectEntity(m_advTranslateRef);
  481. }
  482. m_advTranslateRef = m_advancedModeObjectList[i];
  483. m_advTranslateRefIsChild = entityInTransformList(m_advTranslateRef);
  484. if (m_advTranslateRef != m_advRotateRef) // already selected
  485. {
  486. mainWindow->db()->selectEntity(m_advTranslateRef, true);
  487. }
  488. }
  489. if (!setAdvTranslationTransform(m_advTranslateRef))
  490. {
  491. ccLog::Error("Error calculating adv translation transform, cannot translate along selected item");
  492. advTranslateComboBox->setCurrentIndex(0);
  493. }
  494. return;
  495. }
  496. }
  497. ccLog::Error("Error finding the selected object in DB Tree, cannot translate along selected object");
  498. advTranslateComboBox->setCurrentIndex(0);
  499. }
  500. void ccGraphicalTransformationTool::advRotateComboBoxUpdate(int index)
  501. {
  502. rotComboBoxItems selectedAxis = static_cast<rotComboBoxItems>(rotComboBox->itemData(index).toInt());
  503. incrementalRotationToggle(selectedAxis);
  504. if (!m_advMode || !m_advRotateRef)
  505. {
  506. return;
  507. }
  508. if (selectedAxis == rotComboBoxItems::NONE)
  509. {
  510. return;
  511. }
  512. if (!setAdvRotationAxis(m_advRotateRef, selectedAxis))
  513. {
  514. ccLog::Error("Error setting adv rotation axis, cannot rotate around selected item");
  515. advRotateComboBox->setCurrentIndex(0);
  516. }
  517. }
  518. void ccGraphicalTransformationTool::advRotateRefUpdate(int index)
  519. {
  520. if (index == 0 || m_advancedModeObjectList.empty()) // index 0 is always the origin
  521. {
  522. if (m_advRotateRef != nullptr)
  523. {
  524. rotComboBox->clear();
  525. rotComboBox->insertItem(0, "XYZ", rotComboBoxItems::XYZ);
  526. rotComboBox->insertItem(1, "X", rotComboBoxItems::X);
  527. rotComboBox->insertItem(2, "Y", rotComboBoxItems::Y);
  528. rotComboBox->insertItem(3, "Z", rotComboBoxItems::Z);
  529. rotComboBox->insertItem(4, "None", rotComboBoxItems::NONE);
  530. rotComboBox->setCurrentIndex(rotComboBoxItems::Z);
  531. incrementalRotationToggle(rotComboBoxItems::Z);
  532. }
  533. CCVector3d center = m_toTransform.getBB_recursive().getCenter();
  534. setRotationCenter(center);
  535. m_advRotationRefObjCenter = CCVector3d(0, 0, 0);
  536. m_advRotationAxis = CCVector3d(0, 0, 1);
  537. objCenterRadio->setEnabled(true);
  538. objCenterRadio->setChecked(true);
  539. refAxisRadio->setEnabled(false);
  540. MainWindow* mainWindow = MainWindow::TheInstance();
  541. if (mainWindow && m_advRotateRef != nullptr)
  542. {
  543. mainWindow->db()->unselectEntity(m_advRotateRef);
  544. m_advRotateRef = nullptr;
  545. }
  546. return;
  547. }
  548. int id = advRotateComboBox->itemData(index).toInt();
  549. for (size_t i = 0; i < m_advancedModeObjectList.size(); i++)
  550. {
  551. if (id == m_advancedModeObjectList[i]->getUniqueID())
  552. {
  553. MainWindow* mainWindow = MainWindow::TheInstance();
  554. if (mainWindow)
  555. {
  556. if (m_advRotateRef != nullptr && m_advTranslateRef != m_advRotateRef)//leave selected if translate ref
  557. {
  558. mainWindow->db()->unselectEntity(m_advRotateRef);
  559. }
  560. m_advRotateRef = m_advancedModeObjectList[i];
  561. if (m_advTranslateRef != m_advRotateRef) // already selected
  562. {
  563. mainWindow->db()->selectEntity(m_advRotateRef, true);
  564. }
  565. refAxisRadio->setEnabled(true);
  566. m_advRotateRefIsChild = entityInTransformList(m_advRotateRef);
  567. if (m_advRotateRefIsChild)
  568. {
  569. refAxisRadio->setChecked(true);
  570. objCenterRadio->setEnabled(false);
  571. }
  572. else
  573. {
  574. objCenterRadio->setEnabled(true);
  575. }
  576. }
  577. if (!setAdvRotationAxis(m_advRotateRef, static_cast<rotComboBoxItems>(rotComboBox->itemData(index).toInt())))
  578. {
  579. ccLog::Error("Error setting adv rotation axis, cannot rotate around selected item");
  580. advRotateComboBox->setCurrentIndex(0);
  581. }
  582. return;
  583. }
  584. }
  585. ccLog::Error("Error finding the selected object in DB Tree, cannot translate along selected object");
  586. advRotateComboBox->setCurrentIndex(0);
  587. }
  588. void ccGraphicalTransformationTool::advRefAxisRadioToggled(bool state)
  589. {
  590. if (state)
  591. {
  592. objCenterRadio->setChecked(false);
  593. advRotateRefUpdate(advRotateComboBox->currentIndex()); //force an update
  594. }
  595. }
  596. void ccGraphicalTransformationTool::incrementalTranslationToggle()
  597. {
  598. const bool isIncrementalActive = TxCheckBox->isChecked() || TxCheckBox->isChecked() || TzCheckBox->isChecked();
  599. incrementalTransLabel->setEnabled(isIncrementalActive);
  600. incrementalTransSpin->setEnabled(isIncrementalActive);
  601. }
  602. void ccGraphicalTransformationTool::incrementalRotationToggle(const rotComboBoxItems & selectedRotationItem)
  603. {
  604. if(selectedRotationItem == rotComboBoxItems::NONE || selectedRotationItem == rotComboBoxItems::XYZ) {
  605. incrementalRotLabel->setDisabled(true);
  606. incrementalRotSpin->setDisabled(true);
  607. } else {
  608. incrementalRotLabel->setEnabled(true);
  609. incrementalRotSpin->setEnabled(true);
  610. }
  611. }
  612. void ccGraphicalTransformationTool::advObjectAxisRadioToggled(bool state)
  613. {
  614. if (state)
  615. {
  616. refAxisRadio->setChecked(false);
  617. advRotateRefUpdate(advRotateComboBox->currentIndex()); //force an update
  618. }
  619. }
  620. void ccGraphicalTransformationTool::clear()
  621. {
  622. m_toTransform.detachAllChildren();
  623. m_rotation.toIdentity();
  624. m_translation = CCVector3d(0,0,0);
  625. m_rotationCenter = CCVector3d(0,0,0);
  626. }
  627. void ccGraphicalTransformationTool::clearAdvModeEntities()
  628. {
  629. MainWindow* mainWindow = MainWindow::TheInstance();
  630. if (mainWindow && m_advTranslateRef != nullptr && m_associatedWin)
  631. {
  632. mainWindow->db()->unselectEntity(m_advTranslateRef);
  633. m_advTranslateRef = nullptr;
  634. }
  635. if (mainWindow && m_advRotateRef != nullptr && m_associatedWin)
  636. {
  637. mainWindow->db()->unselectEntity(m_advRotateRef);
  638. m_advRotateRef = nullptr;
  639. }
  640. }
  641. bool ccGraphicalTransformationTool::addEntity(ccHObject* entity)
  642. {
  643. assert(entity);
  644. if (!entity)
  645. return false;
  646. //we don't handle entities associated to another context
  647. if (entity->getDisplay() != m_associatedWin)
  648. {
  649. ccLog::Warning(QString("[Graphical Transformation Tool] Can't use entity '%1' cause it's not displayed in the active 3D view!").arg(entity->getName()));
  650. return false;
  651. }
  652. //we can't transform locked entities
  653. if (entity->isLocked())
  654. {
  655. ccLog::Warning(QString("[Graphical Transformation Tool] Can't transform entity '%1' cause it's locked!").arg(entity->getName()));
  656. return false;
  657. }
  658. //we can't transform child meshes
  659. if (entity->isA(CC_TYPES::MESH) && entity->getParent() && entity->getParent()->isKindOf(CC_TYPES::MESH))
  660. {
  661. ccLog::Warning(QString("[Graphical Transformation Tool] Entity '%1' can't be modified as it is part of a mesh group. You should 'clone' it first.").arg(entity->getName()));
  662. return false;
  663. }
  664. //eventually, we must check that there is no "parent + sibling" in the selection!
  665. //otherwise, the sibling will be rotated twice!
  666. unsigned n = m_toTransform.getChildrenNumber();
  667. for (unsigned i=0; i<n; )
  668. {
  669. ccHObject* previous = m_toTransform.getChild(i);
  670. if (previous->isAncestorOf(entity))
  671. {
  672. //we have found a parent, we won't add this entity
  673. return false;
  674. }
  675. //if the inverse is true, then we get rid of the current element!
  676. else if (entity->isAncestorOf(previous))
  677. {
  678. m_toTransform.detachChild(previous);
  679. --n;
  680. }
  681. else
  682. {
  683. //proceed
  684. ++i;
  685. }
  686. }
  687. m_toTransform.addChild(entity,ccHObject::DP_NONE);
  688. return true;
  689. }
  690. unsigned ccGraphicalTransformationTool::getNumberOfValidEntities() const
  691. {
  692. return m_toTransform.getChildrenNumber();
  693. }
  694. bool ccGraphicalTransformationTool::linkWith(ccGLWindowInterface* win)
  695. {
  696. if (!ccOverlayDialog::linkWith(win))
  697. {
  698. return false;
  699. }
  700. assert(!win || m_toTransform.getChildrenNumber() == 0);
  701. m_toTransform.setDisplay(win);
  702. return true;
  703. }
  704. void ccGraphicalTransformationTool::updateDisplayMessage()
  705. {
  706. if (!m_associatedWin || pauseButton->isChecked())
  707. {
  708. return;
  709. }
  710. if (advPushButton->isChecked())
  711. {
  712. m_associatedWin->displayNewMessage("[Advanced mode]", ccGLWindowInterface::UPPER_CENTER_MESSAGE, false, 3600, ccGLWindowInterface::MANUAL_TRANSFORMATION_MESSAGE);
  713. m_associatedWin->displayNewMessage("[Select Plane or Line to translate along/rotate around]", ccGLWindowInterface::UPPER_CENTER_MESSAGE, true, 3600, ccGLWindowInterface::MANUAL_TRANSFORMATION_MESSAGE);
  714. m_associatedWin->displayNewMessage("[If plane selected, rotation will be around normal vector]", ccGLWindowInterface::UPPER_CENTER_MESSAGE, true, 3600, ccGLWindowInterface::MANUAL_TRANSFORMATION_MESSAGE);
  715. }
  716. else
  717. {
  718. m_associatedWin->displayNewMessage("[Rotation/Translation mode]", ccGLWindowInterface::UPPER_CENTER_MESSAGE, false, 3600, ccGLWindowInterface::MANUAL_TRANSFORMATION_MESSAGE);
  719. }
  720. m_associatedWin->redraw(true, false);
  721. }
  722. bool ccGraphicalTransformationTool::start()
  723. {
  724. assert(!m_processing);
  725. assert(m_associatedWin);
  726. if (!m_associatedWin)
  727. return false;
  728. unsigned childNum = m_toTransform.getChildrenNumber();
  729. if (childNum == 0)
  730. return false;
  731. m_rotation.toIdentity();
  732. m_translation = CCVector3d(0,0,0);
  733. m_rotationCenter = m_toTransform.getBB_recursive().getCenter(); //m_rotation center == selected entities center
  734. //activate "moving mode" in associated GL window
  735. m_associatedWin->setInteractionMode(ccGLWindowInterface::MODE_TRANSFORM_ENTITIES);
  736. m_associatedWin->setPickingMode(ccGLWindowInterface::NO_PICKING, Qt::OpenHandCursor);
  737. //the user must not close this window!
  738. m_associatedWin->setUnclosable(true);
  739. connect(m_associatedWin->signalEmitter(), &ccGLWindowSignalEmitter::rotation, this, &ccGraphicalTransformationTool::glRotate);
  740. connect(m_associatedWin->signalEmitter(), &ccGLWindowSignalEmitter::translation, this, &ccGraphicalTransformationTool::glTranslate);
  741. m_associatedWin->displayNewMessage(QString(), ccGLWindowInterface::UPPER_CENTER_MESSAGE); //clear the area
  742. pauseButton->setChecked(false);
  743. m_advancedModeObjectList.clear();
  744. populateAdvModeItems();
  745. advRotateComboBox->setCurrentIndex(0);
  746. advTranslateComboBox->setCurrentIndex(0);
  747. updateDisplayMessage();
  748. m_associatedWin->redraw(true, false);
  749. return ccOverlayDialog::start();
  750. }
  751. void ccGraphicalTransformationTool::stop(bool state)
  752. {
  753. if (m_associatedWin)
  754. {
  755. //deactivate "moving mode" in associated GL window
  756. m_associatedWin->setInteractionMode(ccGLWindowInterface::MODE_TRANSFORM_CAMERA);
  757. m_associatedWin->setPickingMode(ccGLWindowInterface::DEFAULT_PICKING);
  758. m_associatedWin->setUnclosable(false);
  759. m_associatedWin->signalEmitter()->disconnect(this);
  760. m_associatedWin->displayNewMessage("[Rotation/Translation mode OFF]", ccGLWindowInterface::UPPER_CENTER_MESSAGE, false, 2, ccGLWindowInterface::MANUAL_TRANSFORMATION_MESSAGE);
  761. m_associatedWin->redraw(false, false); //we have to redraw the 3D layer for labels!
  762. }
  763. ccOverlayDialog::stop(state);
  764. }
  765. void ccGraphicalTransformationTool::glTranslate(const CCVector3d& realT)
  766. {
  767. CCVector3d t;
  768. if (m_advMode)
  769. {
  770. CCVector3d mouseMove = realT;
  771. m_advTranslationTransform.inverse().applyRotation(mouseMove);
  772. t = CCVector3d( mouseMove.x * (TxCheckBox->isChecked() ? 1 : 0),
  773. mouseMove.y * (TyCheckBox->isChecked() ? 1 : 0),
  774. mouseMove.z * (TzCheckBox->isChecked() ? 1 : 0));
  775. m_advTranslationTransform.applyRotation(t);
  776. }
  777. else
  778. {
  779. t = CCVector3d( realT.x * (TxCheckBox->isChecked() ? 1 : 0),
  780. realT.y * (TyCheckBox->isChecked() ? 1 : 0),
  781. realT.z * (TzCheckBox->isChecked() ? 1 : 0));
  782. }
  783. if (t.norm2() != 0)
  784. {
  785. m_translation += t;
  786. if (m_advMode && m_advRotateRef != nullptr && refAxisRadio->isChecked() && !m_advRotateRefIsChild)
  787. {
  788. //If we translate we have to update the rotation center when using the ref axis as center of rotation.
  789. //Dont update the rotation center if the rotation ref is contained in m_toTranslate.
  790. CCVector3d centerUpdate = m_rotation.inverse() * m_advRotationRefObjCenter - m_rotation.inverse() * m_position.getTranslationAsVec3D();
  791. m_translation += (m_rotationCenter - centerUpdate) - m_rotation * (m_rotationCenter - centerUpdate);
  792. m_rotationCenter = centerUpdate;
  793. }
  794. updateAllGLTransformations();
  795. }
  796. }
  797. void ccGraphicalTransformationTool::glRotate(const ccGLMatrixd& rotMat)
  798. {
  799. if (m_advMode && m_advRotateRef != nullptr)
  800. {
  801. rotComboBoxItems rotAxis = static_cast<rotComboBoxItems>(rotComboBox->itemData(rotComboBox->currentIndex()).toInt());
  802. double angle = 0;
  803. switch (rotAxis)
  804. {
  805. case rotComboBoxItems::X:
  806. angle = std::asin(rotMat.xRotation()(1, 2));
  807. break;
  808. case rotComboBoxItems::Y:
  809. angle = std::asin(rotMat.yRotation()(2, 0));
  810. break;
  811. case rotComboBoxItems::Z:
  812. angle = std::asin(rotMat.zRotation()(1, 0));
  813. break;
  814. default:
  815. return;
  816. }
  817. ccLog::Print(QString("Angles(%1)").arg(angle));
  818. m_rotation = m_rotation * arbitraryVectorRotation(angle, m_advRotationAxis);
  819. }
  820. else
  821. {
  822. switch (rotComboBox->currentIndex())
  823. {
  824. case rotComboBoxItems::XYZ:
  825. m_rotation = rotMat * m_rotation;
  826. break;
  827. case rotComboBoxItems::X:
  828. m_rotation = rotMat.xRotation() * m_rotation;
  829. break;
  830. case rotComboBoxItems::Y:
  831. m_rotation = rotMat.yRotation() * m_rotation;
  832. break;
  833. case rotComboBoxItems::Z:
  834. m_rotation = rotMat.zRotation() * m_rotation;
  835. break;
  836. case rotComboBoxItems::NONE:
  837. break;
  838. }
  839. }
  840. updateAllGLTransformations();
  841. }
  842. void ccGraphicalTransformationTool::incrementalTransform() {
  843. //We check the sender to handle forward or backward transformation
  844. QObject* senderButton = sender();
  845. const bool isForwardTransform = senderButton == incrementalForwardButton;
  846. // The rotation part:
  847. // No incremental rotation if rotComboBoxItems == XYZ or rotComboBoxItems == NONE because it has no sense
  848. // it could be handled in the subsequent switch cases but it is somehiow more explicit to check
  849. // if the SpinBox is enabled
  850. if(incrementalRotSpin->isEnabled()) {
  851. const double alpha = isForwardTransform ? CCCoreLib::DegreesToRadians(incrementalRotSpin->value()) : -CCCoreLib::DegreesToRadians(incrementalRotSpin->value());
  852. if (m_advMode && m_advRotateRef != nullptr)
  853. {
  854. m_rotation = m_rotation * arbitraryVectorRotation(alpha, m_advRotationAxis);
  855. }
  856. else
  857. {
  858. ccGLMatrixd rotMat;
  859. // compute rotation matrix from spinbox
  860. switch (static_cast<rotComboBoxItems>(rotComboBox->itemData(rotComboBox->currentIndex()).toInt()))
  861. {
  862. case rotComboBoxItems::X:
  863. rotMat.initFromParameters(alpha, CCVector3d(1.0,0.0,0.0), CCVector3d(0.0,0.0,0.0));
  864. break;
  865. case rotComboBoxItems::Y:
  866. rotMat.initFromParameters(alpha, CCVector3d(0.0,1.0,0.0), CCVector3d(0.0,0.0,0.0));
  867. break;
  868. case rotComboBoxItems::Z:
  869. rotMat.initFromParameters(alpha, CCVector3d(0.0,0.0,1.0), CCVector3d(0.0,0.0,0.0));
  870. break;
  871. default:
  872. return;
  873. }
  874. m_rotation = rotMat * m_rotation;
  875. }
  876. updateAllGLTransformations();
  877. }
  878. // The translation part:
  879. // we pass a vector with equal magnitude in the three components; gltranslate will handle the correct transform for us.
  880. const double transMagnitude = isForwardTransform ? incrementalTransSpin->value() : -incrementalTransSpin->value() ;
  881. glTranslate(CCVector3d(transMagnitude,transMagnitude,transMagnitude));
  882. }
  883. void ccGraphicalTransformationTool::reset()
  884. {
  885. m_rotation.toIdentity();
  886. m_translation = CCVector3d(0, 0, 0);
  887. updateAllGLTransformations();
  888. advRotateRefUpdate(advRotateComboBox->currentIndex()); //force an update
  889. advTranslateRefUpdate(advTranslateComboBox->currentIndex()); //force an update
  890. }
  891. void ccGraphicalTransformationTool::setRotationCenter(CCVector3d& center)
  892. {
  893. m_translation += (m_rotationCenter - center) - m_rotation * (m_rotationCenter - center);
  894. m_rotationCenter = center;
  895. updateAllGLTransformations();
  896. }
  897. void ccGraphicalTransformationTool::updateAllGLTransformations()
  898. {
  899. //we recompute global GL transformation matrix
  900. m_position = m_rotation;
  901. m_position += m_rotationCenter + m_translation - m_rotation * m_rotationCenter;
  902. ccGLMatrix newTransf(m_position.data());
  903. for (unsigned i = 0; i < m_toTransform.getChildrenNumber(); ++i)
  904. {
  905. ccHObject* child = m_toTransform.getChild(i);
  906. child->setGLTransformation(newTransf);
  907. child->prepareDisplayForRefresh_recursive();
  908. }
  909. if (m_advTranslateRefIsChild && m_advTranslateRef != nullptr)
  910. {
  911. //update m_advTranslationTransform if the ref object is translated/rotated by virtue of being in m_toTransform
  912. if (m_advTranslateRef->isA(CC_TYPES::PLANE))
  913. {
  914. m_advTranslationTransform = m_position * ccGLMatrixd(m_advTranslateRef->getGLTransformationHistory().data());
  915. }
  916. else if (m_advTranslateRef->isA(CC_TYPES::POLY_LINE))
  917. {
  918. ccPolyline* line = static_cast<ccPolyline*>(m_advTranslateRef);
  919. CCVector3 arbitraryVec = line->getGLTransformation() * (*line->getPoint(1) - *line->getPoint(0));
  920. m_advTranslationTransform = m_position * arbitraryVectorTranslation(arbitraryVec);
  921. }
  922. }
  923. MainWindow::RefreshAllGLWindow(false);
  924. }
  925. void ccGraphicalTransformationTool::apply()
  926. {
  927. //we recompute global GL transformation matrix and display it in console
  928. ccGLMatrixd finalTrans = m_rotation;
  929. finalTrans += m_rotationCenter + m_translation - m_rotation * m_rotationCenter;
  930. ccGLMatrixd finalTransCorrected = finalTrans;
  931. #define NORMALIZE_TRANSFORMATION_MATRIX_WITH_EULER
  932. #ifdef NORMALIZE_TRANSFORMATION_MATRIX_WITH_EULER
  933. {
  934. //convert matrix back and forth so as to be sure to get a 'true' rotation matrix
  935. //DGM: we use Euler angles, as the axis/angle method (formerly used) is not robust
  936. //enough! Shifts could be perceived by the user.
  937. double phi_rad = 0.0;
  938. double theta_rad = 0.0;
  939. double psi_rad = 0.0;
  940. CCVector3d t3D;
  941. finalTrans.getParameters(phi_rad,theta_rad,psi_rad,t3D);
  942. finalTransCorrected.initFromParameters(phi_rad,theta_rad,psi_rad,t3D);
  943. #ifdef QT_DEBUG
  944. ccLog::Print("[GraphicalTransformationTool] Final transformation (before correction):");
  945. ccLog::Print(finalTrans.toString(12,' ')); //full precision
  946. ccLog::Print(QString("Angles(%1,%2,%3) T(%5,%6,%7)").arg(phi_rad).arg(theta_rad).arg(psi_rad).arg(t3D.x).arg(t3D.y).arg(t3D.z));
  947. #endif
  948. }
  949. #endif //NORMALIZE_TRANSFORMATION_MATRIX_WITH_EULER
  950. #ifdef QT_DEBUG
  951. //test: compute rotation "norm" (as it may not be exactly 1 due to numerical (in)accuracy!)
  952. {
  953. ccGLMatrixd finalRotation = finalTransCorrected;
  954. finalRotation.setTranslation(CCVector3(0,0,0));
  955. ccGLMatrixd finalRotationT = finalRotation.transposed();
  956. ccGLMatrixd idTrans = finalRotation * finalRotationT;
  957. double norm = idTrans.data()[0] * idTrans.data()[5] * idTrans.data()[10];
  958. ccLog::PrintDebug("[GraphicalTransformationTool] T*T-1:");
  959. ccLog::PrintDebug(idTrans.toString(12,' ')); //full precision
  960. ccLog::PrintDebug(QString("Rotation norm = %1").arg(norm,0,'f',12));
  961. }
  962. #endif
  963. //update GL transformation for all entities
  964. ccGLMatrix correctedFinalTrans(finalTransCorrected.data());
  965. for (unsigned i = 0; i < m_toTransform.getChildrenNumber(); ++i)
  966. {
  967. ccHObject* toTransform = m_toTransform.getChild(i);
  968. toTransform->setGLTransformation(correctedFinalTrans);
  969. //DGM: warning, applyGLTransformation may delete the associated octree!
  970. MainWindow::ccHObjectContext objContext = MainWindow::TheInstance()->removeObjectTemporarilyFromDBTree(toTransform);
  971. toTransform->applyGLTransformation_recursive();
  972. toTransform->prepareDisplayForRefresh_recursive();
  973. MainWindow::TheInstance()->putObjectBackIntoDBTree(toTransform,objContext);
  974. //special case: if the object is a mesh vertices set, we may have to update the mesh normals!
  975. if (toTransform->isA(CC_TYPES::POINT_CLOUD) && toTransform->getParent() && toTransform->getParent()->isKindOf(CC_TYPES::MESH))
  976. {
  977. ccMesh* mesh = static_cast<ccMesh*>(toTransform->getParent());
  978. if (mesh->hasTriNormals() && !m_toTransform.isAncestorOf(mesh))
  979. {
  980. mesh->transformTriNormals(correctedFinalTrans);
  981. }
  982. }
  983. }
  984. clearAdvModeEntities();
  985. stop(true);
  986. clear();
  987. //output resulting transformation matrix
  988. ccLog::Print("[GraphicalTransformationTool] Applied transformation:");
  989. ccLog::Print(correctedFinalTrans.toString(12,' ')); //full precision
  990. #ifdef QT_DEBUG
  991. {
  992. float phi_rad = 0.0f;
  993. float theta_rad = 0.0f;
  994. float psi_rad = 0.0f;
  995. CCVector3f t3D;
  996. correctedFinalTrans.getParameters(phi_rad,theta_rad,psi_rad,t3D);
  997. ccLog::Print(QString("Angles(%1,%2,%3) T(%5,%6,%7)").arg(phi_rad).arg(theta_rad).arg(psi_rad).arg(t3D.x).arg(t3D.y).arg(t3D.z));
  998. }
  999. #endif
  1000. }
  1001. void ccGraphicalTransformationTool::cancel()
  1002. {
  1003. for (unsigned i=0; i<m_toTransform.getChildrenNumber(); ++i)
  1004. {
  1005. ccHObject* child = m_toTransform.getChild(i);
  1006. child->resetGLTransformation();
  1007. child->prepareDisplayForRefresh_recursive();
  1008. }
  1009. clearAdvModeEntities();
  1010. stop(false);
  1011. clear();
  1012. //MainWindow::RefreshAllGLWindow();
  1013. }