ModifyCorner.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. /**
  2. * Copyright (c) 2011-2018 by Andrew Mustun. All rights reserved.
  3. *
  4. * This file is part of the QCAD project.
  5. *
  6. * QCAD is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * QCAD is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with QCAD.
  18. */
  19. include("Modify.js");
  20. /**
  21. * \class ModifyCorner
  22. * \brief Base class for modification tools that operate on a corner
  23. * (Bevel, Round).
  24. */
  25. function ModifyCorner(guiAction) {
  26. Modify.call(this, guiAction);
  27. // position clicked to choose corner:
  28. this.posCorner = undefined;
  29. // entity / position chosen as first edge:
  30. this.entity1 = undefined;
  31. this.shape1 = undefined;
  32. this.clickPos1 = undefined;
  33. // entity / position chosen as second edge:
  34. this.entity2 = undefined;
  35. this.shape2 = undefined;
  36. this.clickPos2 = undefined;
  37. // trimming on / off:
  38. this.trim = true;
  39. // tool requires additional point (e.g. radius position):
  40. this.requiresPoint = false;
  41. this.posPoint = undefined;
  42. this.posSolution = undefined;
  43. }
  44. ModifyCorner.prototype = new Modify();
  45. ModifyCorner.State = {
  46. ChoosingCorner : 0,
  47. ChoosingEntity1 : 1,
  48. ChoosingEntity2 : 2,
  49. SettingPoint : 3,
  50. };
  51. ModifyCorner.prototype.beginEvent = function() {
  52. Modify.prototype.beginEvent.call(this);
  53. this.setState(ModifyCorner.State.ChoosingEntity1);
  54. };
  55. ModifyCorner.prototype.setState = function(state) {
  56. Modify.prototype.setState.call(this, state);
  57. this.setCrosshairCursor();
  58. var appWin = RMainWindowQt.getMainWindow();
  59. switch (this.state) {
  60. case ModifyCorner.State.ChoosingCorner:
  61. this.getDocumentInterface().setClickMode(RAction.PickCoordinateNoSnap);
  62. this.posCorner = undefined;
  63. this.entity1 = undefined;
  64. this.shape1 = undefined;
  65. this.clickPos1 = undefined;
  66. this.entity2 = undefined;
  67. this.shape2 = undefined;
  68. this.clickPos2 = undefined;
  69. this.posSolution = undefined;
  70. this.posPoint = undefined;
  71. var trCorner = qsTr("Choose corner");
  72. this.setCommandPrompt(trCorner);
  73. this.setLeftMouseTip(trCorner);
  74. this.setRightMouseTip(EAction.trCancel);
  75. break;
  76. case ModifyCorner.State.ChoosingEntity1:
  77. this.getDocumentInterface().setClickMode(RAction.PickEntity);
  78. this.posCorner = undefined;
  79. this.entity1 = undefined;
  80. this.shape1 = undefined;
  81. this.clickPos1 = undefined;
  82. this.entity2 = undefined;
  83. this.shape2 = undefined;
  84. this.clickPos2 = undefined;
  85. this.posSolution = undefined;
  86. this.posPoint = undefined;
  87. var trEntity1 = qsTr("Choose first entity");
  88. this.setCommandPrompt(trEntity1);
  89. this.setLeftMouseTip(trEntity1);
  90. this.setRightMouseTip(EAction.trCancel);
  91. break;
  92. case ModifyCorner.State.ChoosingEntity2:
  93. this.getDocumentInterface().setClickMode(RAction.PickEntity);
  94. this.entity2 = undefined;
  95. this.shape2 = undefined;
  96. this.clickPos2 = undefined;
  97. var trEntity2 = qsTr("Choose second entity");
  98. this.setCommandPrompt(trEntity2);
  99. this.setLeftMouseTip(trEntity2);
  100. this.setRightMouseTip(EAction.trBack);
  101. break;
  102. case ModifyCorner.State.SettingPoint:
  103. this.getDocumentInterface().setClickMode(RAction.PickCoordinate);
  104. this.posSolution = undefined;
  105. this.posPoint = undefined;
  106. var trPoint = qsTr("Set point");
  107. this.setCommandPrompt(trPoint);
  108. this.setLeftMouseTip(trPoint);
  109. this.setRightMouseTip(EAction.trBack);
  110. break;
  111. }
  112. this.simulateMouseMoveEvent();
  113. };
  114. ModifyCorner.prototype.escapeEvent = function() {
  115. switch (this.state) {
  116. case ModifyCorner.State.ChoosingCorner:
  117. Modify.prototype.escapeEvent.call(this);
  118. break;
  119. case ModifyCorner.State.ChoosingEntity1:
  120. Modify.prototype.escapeEvent.call(this);
  121. break;
  122. case ModifyCorner.State.ChoosingEntity2:
  123. this.setState(ModifyCorner.State.ChoosingEntity1);
  124. break;
  125. case ModifyCorner.State.SettingPoint:
  126. this.setState(ModifyCorner.State.ChoosingEntity2);
  127. break;
  128. }
  129. };
  130. ModifyCorner.prototype.pickEntity = function(event, preview) {
  131. var di = this.getDocumentInterface();
  132. var doc = this.getDocument();
  133. var entityId = this.getEntityId(event, preview);
  134. var entity = doc.queryEntity(entityId);
  135. var pos = event.getModelPosition();
  136. var op;
  137. if (!this.isEntitySnappable(entity)) {
  138. // entity not on a snappable layer:
  139. return;
  140. }
  141. switch (this.state) {
  142. case ModifyCorner.State.ChoosingEntity1:
  143. if (isNull(entity)) {
  144. this.entity1 = undefined;
  145. this.shape1 = undefined;
  146. if (preview) {
  147. this.updatePreview();
  148. }
  149. return;
  150. }
  151. var shape = entity.getClosestSimpleShape(pos);
  152. if (this.isShapeSupported(shape)) {
  153. this.entity1 = entity;
  154. this.shape1 = shape;
  155. this.clickPos1 = pos;
  156. if (preview) {
  157. this.updatePreview();
  158. }
  159. else {
  160. this.setState(ModifyCorner.State.ChoosingEntity2);
  161. }
  162. }
  163. else {
  164. if (!preview) {
  165. this.warnUnsupportedShape();
  166. }
  167. }
  168. break;
  169. case ModifyCorner.State.ChoosingEntity2:
  170. if (isNull(entity)) {
  171. this.entity2 = undefined;
  172. this.shape2 = undefined;
  173. if (preview) {
  174. this.updatePreview();
  175. }
  176. return;
  177. }
  178. var shape = entity.getClosestSimpleShape(pos);
  179. if (this.isShapeSupported(shape)) {
  180. this.entity2 = entity;
  181. this.shape2 = shape;
  182. this.clickPos2 = event.getModelPosition();
  183. if (preview) {
  184. this.updatePreview();
  185. }
  186. else {
  187. if (this.requiresPoint) {
  188. this.setState(ModifyCorner.State.SettingPoint);
  189. }
  190. else {
  191. op = this.getOperation(false);
  192. if (!isNull(op)) {
  193. di.applyOperation(op);
  194. this.setState(ModifyCorner.State.ChoosingEntity1);
  195. }
  196. }
  197. }
  198. }
  199. else {
  200. this.entity2 = undefined;
  201. this.shape2 = undefined;
  202. if (preview) {
  203. this.updatePreview();
  204. }
  205. else {
  206. this.warnUnsupportedShape();
  207. }
  208. }
  209. break;
  210. }
  211. };
  212. ModifyCorner.prototype.isShapeSupported = function(shape) {
  213. return isLineBasedShape(shape) || isArcShape(shape) || isCircleShape(shape);
  214. };
  215. ModifyCorner.prototype.warnUnsupportedShape = function() {
  216. EAction.warnNotLineArcCircle();
  217. };
  218. ModifyCorner.prototype.pickCoordinate = function(event, preview) {
  219. var di = this.getDocumentInterface();
  220. var op;
  221. switch (this.state) {
  222. case ModifyCorner.State.ChoosingCorner:
  223. this.posCorner = event.getModelPosition();
  224. var ok = this.pickCorner(event);
  225. if (preview) {
  226. this.updatePreview();
  227. }
  228. else {
  229. if (ok) {
  230. op = this.getOperation(false);
  231. if (!isNull(op)) {
  232. di.applyOperation(op);
  233. }
  234. this.setState(ModifyCorner.State.ChoosingCorner);
  235. }
  236. }
  237. break;
  238. case ModifyCorner.State.SettingPoint:
  239. this.posPoint = event.getModelPosition();
  240. if (preview) {
  241. this.updatePreview();
  242. }
  243. else {
  244. op = this.getOperation(false);
  245. if (!isNull(op)) {
  246. di.applyOperation(op);
  247. }
  248. this.setState(ModifyCorner.State.ChoosingEntity1);
  249. }
  250. break;
  251. }
  252. };
  253. ModifyCorner.prototype.pickCorner = function(event) {
  254. this.entity1 = undefined;
  255. this.entity2 = undefined;
  256. var di = this.getDocumentInterface();
  257. var doc = this.getDocument();
  258. // get closest entity:
  259. var entityId1 = di.getClosestEntity(event.getRInputEvent());
  260. if (entityId1===RObject.INVALID_ID) {
  261. return false;
  262. }
  263. this.entity1 = doc.queryEntity(entityId1);
  264. if (isNull(this.entity1)) {
  265. return false;
  266. }
  267. if (isPolylineEntity(this.entity1)) {
  268. // find two closest segments and click positions:
  269. var vc = this.entity1.countVertices();
  270. var vertexIndex = this.entity1.getClosestVertex(this.posCorner);
  271. this.entity2 = this.entity1;
  272. var s1 = this.entity1.getSegmentAt(RMath.absmod(vertexIndex-1, vc-1));
  273. var s2 = this.entity1.getSegmentAt(vertexIndex);
  274. this.clickPos1 = s1.getPointWithDistanceToEnd(s1.getLength()/3);
  275. this.clickPos2 = s2.getPointWithDistanceToStart(s2.getLength()/3);
  276. this.posSolution = this.posCorner;
  277. return true;
  278. }
  279. this.shape1 = this.entity1.getClosestSimpleShape(this.posCorner);
  280. this.clickPos1 = this.entity1.getClosestPointOnEntity(this.posCorner);
  281. // ids of entities potentially intersecting entity1:
  282. var entityIds = doc.queryIntersectedEntitiesXY(this.entity1.getBoundingBox(), true);
  283. // find intersection points on entity1:
  284. var minDist = undefined;
  285. for (var i=0; i<entityIds.length; i++) {
  286. var entityId = entityIds[i];
  287. var entity2Candidate = doc.queryEntity(entityId);
  288. // intersection points between entity1 and entity2:
  289. var ips = this.entity1.getIntersectionPoints(entity2Candidate.data());
  290. for (var k=0; k<ips.length; k++) {
  291. var ip = ips[k];
  292. var side1 = this.shape1.getSideOfPoint(this.posCorner);
  293. var dist = this.clickPos1.getDistanceTo(ip);
  294. if (isNull(minDist) || dist<minDist) {
  295. var clickPos2Candidate = entity2Candidate.getClosestPointOnEntity(this.posCorner);
  296. var side2 = this.shape1.getSideOfPoint(clickPos2Candidate);
  297. if (side1===side2) {
  298. // potential closest intersection point found:
  299. minDist = dist;
  300. this.entity2 = entity2Candidate;
  301. this.shape2 = entity2Candidate.getClosestSimpleShape(this.posCorner);
  302. this.clickPos2 = clickPos2Candidate;
  303. }
  304. }
  305. }
  306. }
  307. this.posSolution = this.posCorner;
  308. return true;
  309. };
  310. ModifyCorner.prototype.getHighlightedEntities = function() {
  311. var ret = [];
  312. if (isEntity(this.entity1)) {
  313. ret.push(this.entity1.getId());
  314. }
  315. if (isEntity(this.entity2)) {
  316. ret.push(this.entity2.getId());
  317. }
  318. return ret;
  319. };
  320. ModifyCorner.prototype.slotTrimChanged = function(value) {
  321. this.trim = value;
  322. };
  323. ModifyCorner.prototype.slotIndividualEdgesChanged = function(value) {
  324. if (value===true) {
  325. this.setState(ModifyCorner.State.ChoosingEntity1);
  326. }
  327. else {
  328. this.setState(ModifyCorner.State.ChoosingCorner);
  329. }
  330. };
  331. ModifyCorner.prototype.slotSingleClickChanged = function(value) {
  332. this.slotIndividualEdgesChanged(!value);
  333. };