BreakOut.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  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. function BreakOut(guiAction) {
  22. Modify.call(this, guiAction);
  23. this.entity = undefined;
  24. this.pos = undefined;
  25. this.removeSegment = true;
  26. this.extend = false;
  27. this.setUiOptions("BreakOut.ui");
  28. }
  29. BreakOut.prototype = new Modify();
  30. BreakOut.State = {
  31. ChoosingEntity : 0
  32. };
  33. BreakOut.prototype.beginEvent = function() {
  34. Modify.prototype.beginEvent.call(this);
  35. this.setState(BreakOut.State.ChoosingEntity);
  36. };
  37. BreakOut.prototype.setState = function(state) {
  38. Modify.prototype.setState.call(this, state);
  39. this.setCrosshairCursor();
  40. var appWin = RMainWindowQt.getMainWindow();
  41. switch (this.state) {
  42. case BreakOut.State.ChoosingEntity:
  43. this.entity = undefined;
  44. this.shape = undefined;
  45. this.getDocumentInterface().setClickMode(RAction.PickEntity);
  46. var tr;
  47. if (RSpline.hasProxy() && RPolyline.hasProxy()) {
  48. tr = qsTr("Choose line, arc, circle, ellipse, spline or polyline segment");
  49. }
  50. else {
  51. tr = qsTr("Choose line, arc, circle or ellipse segment");
  52. }
  53. this.setLeftMouseTip(tr);
  54. this.setCommandPrompt(tr);
  55. this.setRightMouseTip(EAction.trCancel);
  56. break;
  57. }
  58. };
  59. BreakOut.prototype.escapeEvent = function() {
  60. switch (this.state) {
  61. case BreakOut.State.ChoosingEntity:
  62. EAction.prototype.escapeEvent.call(this);
  63. break;
  64. }
  65. };
  66. BreakOut.prototype.pickEntity = function(event, preview) {
  67. var di = this.getDocumentInterface();
  68. var doc = this.getDocument();
  69. var entityId = this.getEntityId(event, preview);
  70. var entity = doc.queryEntity(entityId);
  71. var pos = event.getModelPosition();
  72. if (isNull(entity)) {
  73. this.entity = undefined;
  74. return;
  75. }
  76. switch (this.state) {
  77. case BreakOut.State.ChoosingEntity:
  78. var cond = isLineBasedEntity(entity) ||
  79. isArcEntity(entity) ||
  80. isCircleEntity(entity) ||
  81. isEllipseEntity(entity) ||
  82. (RSpline.hasProxy() && isSplineEntity(entity)) ||
  83. (RPolyline.hasProxy() && isPolylineEntity(entity));
  84. if (!cond) {
  85. if (!preview) {
  86. if (RSpline.hasProxy() && RPolyline.hasProxy()) {
  87. EAction.warnNotLineArcCircleEllipseSplinePolyline();
  88. }
  89. else {
  90. EAction.warnNotLineArcCircleEllipse();
  91. }
  92. }
  93. break;
  94. }
  95. if (!EAction.assertEditable(entity, preview)) {
  96. break;
  97. }
  98. this.entity = entity;
  99. this.pos = pos;
  100. if (preview) {
  101. this.updatePreview();
  102. }
  103. else {
  104. var op = this.getOperation(false);
  105. if (!isNull(op)) {
  106. di.applyOperation(op);
  107. }
  108. }
  109. break;
  110. }
  111. };
  112. BreakOut.prototype.getOperation = function(preview) {
  113. if (isNull(this.pos) || isNull(this.entity)) {
  114. return undefined;
  115. }
  116. if (preview) {
  117. // no preview of operation:
  118. return;
  119. }
  120. var op = new RAddObjectsOperation();
  121. op.setText(this.getToolTitle());
  122. BreakOut.breakOut(op, this.entity, this.pos, this.extend, this.removeSegment);
  123. return op;
  124. };
  125. BreakOut.prototype.getHighlightedEntities = function() {
  126. var ret = [];
  127. if (isEntity(this.entity)) {
  128. ret.push(this.entity.getId());
  129. }
  130. return ret;
  131. };
  132. BreakOut.prototype.getAuxPreview = function() {
  133. // if (!isValidVector(this.cutPos)) {
  134. // return undefined;
  135. // }
  136. // var ret = [];
  137. // var view = EAction.getGraphicsView();
  138. // var overlap = view.mapDistanceFromView(25);
  139. // var line = new RLine(this.cutPos, this.pos);
  140. // var points = line.getPointsWithDistanceToEnd(-overlap);
  141. // line = new RLine(points[0], points[1]);
  142. // ret.push(line);
  143. // return ret;
  144. };
  145. BreakOut.prototype.slotRemoveSegmentChanged = function(value) {
  146. this.removeSegment = value;
  147. };
  148. /**
  149. * Breaks out the segment closest to pos from the given entity.
  150. *
  151. * \param op RAddObjectsOperation
  152. * \param entity REntity
  153. * \param pos RVector
  154. * \param extend True to extend to closesd intersections instead.
  155. * \param removeSegment True to remove (delete) broken out segment.
  156. *
  157. * \return True on success or false otherwise.
  158. */
  159. BreakOut.breakOut = function(op, entity, pos, extend, removeSegment) {
  160. var doc = entity.getDocument();
  161. var shape = entity.getClosestShape(pos);
  162. var otherShapes = ShapeAlgorithms.getIntersectingShapes(doc, entity.getId(), shape, extend);
  163. var newSegments = ShapeAlgorithms.autoSplit(shape, otherShapes, pos, extend);
  164. if (isNull(newSegments)) {
  165. return false;
  166. }
  167. var e;
  168. if (isNull(newSegments[0]) && isNull(newSegments[1])) {
  169. if (!extend && removeSegment) {
  170. // delete entity completely:
  171. op.deleteObject(entity);
  172. }
  173. }
  174. else {
  175. // replace circle with arc:
  176. if (isCircleEntity(entity)) {
  177. op.deleteObject(entity);
  178. if (!isNull(newSegments[2])) {
  179. if (extend || !removeSegment) {
  180. e = shapeToEntity(doc, newSegments[2]);
  181. if (!isNull(e)) {
  182. e.copyAttributesFrom(getPtr(entity));
  183. op.addObject(e, false);
  184. }
  185. }
  186. }
  187. }
  188. // change existing entity into segment if we keep the segment,
  189. // otherwise delete existing entity
  190. else {
  191. if (removeSegment && !extend) {
  192. // delete entity completely:
  193. op.deleteObject(entity);
  194. }
  195. else {
  196. //modifyEntity(op, entity.data(), newSegments[2]);
  197. if (!isNull(newSegments[2])) {
  198. modifyEntity(op, entity.clone(), newSegments[2]);
  199. }
  200. }
  201. }
  202. }
  203. if (!extend) {
  204. if (!BreakOut.drop(newSegments[0])) {
  205. if (isXLineShape(newSegments[0]) || isRayShape(newSegments[0]) || newSegments[0].getLength()>RS.PointTolerance) {
  206. e = shapeToEntity(entity.getDocument(), newSegments[0]);
  207. if (!isNull(e)) {
  208. e.copyAttributesFrom(getPtr(entity));
  209. op.addObject(e, false);
  210. }
  211. }
  212. }
  213. if (!BreakOut.drop(newSegments[1])) {
  214. if (isXLineShape(newSegments[1]) || isRayShape(newSegments[1]) || newSegments[1].getLength()>RS.PointTolerance) {
  215. e = shapeToEntity(entity.getDocument(), newSegments[1]);
  216. if (!isNull(e)) {
  217. e.copyAttributesFrom(getPtr(entity));
  218. op.addObject(e, false);
  219. }
  220. }
  221. }
  222. }
  223. return true;
  224. };
  225. BreakOut.drop = function(shape) {
  226. if (isNull(shape)) {
  227. return true;
  228. }
  229. if (isLineShape(shape) || isArcShape(shape)) {
  230. if (shape.getLength()<=RS.PointTolerance) {
  231. // drop zero length segments:
  232. return true;
  233. }
  234. }
  235. return false;
  236. };