/** * Copyright (c) 2011-2018 by Andrew Mustun. All rights reserved. * * This file is part of the QCAD project. * * QCAD is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * QCAD is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with QCAD. */ /** * \class ShapeAlgorithms * Various shape based algorithms. */ function ShapeAlgorithms() { } /** * \return Array with only the circle shapes from the given shapes. */ ShapeAlgorithms.getCircleShapes = function(shapes) { if (isNull(shapes)) { return undefined; } var ret = []; for (var i=0; idist2) { var angle2 = Math.asin(dist2/dist1); var angt1 = angle1 + angle2 + Math.PI/2.0; var angt2 = angle1 - angle2 - Math.PI/2.0; offs1 = new RVector(); offs2 = new RVector(); offs1.setPolar(circleRadius1, angt1); offs2.setPolar(circleRadius2, angt1); tangents.push(new RLine(circleCenter1.operator_add(offs1), circleCenter2.operator_add(offs2))); offs1.setPolar(circleRadius1, angt2); offs2.setPolar(circleRadius2, angt2); tangents.push(new RLine(circleCenter1.operator_add(offs1), circleCenter2.operator_add(offs2))); } else { tangents.push(undefined); tangents.push(undefined); } // inner tangents: var dist3 = circleRadius2 + circleRadius1; if (dist1>dist3) { var angle3 = Math.asin(dist3/dist1); var angt3 = angle1 + angle3 + Math.PI/2.0; var angt4 = angle1 - angle3 - Math.PI/2.0; offs1 = new RVector(); offs2 = new RVector(); offs1.setPolar(circleRadius1, angt3); offs2.setPolar(circleRadius2, angt3); tangents.push(new RLine(circleCenter1.operator_subtract(offs1), circleCenter2.operator_add(offs2))); offs1.setPolar(circleRadius1, angt4); offs2.setPolar(circleRadius2, angt4); tangents.push(new RLine(circleCenter1.operator_subtract(offs1), circleCenter2.operator_add(offs2))); } else { tangents.push(undefined); tangents.push(undefined); } return tangents; }; /** * \return Line that is orthogonal to line and tangential to circle. */ ShapeAlgorithms.getOrthogonalTangents = function(line, circle) { var ret = []; var auxLine1, auxLine2; var ips, ips1, ips2; var lineAngle = line.getAngle(); if (isCircleShape(circle) || isArcShape(circle)) { // line parallel to line through center of circle: auxLine1 = new RLine(circle.getCenter(), lineAngle, 100.0); // intersections of parallel with circle: ips1 = circle.getIntersectionPoints(auxLine1, false); for (var i=0; i=1 && ips2.length>=1) { if (ips1[0].equalsFuzzy(ips2[0])) { pointOfContact1 = ips1[0]; } else { auxLine1 = new RLine(ips1[0], ips2[0]); ips = circle.getIntersectionPoints(auxLine1, false); if (ips.length>=1) { pointOfContact1 = ips[0]; } } } if (ips1.length>=2 && ips2.length>=2) { if (ips1[1].equalsFuzzy(ips2[1])) { pointOfContact2 = ips1[1]; } else { auxLine2 = new RLine(ips1[1], ips2[1]); ips = circle.getIntersectionPoints(auxLine2, false); if (ips.length>=1) { pointOfContact2 = ips[0]; } } } if (!isNull(pointOfContact1)) { var pointOnLine1 = line.getClosestPointOnShape(pointOfContact1, false); ret.push(new RLine(pointOfContact1, pointOnLine1)); } if (!isNull(pointOfContact2)) { var pointOnLine2 = line.getClosestPointOnShape(pointOfContact2, false); ret.push(new RLine(pointOfContact2, pointOnLine2)); } } return ret; }; /** * \return Parallels to this shape. * \param distance Distance of first parallel or concentric arc or circle. * \param number Number of offset shapes to generate. * \param sidePosition RVector indicating what side of the shape the parallels * should be RS.LeftHand or RS.RightHand or RS.BothSides. */ ShapeAlgorithms.getOffsetShapes = function(shape, distance, number, sidePosition) { var side = isVector(sidePosition) ? RS.NoSide : sidePosition; var pos = isVector(sidePosition) ? sidePosition : RVector.invalid; return shape.getOffsetShapes(distance, number, side, pos); }; ShapeAlgorithms.getOffsetLines = function(shape, distance, number, sidePosition) { var side = isVector(sidePosition) ? RS.NoSide : sidePosition; var pos = isVector(sidePosition) ? sidePosition : RVector.invalid; return RShape.getOffsetLines(shape, distance, number, side, pos); }; ShapeAlgorithms.getOffsetArcs = function(shape, distance, number, sidePosition) { var side = isVector(sidePosition) ? RS.NoSide : sidePosition; var pos = isVector(sidePosition) ? sidePosition : RVector.invalid; return RShape.getOffsetArcs(shape, distance, number, side, pos); }; /** * \return Array of spline shapes representing the parallel curves to the given ellipse shape. */ ShapeAlgorithms.getOffsetEllipses = function(shape, distance, number, sidePosition) { var side = isVector(sidePosition) ? RS.NoSide : sidePosition; var pos = isVector(sidePosition) ? sidePosition : RVector.invalid; return RShape.getOffsetEllipses(shape, distance, number, side, pos); }; /** * \return Intersection points between shape and other shapes. */ ShapeAlgorithms.getIntersectionPoints = function(shape, otherShapes, onShape, onOtherShapes) { var intersections = []; var i, k; // treat start and end points as intersection points for open shapes: if (onShape && !isCircleShape(shape) && !isFullEllipseShape(shape) && !isXLineShape(shape) && (!isPolylineShape(shape) || !shape.isGeometricallyClosed()) && (!isSplineShape(shape) || !shape.isClosed())) { var sp = shape.getStartPoint(); sp.isStart = true; intersections.push(sp); if (!isRayShape(shape)) { var ep = shape.getEndPoint() ep.isEnd = true; intersections.push(ep); } } // find all intersection points: for (i=0; imaxD) { maxD = d; p = ip; } } // no intersections: if (isNull(p)) { return [undefined, undefined, shape.clone()]; } // angle at intersection point closest to end of arc is where we split the circle: ap = shape.getCenter().getAngleTo(p); shape = new RArc(shape.getCenter(), shape.getRadius(), ap, ap, false); } // find intersection points closest to position: // array of two distances and two point vectors: var cutDistances = ShapeAlgorithms.getClosestIntersectionPointDistances(shape, ips, position); // distance along shape to clicked position: //var dPosition = ; // make sure direction of shape does not change in the process: //intersectionPointDistances.sort(); var cutDist1 = undefined; var cutDist2 = undefined; var cutPos1 = undefined; var cutPos2 = undefined; if (!isNull(cutDistances) && cutDistances.length>1) { cutDist1 = cutDistances[0][0]; cutDist2 = cutDistances[0][1]; cutPos1 = cutDistances[1][0]; cutPos2 = cutDistances[1][1]; } // if we only have one cutting point (XLine, Ray), make it the first parameter: if (isNull(cutDist1)) { cutDist1 = cutDist2; cutPos1 = cutPos2; cutDist2 = undefined; cutPos2 = undefined; } return ShapeAlgorithms.autoSplitManual(shape, cutDist1, cutDist2, cutPos1, cutPos2, position, extend); }; /** * Cut shape at given distances / positions. * * \return Array of three new shapes which each might be undefined if its * length would otherwise be 0. * The first shape is the rest at the start of the shape. * The second shape is the rest at the end of the shape. * The third shape is the segment self in its new shape. */ ShapeAlgorithms.autoSplitManual = function(shape, cutDist1, cutDist2, cutPos1, cutPos2, position, extend) { if (isNull(extend)) { extend = false; } // if (!isCircleShape(shape) && !isFullEllipseShape(shape) && // !isXLineShape(shape) && !isRayShape(shape)) { // if (isNull(cutDist1) || isNull(cutDist2)) { // // abort if shape requires two intersection points: // return undefined; // } // } // if (isNull(cutDist2)) { // cutDist2 = cutDist1; // } var dummy; var distSegment; // var cutPos1 = shape.getPointWithDistanceToStart(cutDist1); // var cutPos2 = undefined; // if (!isNull(cutDist2)) { // cutPos2 = shape.getPointWithDistanceToStart(cutDist2); // } if (isNull(cutDist1) && !isNull(cutPos1)) { cutDist1 = shape.getDistanceFromStart(cutPos1); } if (isNull(cutDist2) && !isNull(cutPos2)) { cutDist2 = shape.getDistanceFromStart(cutPos2); } if (isNull(cutDist2)) { // ray, nothing to cut: if (RMath.fuzzyCompare(cutDist1, 0.0) && shape.getStartPoint().equalsFuzzy(cutPos1)) { return [undefined, undefined, shape.clone()]; } } else { if (RMath.fuzzyCompare(cutDist1, 0.0) && shape.getStartPoint().equalsFuzzy(cutPos1) && RMath.fuzzyCompare(cutDist2, shape.getLength()) && shape.getEndPoint().equalsFuzzy(cutPos2)) { return [undefined, undefined, shape.clone()]; } } var rest1 = undefined; var rest2 = undefined; var segment = undefined; // lines: if (isLineShape(shape)) { rest1 = shape.clone(); rest2 = shape.clone(); if (cutDist1 < cutDist2) { rest1.trimEndPoint(cutDist1); rest2.trimStartPoint(cutDist2); } else { rest1.trimEndPoint(cutDist2); rest2.trimStartPoint(cutDist1); } segment = shape.clone(); segment.setStartPoint(cutPos1); segment.setEndPoint(cutPos2); if (rest1.getLength() cutDist2) { dummy = cutDist1; cutDist1 = cutDist2; cutDist2 = dummy; } // if (!isNull(cutDist1) && !isNull(cutDist2)) { // cutDist1 = cutDist2; // cutDist2 = undefined; // } // <--------x---------------x---------> // rest2 cp2 segment cp1 rest1 if (!isNull(cutDist1) && !isNull(cutDist2)) { rest1 = new RRay(cutPos1, RVector.createPolar(1.0, shape.getDirection2())); segment = new RLine(cutPos1, cutPos2); rest2 = new RRay(cutPos2, RVector.createPolar(1.0, shape.getDirection1())); } // <-o--------------x-----------------> // pos segment cp1 rest1 // <----------------x-------------o---> // rest1 cp1 segment pos else if (!isNull(cutDist1)) { rest1 = new RRay(cutPos1, RVector.createPolar(1.0, shape.getDirection2())); segment = new RRay(cutPos1, RVector.createPolar(1.0, shape.getDirection1())); distSegment = segment.getDistanceTo(position); if (isNaN(distSegment)) { dummy = rest1; rest1 = segment; segment = dummy; } rest2 = undefined; } } // rays: else if (isRayShape(shape)) { rest1 = undefined; rest2 = undefined; if (!isNull(cutDist1) && !isNull(cutDist2) && Math.sign(cutDist1) !== Math.sign(cutDist2)) { dummy = cutDist1; cutDist1 = cutDist2; cutDist2 = dummy; } // if (!cutDist1.isValid() && cutDist2.isValid()) { // cutDist1 = cutDist2; // cutDist2 = undefined; // } // <--------x-------o-------x--------- // rest2 cp2 segment cp1 rest1 if (isValidVector(cutPos1) && isValidVector(cutPos2)) { rest1 = new RLine(shape.getBasePoint(), cutPos1); segment = new RLine(cutPos1, cutPos2); rest2 = new RRay(cutPos2, RVector.createPolar(1.0, shape.getDirection1())); } // <-------o--------x----------------- // segment cp1 rest1 // <----------------x--------o-------- // rest1 cp1 segment else if (isValidVector(cutPos1)) { rest1 = new RLine(shape.getBasePoint(), cutPos1); segment = new RRay(cutPos1, RVector.createPolar(1.0, shape.getDirection1())); rest2 = undefined; distSegment = segment.getDistanceTo(position); if (isNaN(distSegment)) { dummy = rest1; rest1 = segment; segment = dummy; } } } // arcs: else if (isArcShape(shape)) { if (cutDist1 > cutDist2) { var dummy = cutDist1; cutDist1 = cutDist2; cutDist2 = dummy; } rest1 = shape.clone(); rest2 = shape.clone(); rest1.trimEndPoint(cutDist1); rest2.trimStartPoint(cutDist2); segment = shape.clone(); //var l1 = segment.getLength(); segment.setStartAngle(segment.getCenter().getAngleTo(cutPos1)); //segment.trimStartPoint(cutDist1); //var l2 = segment.getLength(); //segment.trimEndPoint(cutDist2 - (l1-l2)); segment.setEndAngle(segment.getCenter().getAngleTo(cutPos2)); if (!extend) { var angleLength1 = rest1.getAngleLength(true); var angleLength2 = rest2.getAngleLength(true); // rest1 is the same as the segment: var same1 = RMath.fuzzyAngleCompare(rest1.getStartAngle(), segment.getStartAngle()) && RMath.fuzzyAngleCompare(rest1.getEndAngle(), segment.getEndAngle()) && rest1.isReversed()===segment.isReversed(); // catch common errors: if (angleLength1+angleLength2 > shape.getAngleLength() || same1) { rest1.trimEndPoint(cutDist2); rest2.trimStartPoint(cutDist1); segment.trimStartPoint(cutDist2); segment.trimEndPoint(cutDist1); angleLength1 = rest1.getAngleLength(true); angleLength2 = rest2.getAngleLength(true); } if (angleLength1<1.0e-5) { rest1 = undefined; } if (angleLength2<1.0e-5) { rest2 = undefined; } } } // circles: else if (isCircleShape(shape)) { if (isNull(cutDist1) || isNull(cutDist2)) { rest1 = undefined; rest2 = undefined; } else { var angle1 = shape.getCenter().getAngleTo(cutPos1); var angle2 = shape.getCenter().getAngleTo(cutPos2); rest1 = new RArc( shape.getCenter(), shape.getRadius(), angle1, angle2, false); rest2 = undefined; segment = new RArc( shape.getCenter(), shape.getRadius(), angle2, angle1, false); if (!isNull(position)) { var cursorAngle = shape.getCenter().getAngleTo(position); if (RMath.isAngleBetween(cursorAngle, angle1, angle2, false)) { rest1.setStartAngle(angle2); rest1.setEndAngle(angle1); segment.setStartAngle(angle1); segment.setEndAngle(angle2); } } var angleLength1 = rest1.getAngleLength(true); if (angleLength1 shape.getAngleLength()) { rest1.trimEndPoint(cutPos2, cutPos2); rest2.trimStartPoint(cutPos1, cutPos1); segment.trimStartPoint(cutPos2, cutPos2); segment.trimEndPoint(cutPos1, cutPos1); angleLength1 = rest1.getAngleLength(true); angleLength2 = rest2.getAngleLength(true); } if (angleLength1<1.0e-5) { rest1 = undefined; } if (angleLength2<1.0e-5) { rest2 = undefined; } } // full ellipses: else if (isFullEllipseShape(shape)) { if (!isValidVector(cutPos1) || !isValidVector(cutPos2)) { rest1 = undefined; rest2 = undefined; } else { var angle1 = shape.getParamTo(cutPos1); var angle2 = shape.getParamTo(cutPos2); rest1 = new REllipse( shape.getCenter(), shape.getMajorPoint(), shape.getRatio(), angle1, angle2, false); rest2 = undefined; segment = new REllipse( shape.getCenter(), shape.getMajorPoint(), shape.getRatio(), angle2, angle1, false); if (!isNull(position)) { var cursorAngle = shape.getParamTo(position); if (RMath.isAngleBetween(cursorAngle, angle1, angle2, false)) { rest1.setStartParam(angle2); rest1.setEndParam(angle1); segment.setStartParam(angle1); segment.setEndParam(angle2); } } var angleLength1 = rest1.getAngleLength(); if (angleLength1 cutDist2) { var dummy = cutDist1; cutDist1 = cutDist2; cutDist2 = dummy; } rest1.trimEndPoint(cutDist1); var l1 = segment.getLength(); segment.trimStartPoint(cutDist1); var l2 = segment.getLength(); segment.trimEndPoint(cutDist2 - (l1-l2)); rest2.trimStartPoint(cutDist2); } if (!isNull(segment)) { if (segment.getLength()cutDist2) { cutPos2 = ip; cutDist2 = dist; } } else { var dists = shape.getDistancesFromStart(ip); for (var k=0; kcutDist1) { cutDist1 = dist; cutPos1 = ip; } } if (circular) { if (isNull(cutDistMax) || dist>cutDistMax) { cutDistMax = dist; cutPosMax = ip; } } // smallest distance to start // but larger than click point if (dist>pDist) { if (isNull(cutDist2) || distpDist || isPolylineShape(shape)))) { cutDistMin = dist; cutPosMin = ip; } } } } } if (circular) { if (isNull(cutDist1)) { cutDist1 = cutDistMax; cutPos1 = cutPosMax; } if (isNull(cutDist2)) { cutDist2 = cutDistMin; cutPos2 = cutPosMin; } } if (isEllipseShape(shape) && shape.isReversed()) { var dummy = cutPos1; cutPos1 = cutPos2; cutPos2 = dummy; dummy = cutDist1; cutDist1 = cutDist2; cutDist2 = dummy; } // open shape: cut to start or end point: if (!isCircleShape(shape) && !isFullEllipseShape(shape) && !isXLineShape(shape) && !isRayShape(shape) && (!isPolylineShape(shape) || !shape.isGeometricallyClosed()) && (!isSplineShape(shape) || !shape.isClosed())) { if (!isValidVector(cutPos1)) { cutDist1 = 0.0; cutPos1 = shape.getStartPoint(); } if (!isValidVector(cutPos2)) { cutDist2 = shape.getLength(); cutPos2 = shape.getEndPoint(); } } if (reversedShape) { shape.reverse(); } return [ [cutDist1, cutDist2], [cutPos1, cutPos2] ]; /* var orthoLine = undefined; var reversedShape = false; // auxiliary line othogonal to entity and through cursor: var p = shape.getClosestPointOnShape(position, true); if (isLineBasedShape(shape)) { var orthoAngle = shape.getDirection1()+Math.PI/2.0; var r = RVector.createPolar(1.0, orthoAngle); orthoLine = new RLine(position, position.operator_add(r)); } else if (isArcShape(shape) || isCircleShape(shape) || isEllipseShape(shape)) { orthoLine = new RLine(shape.getCenter(), position); if (isArcShape(shape) || isEllipseShape(shape)) { if (shape.isReversed()) { shape.reverse(); reversedShape = true; } } } if (isNull(orthoLine) && !isSplineShape(shape) && !isPolylineShape(shape)) { return undefined; } var intersections = []; // treat start and end points as intersection points: if (onShape && !isCircleShape(shape) && !isFullEllipseShape(shape) && !isXLineShape(shape) && (!isPolylineShape(shape) || !shape.isGeometricallyClosed())) { var sp = shape.getStartPoint(); sp.isStart = true; intersections.push(sp); if (!isRayShape(shape)) { var ep = shape.getEndPoint() ep.isEnd = true; intersections.push(ep); } } // find all intersection points: for (var i=0; idistRight) { cutPos1 = inters; distRight = dist; } if (isNull(distLeft) || dist0.0) { if (isNull(distRight) || dist0.0) { if (isNull(distRight) || distdistRightMax) { cutPos3 = inters; distRightMax = dist; } } else if (dist<0.0) { dist = Math.abs(dist); if (isNull(distLeft) || distdistLeftMax) { cutPos4 = inters; distLeftMax = dist; } } } } } if (!isCircleShape(shape) && !isFullEllipseShape(shape) && !isXLineShape(shape) && !isRayShape(shape) && (!isPolylineShape(shape) || shape.isGeometricallyClosed())) { if (!isValidVector(cutPos1)) { cutPos1 = shape.getEndPoint(); } if (!isValidVector(cutPos2)) { cutPos2 = shape.getStartPoint(); } } if (isPolylineShape(shape)) { if (isNull(distLeft)) { cutPos1 = cutPos3; cutPos2 = cutPos2; } if (isNull(distRight)) { cutPos1 = cutPos1; cutPos2 = cutPos4; } } if (reversedShape) { shape.reverse(); } return [cutPos1, cutPos2]; */ }; /** * \return RCircle through all three given points (RVector) or RLine if only * two points are given. */ ShapeAlgorithms.createCircleFrom3Points = function(point1, point2, point3) { ShapeAlgorithms.error = undefined; if (isNull(point1) || isNull(point2)) { return undefined; } if (isNull(point3)) { return new RLine(point1, point2); } if (point1.equalsFuzzy(point2) || point2.equalsFuzzy(point3) || point3.equalsFuzzy(point1)) { ShapeAlgorithms.error = qsTr("At least two points are identical."); return undefined; } var ret = RCircle.createFrom3Points(point1, point2, point3); if (!ret.isValid()) { ShapeAlgorithms.error = qsTr("No circle possible."); return undefined; } return ret; }; /** * \return RArc through all three given points (RVector) or RLine if only * two points are given. */ ShapeAlgorithms.createArcFrom3Points = function(point1, point2, point3) { ShapeAlgorithms.error = undefined; if (isNull(point1) || isNull(point2)) { return undefined; } if (isNull(point3)) { return new RLine(point1, point2); } if (point1.equalsFuzzy(point2) || point2.equalsFuzzy(point3) || point3.equalsFuzzy(point1)) { ShapeAlgorithms.error = qsTr("At least two points are identical."); return undefined; } var ret = RArc.createFrom3Points(point1, point2, point3); if (!ret.isValid()) { ShapeAlgorithms.error = qsTr("No arc possible."); return undefined; } return ret; }; /** * Approximates the given ellipse with arc segments and returns a polyline with * arc segments. * * \param segments Number of arc segments to generate. * \return RPolyline object or undefined */ ShapeAlgorithms.approximateEllipse = function(ellipse, segments) { ShapeAlgorithms.error = undefined; if (segments<=0) { ShapeAlgorithms.error = qsTr("Invalid number of segments: %1.").arg(segments); return undefined; } if (ellipse.getMajorRadius()0; order--) { vs[order] = []; var startIndex = 0; var keys = vertices.getKeys(); var values = vertices.getValues(); do { i = values.indexOf(order, startIndex); startIndex = i+1; if (i!==-1) { vs[order].push(keys[i]); } } while (i!==-1); } var vert = []; // quadrilateral: if (vs[4].length===1 && vs[3].length===2 && vs[2].length===3) { vert = [vs[3][0], vs[4][0], vs[3][1]]; var l1 = new RLine(vs[3][0], vs[4][0]); var l2 = new RLine(vs[4][0], vs[3][1]); // ret.push(new RLine(vs[3][0], vs[4][0])); // ret.push(new RLine(vs[4][0], vs[3][1])); for (i=0; i1000.0) { // return new RLine(startPoint, endPoint); // } if (splineIsArc) { return arc; } } } var line = new RLine(startPoint, endPoint); var splineIsLine = true; for (i=0.0; i<1.0; i+=0.1) { point = spline.getPointAt(i); if (!line.isOnShape(point, true, tolerance)) { splineIsLine = false; break; } } if (splineIsLine) { return line; } return spline; }; /** * Converts the given circle into an arc with the given start angle or 0. */ ShapeAlgorithms.circleToArc = function(circle, startAngle) { if (isNull(startAngle)) { startAngle = 0.0; } return circle.toArc(startAngle); }; /** * Converts the given line or arc into a polyline with numSegments segments. */ ShapeAlgorithms.lineOrArcToPolyline = function(shape, numSegments) { var ret = new RPolyline(); var l = shape.getLength(); var cursor; for (var i=0; i<=numSegments; i++) { if (i===0) { cursor = shape.getStartPoint(); } else if (i===numSegments) { cursor = shape.getEndPoint(); } else { cursor = shape.getPointsWithDistanceToEnd(l/numSegments*i, RS.FromStart)[0]; } ret.appendVertex(cursor); } return ret; }; ShapeAlgorithms.removeSharedPointer = function(shape) { if (isArray(shape)) { var ret = []; for (var i=0; i0 && pl.getEndPoint().equalsFuzzy(shape.getEndPoint())) { shape.reverse(); } pl.appendShape(shape); }; /** * Round or bevel between given polylines. * * \param trimmedShape1 Polyline segment or polyline 1, trimmed to cornerShape. * \param ending1 RS::Ending which end was trimmed. * \param segmentIndex1 Index of polyline segment that was trimmed. * \param trimmedShape2 Polyline segment or polyline 2, trimmed to cornerShape. * \param ending2 RS::Ending which end was trimmed. * \param segmentIndex2 Index of polyline segment that was trimmed. * \param cornerShape Shape to add at corner (arc, line, ...). */ ShapeAlgorithms.modifyPolylineCorner = function(polyline1, trimmedShape1, ending1, segmentIndex1, polyline2, trimmedShape2, ending2, segmentIndex2, cornerShape) { return polyline1.modifyPolylineCorner(trimmedShape1, ending1, segmentIndex1, trimmedShape2, ending2, segmentIndex2, cornerShape); }; /** * Finds the next segment in CCW direction from the cursor position. * * \param cursor Current position * \param dir Direction backwards to last traced segment */ //ShapeAlgorithms.getShapeSegment = function(cursor, dir) { //}; ShapeAlgorithms.divideShape = function(shape, pos1, pos2) { if (isNull(pos1) || isNull(shape)) { return undefined; } // circles and ellipses require two cut points: if (isNull(pos2)) { if (isCircleShape(shape) || (isEllipseShape(shape) && shape.isFullEllipse())) { return undefined; } } var center; var angle = undefined; var angle2 = undefined; var e; var cutPos1 = undefined; var cutPos2 = undefined; if (isCircleShape(shape)) { center = shape.getCenter(); var radius = shape.getRadius(); angle = center.getAngleTo(pos1); angle2 = center.getAngleTo(pos2); cutPos1 = center.operator_add(RVector.createPolar(radius, angle)); cutPos2 = center.operator_add(RVector.createPolar(radius, angle2)); // introduce tiny gap to make sure full arc is still rendered correctly // in other CAD systems: var arc1 = new RArc( shape.getCenter(), shape.getRadius(), angle, angle2, false); var arc2 = new RArc( shape.getCenter(), shape.getRadius(), angle2, angle, false); return [ [ arc1, arc2 ], [ cutPos1, cutPos2 ] ]; } else if (isEllipseShape(shape) && shape.isFullEllipse()) { center = shape.getCenter(); var ellipseAngle = shape.getAngle(); angle = center.getAngleTo(pos1) - ellipseAngle; angle2 = center.getAngleTo(pos2) - ellipseAngle; cutPos1 = shape.getPointAt(angle); cutPos2 = shape.getPointAt(angle2); var ellipse1 = shape.clone(); ellipse1.setStartParam(ellipse1.angleToParam(angle)); ellipse1.setEndParam(ellipse1.angleToParam(angle2)); var ellipse2 = shape.clone(); ellipse2.setStartParam(ellipse2.angleToParam(angle2)); ellipse2.setEndParam(ellipse2.angleToParam(angle)); return [ [ ellipse1, ellipse2 ], [ cutPos1, cutPos2 ] ]; } else if (isPolylineShape(shape) && shape.isClosed()) { shape.relocateStartPoint(pos1); shape.convertToOpen(); cutPos1 = pos1; if (!isNull(pos2)) { return Divide.divideShape(pos2, undefined, shape); } return [ [ shape, undefined ], [ pos1, undefined ] ]; } else { var shape1 = shape.clone(); var shape2 = shape.clone(); shape1 = trimEndPoint(shape1, pos1, pos1); if (isRayShape(shape1)) { // ray points in opposite direction: cutPos1 = shape1.getStartPoint(); } else { cutPos1 = shape1.getEndPoint(); } shape2 = trimStartPoint(shape2, pos1, pos1); return [ [ shape1, shape2 ], [ cutPos1, cutPos2 ] ]; } };