Divide.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  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("scripts/Modify/Modify.js");
  20. include("scripts/ShapeAlgorithms.js");
  21. /**
  22. * \class Divide
  23. * \brief Divide entities into two equally long parts.
  24. * \ingroup ecma_modify
  25. */
  26. function Divide(guiAction) {
  27. Modify.call(this, guiAction);
  28. this.entity = undefined;
  29. // user click position:
  30. this.pos = undefined;
  31. this.pos2 = undefined;
  32. // actual cutting point:
  33. this.cutPos = undefined;
  34. this.cutPos2 = undefined;
  35. }
  36. Divide.prototype = new Modify();
  37. Divide.State = {
  38. ChoosingEntity : 0,
  39. SettingPos : 1,
  40. SettingPos2 : 2
  41. };
  42. Divide.prototype.beginEvent = function() {
  43. Modify.prototype.beginEvent.call(this);
  44. this.setState(Divide.State.ChoosingEntity);
  45. };
  46. Divide.prototype.setState = function(state) {
  47. Modify.prototype.setState.call(this, state);
  48. this.setCrosshairCursor();
  49. var tr;
  50. var appWin = RMainWindowQt.getMainWindow();
  51. switch (this.state) {
  52. case Divide.State.ChoosingEntity:
  53. this.entity = undefined;
  54. this.pos = undefined;
  55. this.cutPos = undefined;
  56. this.getDocumentInterface().setClickMode(RAction.PickEntity);
  57. if (RSpline.hasProxy() && RPolyline.hasProxy()) {
  58. tr = qsTr("Choose line, arc, circle, ellipse, spline or polyline");
  59. }
  60. else {
  61. tr = qsTr("Choose line, arc, circle or ellipse")
  62. }
  63. this.setLeftMouseTip(tr);
  64. this.setCommandPrompt(tr);
  65. this.setRightMouseTip(EAction.trCancel);
  66. break;
  67. case Divide.State.SettingPos:
  68. this.pos = undefined;
  69. this.cutPos = undefined;
  70. this.pos2 = undefined;
  71. this.cutPos2 = undefined;
  72. this.getDocumentInterface().setClickMode(RAction.PickCoordinate);
  73. tr = qsTr("Specify point");
  74. this.setLeftMouseTip(tr);
  75. this.setCommandPrompt(tr);
  76. this.setRightMouseTip(EAction.trBack);
  77. EAction.showSnapTools();
  78. break;
  79. case Divide.State.SettingPos2:
  80. this.pos2 = undefined;
  81. this.cutPos2 = undefined;
  82. this.getDocumentInterface().setClickMode(RAction.PickCoordinate);
  83. tr = qsTr("Specify second point");
  84. this.setLeftMouseTip(tr);
  85. this.setCommandPrompt(tr);
  86. this.setRightMouseTip(EAction.trBack);
  87. EAction.showSnapTools();
  88. break;
  89. }
  90. };
  91. Divide.prototype.escapeEvent = function() {
  92. switch (this.state) {
  93. case Divide.State.ChoosingEntity:
  94. EAction.prototype.escapeEvent.call(this);
  95. break;
  96. case Divide.State.SettingPos:
  97. this.setState(Divide.State.ChoosingEntity);
  98. break;
  99. case Divide.State.SettingPos2:
  100. this.setState(Divide.State.SettingPos);
  101. break;
  102. }
  103. };
  104. Divide.prototype.pickEntity = function(event, preview) {
  105. var di = this.getDocumentInterface();
  106. var doc = this.getDocument();
  107. var entityId = this.getEntityId(event, preview);
  108. var entity = doc.queryEntity(entityId);
  109. var pos = event.getModelPosition();
  110. if (isNull(entity)) {
  111. this.entity = undefined;
  112. return;
  113. }
  114. switch (this.state) {
  115. case Divide.State.ChoosingEntity:
  116. if (isLineBasedEntity(entity) ||
  117. isArcEntity(entity) ||
  118. isCircleEntity(entity) ||
  119. isEllipseEntity(entity) ||
  120. (RSpline.hasProxy() && isSplineEntity(entity)) ||
  121. (RPolyline.hasProxy() && isPolylineEntity(entity))) {
  122. this.entity = entity;
  123. if (preview) {
  124. this.updatePreview();
  125. }
  126. else {
  127. this.setState(Divide.State.SettingPos);
  128. }
  129. }
  130. else {
  131. if (!preview) {
  132. if (RSpline.hasProxy() && RPolyline.hasProxy()) {
  133. EAction.warnNotLineArcCircleEllipseSplinePolyline();
  134. }
  135. else {
  136. EAction.warnNotLineArcCircleEllipse();
  137. }
  138. }
  139. }
  140. break;
  141. }
  142. };
  143. Divide.prototype.pickCoordinate = function(event, preview) {
  144. var di = this.getDocumentInterface();
  145. var op;
  146. switch (this.state) {
  147. case Divide.State.SettingPos:
  148. this.pos = event.getModelPosition();
  149. // full circle or ellipse: require two cutting points:
  150. if (isCircleEntity(this.entity) ||
  151. (isEllipseEntity(this.entity) && this.entity.isFullEllipse())) {
  152. if (preview) {
  153. this.updatePreview();
  154. }
  155. else {
  156. this.setState(Divide.State.SettingPos2);
  157. }
  158. }
  159. else {
  160. if (preview) {
  161. this.updatePreview();
  162. }
  163. else {
  164. op = this.getOperation(false);
  165. if (!isNull(op)) {
  166. di.applyOperation(op);
  167. }
  168. this.setState(Divide.State.ChoosingEntity);
  169. }
  170. }
  171. break;
  172. case Divide.State.SettingPos2:
  173. this.pos2 = event.getModelPosition();
  174. if (preview) {
  175. this.updatePreview();
  176. }
  177. else {
  178. op = this.getOperation(false);
  179. if (!isNull(op)) {
  180. di.applyOperation(op);
  181. }
  182. this.setState(Divide.State.ChoosingEntity);
  183. }
  184. break;
  185. }
  186. };
  187. Divide.prototype.getOperation = function(preview) {
  188. var op = new RAddObjectsOperation();
  189. op.setText(this.getToolTitle());
  190. var cutPositions = Divide.divide(op, this.pos, this.pos2, this.entity);
  191. if (cutPositions.length===0) {
  192. destr(op);
  193. return undefined;
  194. }
  195. this.cutPos = cutPositions[0];
  196. this.cutPos2 = cutPositions[1];
  197. return op;
  198. };
  199. Divide.prototype.getHighlightedEntities = function() {
  200. var ret = [];
  201. if (isEntity(this.entity)) {
  202. ret.push(this.entity.getId());
  203. }
  204. return ret;
  205. };
  206. Divide.prototype.getAuxPreview = function() {
  207. if (!isValidVector(this.cutPos)) {
  208. return undefined;
  209. }
  210. var ret = [];
  211. var view = EAction.getGraphicsView();
  212. var overlap = view.mapDistanceFromView(25);
  213. var line = new RLine(this.cutPos, this.pos);
  214. var points = line.getPointsWithDistanceToEnd(-overlap);
  215. line = new RLine(points[0], points[1]);
  216. ret.push(line);
  217. return ret;
  218. };
  219. /**
  220. * Divides the given entity at the given one or two positions
  221. * as part of the given operation.
  222. *
  223. * \return Array of actual cut points.
  224. */
  225. Divide.divide = function(op, pos1, pos2, entity) {
  226. if (isNull(pos1) || isNull(entity)) {
  227. return [];
  228. }
  229. entity = entity.clone();
  230. //var shape = entity.getClosestSimpleShape(pos);
  231. var shape = entity.castToShape();
  232. var res = Divide.divideShape(pos1, pos2, shape);
  233. if (isNull(res)) {
  234. return [];
  235. }
  236. var shape1 = res[0][0];
  237. var shape2 = res[0][1];
  238. op.deleteObject(entity);
  239. var e;
  240. if (!isNull(shape1)) {
  241. e = shapeToEntity(entity.getDocument(), shape1);
  242. e.copyAttributesFrom(entity);
  243. op.addObject(e, false);
  244. }
  245. if (!isNull(shape2)) {
  246. e = shapeToEntity(entity.getDocument(), shape2);
  247. e.copyAttributesFrom(entity);
  248. op.addObject(e, false);
  249. }
  250. return res[1];
  251. // else if (isPolylineShape(shape) && shape.isClosed()) {
  252. // shape.relocateStartPoint(pos1);
  253. // modifyEntity(op, entity, shape);
  254. // cutPos1 = pos1;
  255. // if (!isNull(pos2)) {
  256. // Divide.divide(op, pos2, undefined, entity);
  257. // }
  258. // }
  259. // else {
  260. // var shape1 = shape.clone();
  261. // var shape2 = shape.clone();
  262. // shape1 = trimEndPoint(shape1, pos1, pos1);
  263. // cutPos1 = shape1.getEndPoint();
  264. // shape2 = trimStartPoint(shape2, pos1, pos1);
  265. // // modify chosen entity into first part:
  266. // modifyEntity(op, entity, shape1);
  267. // // add second part as new entity:
  268. // if (isLineBasedShape(shape2) || isArcShape(shape2) ||
  269. // isEllipseShape(shape2) || isSplineShape(shape2) || isPolylineShape(shape2)) {
  270. // e = shapeToEntity(entity.getDocument(), shape2);
  271. // if (!isNull(e)) {
  272. // e.copyAttributesFrom(entity);
  273. // op.addObject(e, false);
  274. // }
  275. // }
  276. // }
  277. // return [cutPos1, cutPos2];
  278. };
  279. Divide.divideShape = function(pos1, pos2, shape) {
  280. return ShapeAlgorithms.divideShape(shape, pos1, pos2);
  281. };