Skip to main content
Known Participant
August 24, 2016
Answered

Cutting angled points only

  • August 24, 2016
  • 2 replies
  • 1506 views

Odd question but one I've had for a while. In my work there have been times when I needed to convert a shape to a series of lines, keeping the curved parts but breaking the line where it angles. Anybody know of a trick to this other than manually selecting them?

This topic has been closed for replies.
Correct answer o-marat

kylwell, maybe this script will do.

/**

* ai.jsx (c)MaratShagiev m_js@bk.ru 27.08.2016

*

* cutPathByCornerPoints_v1.0

*

* Using:

* * Select a single path item;

* * Run the script

*

* Great destination:

* * cutting path item into pieces;

* * the point of cutting path item - corner points;

* * cut closed and open paths;

*

* What is really going on here:

* * source circuit is used as a model;

* * on top of the original path created new paths;

* * the original path is deleted;

*/

//@target illustrator

cutByCornPnts (selection[0]);

function cutByCornPnts (pth) {

  if (_cut (pth)) pth.remove ();

  function _cut (pth) {

    var remPth = false;

    if (pth.closed) {

      for (var i = 0; i < pth.pathPoints.length; i++) {

        var pnt = pth.pathPoints;

        if (!__isCornerPoint (pnt)) continue;

        __addPathByTmpl (pth, i);

        remPth = true;

      }

    } else {

      for (var i = 0; i < pth.pathPoints.length; i++) {

        var pnt = pth.pathPoints;

        i       = __addPathByTmpl (pth, i);

        remPth  = true;

      }

    }

    return remPth;

    function __addPathByTmpl (pathTmpl, iStartPnt) {

      var doc       = activeDocument,

          j, pntTmpl, pthDupl, pnt,

          endPthAdd = 0,

          pnts      = [pathTmpl.pathPoints [iStartPnt]];

      if (pathTmpl.closed) endPthAdd = 1;

      try {

        for (j = iStartPnt + 1; j < pathTmpl.pathPoints.length + endPthAdd; j++) {

          pntTmpl = pathTmpl.pathPoints;

          if (__isCornerPoint (pntTmpl)) {

            pnts.push (pntTmpl);

            break;

          }

          pntTmpl = pathTmpl.pathPoints;

          pnts.push (pntTmpl);

        }

      } catch (e) {

        for (j = 0; j < iStartPnt + endPthAdd; j++) {

          pntTmpl = pathTmpl.pathPoints;

          if (__isCornerPoint (pntTmpl)) {

            pnts.push (pntTmpl);

            break;

          }

          pntTmpl = pathTmpl.pathPoints;

          pnts.push (pntTmpl);

        }

      }

      if (pnts.length > 1) {

        pthDupl = doc.pathItems.add ();

        for (var i = 0; i < pnts.length; i++) {

          var pnt          = pnts;

          var p            = pthDupl.pathPoints.add ();

          p.anchor         = [pnt.anchor[0], pnt.anchor[1]];

          p.leftDirection  = [pnt.leftDirection[0], pnt.leftDirection[1]];

          p.rightDirection = [pnt.rightDirection[0], pnt.rightDirection[1]];

          p.pointType      = pnt.pointType;

        }

      }

      iStartPnt = j; // for closed paths

      return --j; // for open paths

    }

    /**

     * Unfortunately the Pen Tool creates all the points as smooth.

     * Even if in fact they are corner.

     * One way to solve this problem -

     * check all the points with this helper.

     *

     * @param {Object} pnt - object of class PathPoint

     * @return {Boolean}

     * */

    function __isCornerPoint (pnt) {

      if (pnt.pointType == PointType.CORNER) return true;

      var x_1, x_2, x_3,

          y_1, y_2, y_3,

          prec    = 100000,

          precLow = 10;

      x_1 = Math.round (pnt.leftDirection [0] * prec) / prec; // x

      y_1 = Math.round (pnt.leftDirection [1] * prec) / prec; // y

      x_2 = Math.round (pnt.rightDirection [0] * prec) / prec;

      y_2 = Math.round (pnt.rightDirection [1] * prec) / prec;

      x_3 = Math.round (pnt.anchor [0] * prec) / prec;

      y_3 = Math.round (pnt.anchor [1] * prec) / prec;

      if ((x_1 == x_2 && x_2 == x_3) && (y_1 == y_2 && y_2 == y_3)) return true;

      if ((x_1 == x_2) && (y_1 == y_2)) return true; // directions is equals

      if ((x_1 == x_3) && (y_1 == y_3)) return true; // left directon equals with anchor

      if ((x_2 == x_3) && (y_2 == y_3)) return true; // right direction equals with anchor

      // The equation of a straight line

      // points 1, 2, 3 are not equal and don't lie on one straight line

      if (

        Math.ceil (((x_3 - x_1) * (y_2 - y_1)) * precLow) / precLow !=

        Math.ceil (((x_2 - x_1) * (y_3 - y_1)) * precLow) / precLow

      ) return true;

      return false;

    }

  }

}

2 replies

o-marat
Inspiring
August 25, 2016

Another way - to draw  the new paths (by/using data of) the points of the initial path. Then initial path is removed...

kylwellAuthor
Known Participant
August 25, 2016

The only problem with that is I would be redrawing some 100+ paths. The stuff I create can get... complex. While I've done it before I was hoping somebody knew of a script that could help speed the process up. That and it gets really annoying to cut everything and then realize it doesn't work and I need to adjust my offsets.

o-marat
Inspiring
August 28, 2016

Why the heck it didn't take it the first 3 times... Ok, it's working and working pretty spiffy. For some odd reason I cannot figure out I have one document that throws up a;

Error 8705: Target layer cannot be modified

Line: 69

-> pthDupl = doc.pathltems.add O;

When I try to run it on a path. I can copy & paste the path to another document and it works. Haven't been able to reproduce in on another file but in the meantime, yes it works awesomely. The ONLY improvements I could see would be being able to perform it on multiple paths @ once, and the ability to designate min/max angles.

Thanks, this'll save me some seriously tedious work.


Now the script works with multiple selected objects (path items and groups), which may be located on different layers. Now you don't need make visible all layers - only select items.

About the ability to designate min/max angles: you need the interface (dialog window)? I will try to do it within a week...

/**

* ai_cs6+.jsx (c)MaratShagiev m_js@bk.ru 29.08.2016

*

* cutPathByCornerPoints_v2

*

* What's new:

* * Add the process of the collections

*

* Using:

* * Select group or/and path item;

* * Run the script

*

* Great destination:

* * cutting path item into pieces;

* * the point of cutting path item - corner points;

* * cut closed and open paths;

*

* What is really going on here:

* * source path is used as a template;

* * on top of the original path created new paths;

* * the original path is deleted;

*/

//@target illustrator

try {

  var collection = selection;

  executeMenuCommand ('deselectall');

  recurs (cutByCornPnts, selection);

} catch (e) {

  alert ('Error: ' + e.message + '\rin line #' + e.line);

}

function recurs (fn, collection) {

  if (!collection.length) throw new Error ('Select items and run script');

  for (var i = 0; i < collection.length; i++) {

    var elem = collection;

    switch (elem.typename) {

      case 'GroupItem':

        recurs (fn, elem.pageItems);

        break;

      case 'PathItem':

        fn (elem);

        break;

      case 'CompoundPathItem':

        break;

      default:

        break;

    }

  }

}

function cutByCornPnts (pth) {

  pth.selected = true;

  if (_cut (pth)) pth.remove ();

  function _cut (pth) {

    var remPth = false;

    if (pth.closed) {

      for (var i = 0; i < pth.pathPoints.length; i++) {

        var pnt = pth.pathPoints;

        if (!__isCornerPoint (pnt)) continue;

        __addPathByTmpl (pth, i);

        remPth = true;

      }

    } else {

      for (var k = 1; k < pth.pathPoints.length - 1; k++) {

        // path that doesn't contain the corner points shouldn't redrawn

        if (!__isCornerPoint (pth.pathPoints)) continue;

        // redraw path that contains corner points

        for (var i = 0; i < pth.pathPoints.length; i++) {

          var pnt = pth.pathPoints;

          i       = __addPathByTmpl (pth, i);

          remPth  = true;

        }

        break;

      }

    }

    pth.selected = false;

    return remPth;

    function __addPathByTmpl (pathTmpl, iStartPnt) {

      var doc       = activeDocument,

          j, pntTmpl, pthDupl, pnt,

          endPthAdd = 0,

          pnts      = [pathTmpl.pathPoints [iStartPnt]];

      if (pathTmpl.closed) endPthAdd = 1;

      try {

        for (j = iStartPnt + 1; j < pathTmpl.pathPoints.length + endPthAdd; j++) {

          pntTmpl = pathTmpl.pathPoints;

          if (__isCornerPoint (pntTmpl)) {

            pnts.push (pntTmpl);

            break;

          }

          pntTmpl = pathTmpl.pathPoints;

          pnts.push (pntTmpl);

        }

      } catch (e) {

        for (j = 0; j < iStartPnt + endPthAdd; j++) {

          pntTmpl = pathTmpl.pathPoints;

          if (__isCornerPoint (pntTmpl)) {

            pnts.push (pntTmpl);

            break;

          }

          pntTmpl = pathTmpl.pathPoints;

          pnts.push (pntTmpl);

        }

      }

      if (pnts.length > 1) {

        pthDupl = doc.activeLayer.pathItems.add ();

        pthDupl.move (pathTmpl, ElementPlacement.PLACEBEFORE);

        for (var i = 0; i < pnts.length; i++) {

          var pnt          = pnts;

          var p            = pthDupl.pathPoints.add ();

          p.anchor         = [pnt.anchor[0], pnt.anchor[1]];

          p.leftDirection  = [pnt.leftDirection[0], pnt.leftDirection[1]];

          p.rightDirection = [pnt.rightDirection[0], pnt.rightDirection[1]];

          p.pointType      = pnt.pointType;

        }

      }

      iStartPnt = j; // for closed paths

      return --j; // for open paths

    }

    /**

     * Unfortunately the Pen Tool creates all the points as smooth.

     * Even if in fact they are corner.

     * One way to solve this problem -

     * check all the points with this helper.

     *

     * todo: make this function more accurate...

     *

     * @param {Object} pnt - object of class PathPoint

     * @return {Boolean}

     * */

    function __isCornerPoint (pnt) {

      if (pnt.pointType == PointType.CORNER) return true;

      var x_1, x_2, x_3,

          y_1, y_2, y_3,

          prec    = 100000,

          precLow = 10;

      x_1 = Math.round (pnt.leftDirection [0] * prec) / prec; // x

      y_1 = Math.round (pnt.leftDirection [1] * prec) / prec; // y

      x_2 = Math.round (pnt.rightDirection [0] * prec) / prec;

      y_2 = Math.round (pnt.rightDirection [1] * prec) / prec;

      x_3 = Math.round (pnt.anchor [0] * prec) / prec;

      y_3 = Math.round (pnt.anchor [1] * prec) / prec;

      if ((x_1 == x_2 && x_2 == x_3) && (y_1 == y_2 && y_2 == y_3)) return true;

      if ((x_1 == x_2) && (y_1 == y_2)) return true; // directions is equals

      if ((x_1 == x_3) && (y_1 == y_3)) return true; // left directon equals with anchor

      if ((x_2 == x_3) && (y_2 == y_3)) return true; // right direction equals with anchor

      // The equation of a straight line

      // points 1, 2, 3 are not equal and don't lie on one straight line

      if (

        Math.ceil (((x_3 - x_1) * (y_2 - y_1)) * precLow) / precLow !=

        Math.ceil (((x_2 - x_1) * (y_3 - y_1)) * precLow) / precLow

      ) return true;

      return false;

    }

  }

}

o-marat
Inspiring
August 24, 2016

kylwell​, hi!

This is a function (compatible CS6+) that cuts the shape, which consists only of the corner points (star, poligon, rectangle).

If I'm on the right way I can add code to handle any paths.

Before running the script, you need to select the shape.

//@target illustrator

(function cutCornerShapeByPoints (pth) {

  var i, pnt, nextPnt, pthCut;

  executeMenuCommand ('deselectall');

  for (i = 0; i < pth.pathPoints.length; i++) {

    try {

      pnt     = pth.pathPoints;

      nextPnt = pth.pathPoints[i + 1];

    } catch (e) {

      nextPnt = pth.pathPoints[0];

    }

    pnt.selected = PathPointSelection.ANCHORPOINT;

      executeMenuCommand ('copy');

      executeMenuCommand ('pasteFront');

      pthCut = selection[0];

      pthCut.pathPoints[0].remove ();

      executeMenuCommand ('deselectall');

    } 

  pth.remove ();

} (selection[0]));