• Global community
    • Language:
      • Deutsch
      • English
      • EspaƱol
      • FranƧais
      • PortuguĆŖs
  • ę—„ęœ¬čŖžć‚³ćƒŸćƒ„ćƒ‹ćƒ†ć‚£
    Dedicated community for Japanese speakers
  • ķ•œźµ­ ģ»¤ė®¤ė‹ˆķ‹°
    Dedicated community for Korean speakers
Exit
0

Does anyone have a script for adding an anchor point to the top-most point of a path?

Participant ,
Mar 07, 2022 Mar 07, 2022

Copy link to clipboard

Copied

Hi there!

 

I was wondering if any of you have got a script that would be able to add an anchor point to the top-most/bottom-most point of a selected path (ex: an arc)?

 

I know it's a long shot, and I'm not even sure if it's doable. But it's a problem I've run into quite often, so I was wondering if someone has been able to fix it in the past. Thank you!

TOPICS
Scripting

Views

2.2K

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Community Expert , Mar 13, 2022 Mar 13, 2022

Hi @Eduard Buta, I've made a script that I think will do what you want. I've made a github page for it and you can download the latest release .zip file. The way you use it is to select *just the path segment(s) you want* and run the script "Add Path Point At Extrema.js". So if you just want a top anchor point, just select the topmost path segment (use direct selection tool and click on the path no on the anchor points) and then run script. If you select the whole path, it will add extreme point

...

Votes

Translate

Translate
Adobe
Community Expert ,
Mar 10, 2022 Mar 10, 2022

Copy link to clipboard

Copied

Eduard,

 

if it is ā€“ for some reason ā€“ required to run the actions via scripts, you can download them here:

 

Point Maker Scripts

 

It contains four simple scripts that will run the actions in the Point Maker 2 action set.

 

Instruction:

 

- Download and unzip the file

- Important: In the Actions palette, first make sure that you've imported the action set point_maker_2.aia

- Select a curved path and run one of the scripts, for example point_maker_top.jsx

 

That should work pretty well.

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Mar 11, 2022 Mar 11, 2022

Copy link to clipboard

Copied

@Kurt Gold, I'm going to have a try at this one too, purely with scripting solution (see my comment to @femkeblanco). This is just for fun, and not because you haven't already solved it.

- Mark

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Mar 11, 2022 Mar 11, 2022

Copy link to clipboard

Copied

I won't be able to do anything over the weekend, so I thought I would post my progress.  Step one, finding the extrema of the segments, is done.  The math was not as hard as I thought.  (Step two would be redrawing the path with one or more of these points.) 

femkeblanco_0-1647037584313.png

// select path
var doc = app.activeDocument;
var Ps = doc.selection[0].pathPoints;
// iterate segments
for (var i = 0; i < Ps.length - 1; i++) {
    var Px = [Ps[i].anchor[0], Ps[i].rightDirection[0], Ps[i + 1].leftDirection[0], Ps[i + 1].anchor[0]];
    var Py = [Ps[i].anchor[1], Ps[i].rightDirection[1], Ps[i + 1].leftDirection[1], Ps[i + 1].anchor[1]];
    getNDrawPoint();
}
function getNDrawPoint() {
    // get cubic Bezier curve extrema
    // for further info:  https://pomax.github.io/bezierinfo/#extremities
    var a = 3 * Py[3] - 9 * Py[2] + 9 * Py[1] - 3 * Py[0];
    var b = 6 * Py[0] - 12 * Py[1] + 6 * Py[2];
    var c = 3 * Py[1] - 3 * Py[0];
    var t1 = (- b + Math.sqrt(b * b - 4 * a * c)) / (2 * a);
    if (t1 > 0 && t1 < 1) var p1 = getPoint(Px, Py, t1);
    var t2 = (- b - Math.sqrt(b * b - 4 * a * c)) / (2 * a);
    if (t2 > 0 && t2 < 1) var p2 = getPoint(Px, Py, t2);
    // draw point(s)
    if(p1) drawPoint(p1[0], p1[1])
    if(p2) drawPoint(p2[0], p2[1])
}
function getPoint(Px, Py, t) {
    var x = Px[0] * (1 - t) * (1 - t) * (1 - t) + 3 * Px[1] * t * (1 - t) * (1 - t) + 3 * Px[2] * t * t * (1 - t) + Px[3] * t * t * t;
    var y = Py[0] * (1 - t) * (1 - t) * (1 - t) + 3 * Py[1] * t * (1 - t) * (1 - t) + 3 * Py[2] * t * t * (1 - t) + Py[3] * t * t * t;
    return [x, y];
}
function drawPoint(x, y) {
    var path1 = doc.pathItems.add();
    path1.setEntirePath([[x - 0.5, y + 0.5], [x + 0.5, y - 0.5]]);
    var path2 = doc.pathItems.add();
    path2.setEntirePath([[x + 0.5, y + 0.5], [x - 0.5, y - 0.5]]);
    path2.strokeWidth = path1.strokeWidth = 5;
    path2.strokeColor = path1.strokeColor = doc.swatches["CMYK red"].color;
    var group1 = doc.groupItems.add();
    path1.moveToEnd(group1);
    path2.moveToEnd(group1);
}

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Mar 15, 2022 Mar 15, 2022

Copy link to clipboard

Copied

I was naive in thinking that it's just a matter of redrawing the path with added anchor points.  In reality, all handles will need to be adjusted.  It's back to the drawing board.  (I'm hoping to solve this independently from @m1b's solution.)

femkeblanco_0-1647371118663.png

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Mar 12, 2022 Mar 12, 2022

Copy link to clipboard

Copied

An improved action set is availabe here:

 

Point Maker 3

 

It contains two additional actions that create points at all outer peaks of single or multiple selected curved paths.

 

point_maker_all_single_selection is supposed to work with single selected paths only.

 

point_maker_all_multiple_selection can handle multiple selected (ungrouped and non-overlapping) paths. It's a bit long-winded and it could be simplified. But this simplification would require some interaction by the user, so I didn't implement that option, accepting that it is just another bumpy ride.

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Mar 14, 2022 Mar 14, 2022

Copy link to clipboard

Copied

Hi @Kurt Gold, I tried point_maker_3 and once again you have performed some incredible action wizardry! Do you record your actions in the normal way, or create/tweak them using the underlying action markup?

- Mark

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Mar 14, 2022 Mar 14, 2022

Copy link to clipboard

Copied

Good Morning, Mark (late evening over here),

 

usually I try to go the normal (sometimes insane) way without any dirty tricks. Sometimes, however, I tweak them by editing the action code if it is required. Manipulating them this way unfortunately may be a bit risky and can destroy the entire action.

 

The Point Maker actions just use common commands. At least so far, but it may vary in case it is necessary.

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Mar 15, 2022 Mar 15, 2022

Copy link to clipboard

Copied

Haha yes insane-ly amazing! šŸ™‚

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Mar 15, 2022 Mar 15, 2022

Copy link to clipboard

Copied

Thank you very much Kurt for your implication here. I'm sure these will be super helpful to those that prefer using actions as opposed to scripts. I appreciate the help here! And please excuse my rather late answer.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Mar 13, 2022 Mar 13, 2022

Copy link to clipboard

Copied

Hi @Eduard Buta, I've made a script that I think will do what you want. I've made a github page for it and you can download the latest release .zip file. The way you use it is to select *just the path segment(s) you want* and run the script "Add Path Point At Extrema.js". So if you just want a top anchor point, just select the topmost path segment (use direct selection tool and click on the path no on the anchor points) and then run script. If you select the whole path, it will add extreme points to every segment.

- Mark

add-path-point-at-extrema-anim.gif

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Mar 14, 2022 Mar 14, 2022

Copy link to clipboard

Copied

That's a very good approach, Mark.

 

In particular I like that selecting the entire path will add extreme points to every segment, not only to the outermost regions of the whole path.

 

I have another action that can do that as well, but currently it only works with filled, but unstroked paths. Perhaps I will add it to Point Maker 4 as soon as I find a way that works with stroked paths as well.

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Mar 15, 2022 Mar 15, 2022

Copy link to clipboard

Copied

This is gold, Mark. Thank you very much for your implication. I've even managed to merge the two together since I am using an extension to run these scripts and I was getting an error otherwise. Thank you very much!

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Mar 15, 2022 Mar 15, 2022

Copy link to clipboard

Copied

Nice one! I should have said you can just copy and paste Bez.js in front of the script in the same file and it will work. You can also remove any methods of Bez.js that you don't need for your purposes. It's easiest for me to keep Bez.js separated because I use it for different scripts. There are ways in a CEP extension that you can keep it separate and it will still load properly, but it sounds like it's easy enough how you've done it.

- Mark

 

P.S. Eduard, your usage of the word "implication" is unusual in English. I think you intend "contribution". Anyway you are welcome. I'm happy to help.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Advocate ,
Mar 17, 2022 Mar 17, 2022

Copy link to clipboard

Copied

Bonjour m1b,
On ne peut ĆŖtre qu'Ć©merveillĆ© devant un tel script, qui remplit parfaitement sa mission dans un temps record.

Avec une modification, il fonctionne sur des versions plus anciennes comme CS, CS2, CS5, CS6, (avec var items = doc.selection;). Vu la rapiditĆ©, j'ai mĆŖme ajoutĆ© un avertissement indiquant que le traitement est terminĆ© (nombre de points crĆ©Ć©s). TestĆ© sur un tracĆ© complexe copiĆ© plusieurs fois avec des inclinaisons diffĆ©rentes, votre script a crĆ©Ć© 408 points presque instantanĆ©ment (en moyenne 12 points par tracĆ©).
Pour ma part, je n'ai jamais pu assimiler toutes le subtilitĆ©s de la programmation objet et ne connaissant pas la fonction getExtremaOfCurve() de Nishio Hirokazu (grand mathĆ©maticien, je prĆ©sume), jā€™avais imaginĆ© le scĆ©nario suivant:

1 Connaissant le sens du tracƩ, sƩlectionner un point.
- Ce point doit prƩcƩder le sommet convoitƩ.
2 Lancer le script.
- Ici, vous devrez renseigner le choix du mode.
0 pour gauche/droite, Left/Right et 1 pour haut/bas, Top/Bottom.
Le script doit:
Par itĆ©ration, Ć  partir de ce point sur un copie du tracĆ©, crĆ©er un nouveaux point jusqu'Ć  ce que la tangente Ć  la courbe en ce point change dā€™inclinaison.
Afficher le rƩsultat, si rƩussite: par exemple "ration = 0.89" sinon "ration = undefined "

extreme.PNG

function test() {
// INIT ----------------------------
  var M = 1; // Modes = 1 sommets top-bottom, Modes = 0 left-right
  var steep = 0.001; // steep ratio
// ---------------------------------
  var regMod, obj, rep, ratio;
      regMod = new RegExp("^[01]{0,1}$","g"); // number
      obj = app.activeDocument.selection[0];
        if (app.selection.length == 0)  {return;}
        if (obj.typename != "PathItem") {return;}
          do {
            var rep = prompt("Mode 0  Left/Right 1 Top /Bottom ?",M,"");
          }
            while (!saisie(rep,regMod) || !rep == null);
          if (rep == null || rep == "") {return;}
      M = rep*1;
            for (var k = 0, r = 0; k < obj.pathPoints.length; k++) {
              if (isSelected(obj.pathPoints[k])) {
                 break;
              }
            }
        alert("Ratio = "+addpT(obj,k,M));
// --------
function addpT (obj,i,M) {
  var pnts, Sg, p, pt, tg, q,ecart;
      pnts = [];
      Sg = 0;  // signe ecart  0 pour - 1 pour +
      p = obj.pathPoints;
        for(var ii = 0; ii < p.length; ii++){
          pnts.push(getDat(p[ii]));
        }
        //alert(pnts.join("\r"))
        j = parseIdx(p,i+1);
        if (j < 0) return;

    for(var t = steep; t <= 1; t += steep) {
      tg = obj.duplicate();
      p = tg.pathPoints;
      q = [p[i].anchor, p[i].rightDirection,
      p[j].leftDirection, p[j].anchor];

      p[i].rightDirection = linearSprit(q[0],q[1],t);
      p[j].leftDirection  = linearSprit(q[2],q[3],t);

      p.add();
          if (j) {
            p[j+1].leftDirection = linearSprit(q[2],q[3],t);
            p[j+1].anchor = q[3];
            p[j+1].rightDirection = p[j].rightDirection;
          }
          else {
            p[j].leftDirection = linearSprit(q[2],q[3],t);
          }
      p[i+1].anchor = bezier(q,t);
      p[i+1].leftDirection  = nwDirection (q[0],q[1],q[2],t);
      p[i+1].rightDirection = nwDirection (q[1],q[2],q[3],t);
      ecart = p[i+1].rightDirection[M]-p[i+1].leftDirection[M];
          if (t == steep) {
            if (ecart > 0) {
              Sg = 1;
            }
          }

          if ((ecart <= 0 && Sg) || (ecart >= 0 && !Sg)) {
            p[i+1].leftDirection[M] = p[i+1].rightDirection[M] = p[i+1].anchor[M];
              for(var k = i+3; k <= pnts.length; k++){
                  p[k].anchor         = pnts[k-1][0];
                  p[k].rightDirection = pnts[k-1][1];
                  p[k].leftDirection  = pnts[k-1][2];
                  p[k].pointType      = pnts[k-1][3];
               }
            obj.remove();
            return t;
          }
       //redraw();
      tg.remove();
    }
}
// --------
// returns an array for properties of a pathpoint
function getDat(p){ // pathPoint
  with(p) return [anchor, rightDirection, leftDirection, pointType];
}
// --------
function linearSprit (p0,p1,t){ //linear bezier
    var u = 1-t;
    return [p1[0]*t+p0[0]*u,p1[1]*t+p0[1]*u];
}
// --------
function nwDirection(p0,p1,p2,t){ //quadratic bezier
    var u = 1-t;
    return   [u*u*p0[0]+2*u*t*p1[0]+t*t*p2[0],u*u*p0[1]+2*u*t*p1[1]+t*t*p2[1]];
}
// --------
function bezier(q,t) {  // identique Ć  nwAnchor
  var u = 1-t;
  return [u*u*u*q[0][0]+3*u*t*(u*q[1][0]+t*q[2][0])+t*t*t*q[3][0],
          u*u*u*q[0][1]+3*u*t*(u*q[1][1]+t*q[2][1])+t*t*t*q[3][1]];
}
// --------
function parseIdx(p, n){ // PathPoints, number for index
  var len = p.length;
  if(p.parent.closed){
    return n >= 0 ? n%len : len-Math.abs(n%len);
  } else {
    return (n < 0 || n > len-1) ? -1 : n;
  }
}
// --------
function isSelected(p){ // PathPoint
  return p.selected == PathPointSelection.ANCHORPOINT;
}
// --------
function saisie(chaine,reg) // test saisie number
{
  if (chaine == null || chaine == "") return true;
      if (reg.test(chaine)) return true;
   return false;
}
}
// -------
if (app.documents.length) test();
// --------

Sans prƩtension RenƩ

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Mar 17, 2022 Mar 17, 2022

Copy link to clipboard

Copied

LATEST

Thanks @renĆ©l80416020. You have arrived at an impressive way of solving this problem! I know you are an accomplished problem solver when I saw you have a offset path script. šŸ™‚

I am sad to say, I myself am like a child playing with the toys of adults, putting them together often with little understanding of their workings! Nonetheless, it is a rewarding and fun activity, with it's own trials and challenges to overcome.

I use the objects (Bez and BezPoint, etc) because it helps me compartmentalise the functionality. I can say to myself well it's a BezPoint, so it should be able to do a thing to itself, or calculate something about itself, and that helps me organise everything. I don't always use this structure well but I'm learning.

- Mark

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines